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