xref: /aosp_15_r20/external/deqp/framework/common/tcuImageIO.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Image IO.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuImageIO.hpp"
25 #include "tcuResource.hpp"
26 #include "tcuSurface.hpp"
27 #include "tcuCompressedTexture.hpp"
28 #include "deFilePath.hpp"
29 #include "deUniquePtr.hpp"
30 
31 #include <string>
32 #include <vector>
33 #include <cstdio>
34 
35 #include "png.h"
36 
37 namespace tcu
38 {
39 namespace ImageIO
40 {
41 
42 using std::string;
43 using std::vector;
44 
45 /*--------------------------------------------------------------------*//*!
46  * \brief Load image from resource
47  *
48  * TextureLevel storage is set to match image data. Only PNG format is
49  * currently supported.
50  *
51  * \param dst        Destination pixel container
52  * \param archive    Resource archive
53  * \param fileName    Resource file name
54  *//*--------------------------------------------------------------------*/
loadImage(TextureLevel & dst,const tcu::Archive & archive,const char * fileName)55 void loadImage(TextureLevel &dst, const tcu::Archive &archive, const char *fileName)
56 {
57     string ext = de::FilePath(fileName).getFileExtension();
58 
59     if (ext == "png" || ext == "PNG")
60         loadPNG(dst, archive, fileName);
61     else
62         throw InternalError("Unrecognized image file extension", fileName, __FILE__, __LINE__);
63 }
64 
65 DE_BEGIN_EXTERN_C
pngReadResource(png_structp png_ptr,png_bytep data,png_size_t length)66 static void pngReadResource(png_structp png_ptr, png_bytep data, png_size_t length)
67 {
68     tcu::Resource *resource = (tcu::Resource *)png_get_io_ptr(png_ptr);
69     resource->read(data, (int)length);
70 }
71 DE_END_EXTERN_C
72 
73 /*--------------------------------------------------------------------*//*!
74  * \brief Load PNG image from resource
75  *
76  * TextureLevel storage is set to match image data.
77  *
78  * \param dst        Destination pixel container
79  * \param archive    Resource archive
80  * \param fileName    Resource file name
81  *//*--------------------------------------------------------------------*/
loadPNG(TextureLevel & dst,const tcu::Archive & archive,const char * fileName)82 void loadPNG(TextureLevel &dst, const tcu::Archive &archive, const char *fileName)
83 {
84     de::UniquePtr<Resource> resource(archive.getResource(fileName));
85 
86     // Verify header.
87     uint8_t header[8];
88     resource->read(header, sizeof(header));
89     TCU_CHECK(png_sig_cmp((png_bytep)&header[0], 0, DE_LENGTH_OF_ARRAY(header)) == 0);
90 
91     png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, DE_NULL, DE_NULL, DE_NULL);
92     TCU_CHECK(png_ptr);
93 
94     png_infop info_ptr = png_create_info_struct(png_ptr);
95     TCU_CHECK(info_ptr);
96 
97     if (setjmp(png_jmpbuf(png_ptr)))
98         throw InternalError("An error occured when loading PNG", fileName, __FILE__, __LINE__);
99 
100     png_set_read_fn(png_ptr, resource.get(), pngReadResource);
101     png_set_sig_bytes(png_ptr, 8);
102 
103     png_read_info(png_ptr, info_ptr);
104 
105     const uint32_t width  = (uint32_t)png_get_image_width(png_ptr, info_ptr);
106     const uint32_t height = (uint32_t)png_get_image_height(png_ptr, info_ptr);
107     TextureFormat textureFormat;
108 
109     {
110         const png_byte colorType = png_get_color_type(png_ptr, info_ptr);
111         const png_byte bitDepth  = png_get_bit_depth(png_ptr, info_ptr);
112 
113         if (colorType == PNG_COLOR_TYPE_RGB && bitDepth == 8)
114             textureFormat = TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8);
115         else if (colorType == PNG_COLOR_TYPE_RGBA && bitDepth == 8)
116             textureFormat = TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8);
117         else
118             throw InternalError("Unsupported PNG depth or color type", fileName, __FILE__, __LINE__);
119     }
120 
121     // Resize destination texture.
122     dst.setStorage(textureFormat, width, height);
123 
124     std::vector<png_bytep> row_pointers;
125     row_pointers.resize(height);
126     for (uint32_t y = 0; y < height; y++)
127         row_pointers[y] = (uint8_t *)dst.getAccess().getDataPtr() + y * dst.getAccess().getRowPitch();
128 
129     png_read_image(png_ptr, &row_pointers[0]);
130 
131     png_destroy_info_struct(png_ptr, &info_ptr);
132     png_destroy_read_struct(&png_ptr, DE_NULL, DE_NULL);
133 }
134 
textureFormatToPNGFormat(const TextureFormat & format)135 static int textureFormatToPNGFormat(const TextureFormat &format)
136 {
137     if (format == TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8))
138         return PNG_COLOR_TYPE_RGB;
139     else if (format == TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
140         return PNG_COLOR_TYPE_RGBA;
141     else
142         throw InternalError("Unsupported texture format", DE_NULL, __FILE__, __LINE__);
143 }
144 
145 /*--------------------------------------------------------------------*//*!
146  * \brief Write image to file in PNG format
147  *
148  * This is provided for debugging and development purposes. Test code must
149  * not write to any files except the test log by default.
150  *
151  * \note Only RGB/RGBA, UNORM_INT8 formats are supported
152  * \param src        Source pixel data
153  * \param fileName    File name
154  *//*--------------------------------------------------------------------*/
savePNG(const ConstPixelBufferAccess & src,const char * fileName)155 void savePNG(const ConstPixelBufferAccess &src, const char *fileName)
156 {
157     FILE *fp = fopen(fileName, "wb");
158     TCU_CHECK(fp);
159 
160     png_structp pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
161 
162     if (!pngPtr)
163     {
164         fclose(fp);
165         TCU_CHECK(pngPtr);
166     }
167 
168     png_infop infoPtr = png_create_info_struct(pngPtr);
169     if (!infoPtr)
170     {
171         png_destroy_write_struct(&pngPtr, NULL);
172         TCU_CHECK(infoPtr);
173     }
174 
175     if (setjmp(png_jmpbuf(pngPtr)))
176     {
177         png_destroy_write_struct(&pngPtr, &infoPtr);
178         fclose(fp);
179         throw tcu::InternalError("PNG compression failed");
180     }
181     else
182     {
183         int pngFormat = textureFormatToPNGFormat(src.getFormat());
184 
185         png_init_io(pngPtr, fp);
186 
187         // Header
188         png_set_IHDR(pngPtr, infoPtr, src.getWidth(), src.getHeight(), 8, pngFormat, PNG_INTERLACE_NONE,
189                      PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
190         png_write_info(pngPtr, infoPtr);
191 
192         std::vector<png_bytep> rowPointers(src.getHeight());
193         for (int y = 0; y < src.getHeight(); y++)
194             rowPointers[y] = (uint8_t *)src.getDataPtr() + y * src.getRowPitch();
195 
196         png_write_image(pngPtr, &rowPointers[0]);
197         png_write_end(pngPtr, NULL);
198 
199         png_destroy_write_struct(&pngPtr, &infoPtr);
200         fclose(fp);
201     }
202 }
203 
204 enum PkmImageFormat
205 {
206     ETC1_RGB_NO_MIPMAPS  = 0,
207     ETC1_RGBA_NO_MIPMAPS = 1,
208     ETC1_RGB_MIPMAPS     = 2,
209     ETC1_RGBA_MIPMAPS    = 3
210 };
211 
readBigEndianShort(tcu::Resource * resource)212 static inline uint16_t readBigEndianShort(tcu::Resource *resource)
213 {
214     uint16_t val;
215     resource->read((uint8_t *)&val, sizeof(val));
216     return (uint16_t)(((val >> 8) & 0xFF) | ((val << 8) & 0xFF00));
217 }
218 
219 /*--------------------------------------------------------------------*//*!
220  * \brief Load compressed image data from PKM file
221  *
222  * \note            Only ETC1_RGB8_NO_MIPMAPS format is supported
223  * \param dst        Destination pixel container
224  * \param archive    Resource archive
225  * \param fileName    Resource file name
226  *//*--------------------------------------------------------------------*/
loadPKM(CompressedTexture & dst,const tcu::Archive & archive,const char * fileName)227 void loadPKM(CompressedTexture &dst, const tcu::Archive &archive, const char *fileName)
228 {
229     de::UniquePtr<Resource> resource(archive.getResource(fileName));
230 
231     // Check magic and version.
232     uint8_t refMagic[] = {'P', 'K', 'M', ' ', '1', '0'};
233     uint8_t magic[6];
234     resource->read(magic, DE_LENGTH_OF_ARRAY(magic));
235 
236     if (memcmp(refMagic, magic, sizeof(magic)) != 0)
237         throw InternalError("Signature doesn't match PKM signature", resource->getName().c_str(), __FILE__, __LINE__);
238 
239     uint16_t type = readBigEndianShort(resource.get());
240     if (type != ETC1_RGB_NO_MIPMAPS)
241         throw InternalError("Unsupported PKM type", resource->getName().c_str(), __FILE__, __LINE__);
242 
243     uint16_t width        = readBigEndianShort(resource.get());
244     uint16_t height       = readBigEndianShort(resource.get());
245     uint16_t activeWidth  = readBigEndianShort(resource.get());
246     uint16_t activeHeight = readBigEndianShort(resource.get());
247 
248     DE_UNREF(width && height);
249 
250     dst.setStorage(COMPRESSEDTEXFORMAT_ETC1_RGB8, (int)activeWidth, (int)activeHeight);
251     resource->read((uint8_t *)dst.getData(), dst.getDataSize());
252 }
253 
254 } // namespace ImageIO
255 } // namespace tcu
256