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