From cda14c50fedd579b0fe07247b8efc0b1a91c6d7d Mon Sep 17 00:00:00 2001 From: Tom Robinson Date: Mon, 11 Jan 2016 16:49:57 +0000 Subject: [PATCH] Added ASTC Native file format loader ASTC can be wrapped in a KTX file, but also has its own native file format. This patch provides support for the native ASTC file format (.astc). Textures can be generated using tools (Eg. Mali texture compression tool). Note: ASTC is "OpenGL friendly" in that the textures are pre-flipped vertically. In DALi there is currently not a differenciation between different texture compression formats in that the data (once the header is extracted) is given to the hardware as-is. For this reason textures must currently be pre-flipped vertically (before compression) when using the native .astc file format with DALI. An example .astc file is included as part of the unit tests. Change-Id: I574961bc184d68d3ec722be3c682ca2a2b7ed0ce --- ...fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc | Bin 0 -> 2064 bytes automated-tests/images/test-image.wbmp | Bin 0 -> 260 bytes .../utc-Dali-CompressedTextures.cpp | 67 ++++-- .../utc-image-loading-common.h | 10 +- platform-abstractions/tizen/file.list | 3 +- .../tizen/image-loaders/image-loader.cpp | 8 +- .../tizen/image-loaders/loader-astc.cpp | 246 +++++++++++++++++++++ .../tizen/image-loaders/loader-astc.h | 69 ++++++ 8 files changed, 380 insertions(+), 23 deletions(-) create mode 100644 automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc create mode 100644 automated-tests/images/test-image.wbmp create mode 100755 platform-abstractions/tizen/image-loaders/loader-astc.cpp create mode 100644 platform-abstractions/tizen/image-loaders/loader-astc.h diff --git a/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc b/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc new file mode 100644 index 0000000000000000000000000000000000000000..78b370bc468dd185c86f8253f161e288183269a2 GIT binary patch literal 2064 zcmZXVc{r2{8^+&xy%_7fwj#+^oskw>B4Xx!afWba-m!*bNo6NeO(hha(V{7P629VC zqLD32w4CHP$xLKuV$`ALC>mO1eLvrKUEe=_&wuw{zx#Tw`?(*r>Qa9QBIp4C1po*D zu(XW-cfNiN38B+*oC*r3s=KRh06?#~FrvN}GY}O7n1&bV+p5}JKQ@03VUIoxbD95U z>{RHq@LjTmLcs@yp+j5WWbIeoy%n0qpmhJ&u^}8H3ZGX+%C!)X)m-Fd@9VdXS*lY$ zt%!nr?bO!29*bt3k8%G|0s|Dz)I6)YzUpV=Sh?sK0v5`<&PFjQG2&~rtToN3fuDx| zs1h(!vfMVM}LXj$|}fz8oH4D+XZv5;Bhp&r9Bve7qXup`9*wD4LhY-fOumz;yd zJm3NG&`4QiB}!I-?FJ86SJ|o6T@6*A#mKwhgCQFX<#LSXd7qsOR{71*DLoyMoq8fb zvJ*hS$D41D9q}HU=J?Lw3CB=q|A9LytivTQoQ$rhmBEN&^#1gF19`32^d}-l>PJLU zMrW!1voC=44em8lqWcIU0~EEhk)qKni31|O!kM1+RAy`5s+EGX`huf#lhg=6;rLR7+WoFm=U6O_T~9H zx8073SQtS<;NQ?m?>+HPn3n2kX16An0t-AK(p!D#Zcz?={X^@9m9YlQDQ-(g^4EIJ>~0nCeD*KF}jN6E^MD}9o@ zKG_7(?g*!|YGw1j9Cvk>Eq|@fi_dOfU=ro%XDnJM%4>II7u*|zQ85I!$rY-1+eP(#_f{)6N+7oHA1w5=M3`+ zvR|gPlXZpL7~tH>%JSke6~~jFH>9O8x{37pSzSDpw>%M;d~!G1ElZbTd8c%eQ_ChH zEj~&H>HEX%FA+OD8=Nc`Xc$y>ZXh{`sFWaoPM@90L%Ur#gqFY|IhNN)G=1nb1_h^g zC8ao)ke{AXCm4|!+&k1JKJbf~O9qk7NRI#Cy(T5$_{s{7|EMvdvB~|FMcveQw=+nE zpIIn56b_zj)C@bBo(BJXSei*R=6OMGO^8zD$i8}_oH;ljVebx%P$KP0a+RE|unH-T zmBVHzbfSu?vIj9mX#aKwu@_}a!Q{(D^JVN*CB>xc9{Oty^)w=*!vQfru>kDi)iR1gvqit%|4E+Tp80{}`S(18J7$!Z?E`h(e_f9MIX*+wW#pkN-?`uSzoC{xR!$xl^BhnBBbq`zjkX)1dxBI>7>r_R=G8edp+@Uv&*fiX} z*o7%}ii_Xa=OC{k>|A+IibBBU$2x<_`{wXPysr5mjE2elU5zB>GVM#otE0cRGkCgO zcgVDymT=HY+ak+q)o={meGKI&Lj0nD%^huw=Cl6Uw~fhq{2_Ny;At zt5~E$RdO3i^cvsC(j5~H4KYl9;#!QmXF8a=E%?9EYe&h*OW3~EF?W=Zxb2Wh5GszP zZ;2Q98ncvJvft|tpb%R2Nkxh3VeTO8qLt{Nv~|3Q1Kv1NC-c*{w#p3*FtsrtWuPNP zHGFhrI7SxfmQsy;?mRfP-hTtWw6uhU#hJ+64E4<6h{HlDvC$ZK{}+elNZQfg7Bd?K zr?nYiWGOT5bvLEy>Gs0m7-(-O;1gYIEii`)7r5@O7mMF>-_6Tbha)sE ziH^(Xn9MWB){9;yN{giG`;xD9+~p3om}&!n69e=u*c2bkC~{lxg;J(Ola_tJQ; zIC+{WHp@00z{p74-MZ^(`PqV7l91$L2AJL!nD(Nb^6i|(&EXTW46v>@DgQx3isj|? zeAmtB>OT{u)^=2+ST?rdo{9iwAZ&5n`N3!ENS?TpPgvc5VV3j9C=K&|e%pg}Z1%qa D`WU(@ literal 0 HcmV?d00001 diff --git a/automated-tests/images/test-image.wbmp b/automated-tests/images/test-image.wbmp new file mode 100644 index 0000000000000000000000000000000000000000..8ec84aed177ff411b63814653a5ccb0966341248 GIT binary patch literal 260 zcmWO1u}Z^07y#h3L`b(7n!Qbv;SL|b%@Cr5n~t;ps-621SENI6EDgBXh6u?Y9OEYG z&__@Q!9|?i>QJ=5{odd+j9w@K#wf75O literal 0 HcmV?d00001 diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp index 6b7a616..425806e 100644 --- a/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp +++ b/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp @@ -21,12 +21,17 @@ #include #include #include "platform-abstractions/tizen/image-loaders/loader-ktx.h" +#include "platform-abstractions/tizen/image-loaders/loader-astc.h" // INTERNAL INCLUDES #include "image-loaders.h" using namespace Dali; +// Pre-define loader functions for each image type being tested (as they are reused in different tests). +static const LoadFunctions KtxLoaders( TizenPlatform::LoadKtxHeader, TizenPlatform::LoadBitmapFromKtx ); +static const LoadFunctions AstcLoaders( TizenPlatform::LoadAstcHeader, TizenPlatform::LoadBitmapFromAstc ); + /** * This class encapsulates knowledge of testing compressed files. * It requires a few input parameters per test to confirm if the file was read and understood. @@ -36,8 +41,20 @@ class KtxTestFixture { public: - KtxTestFixture() {} - ~KtxTestFixture() {} + /** + * Constructor. + * Sets up the fixture. + */ + KtxTestFixture( void ) + { + } + + /** + * Destructor. + */ + ~KtxTestFixture() + { + } /** * This struct contains any per-test parameters. @@ -45,12 +62,14 @@ class KtxTestFixture */ struct TestEntry { - std::string filename; ///< Name of the compressed texture KTX file to load. - int expectedWidth; ///< The width the texture should be. - int expectedHeight; ///< The height the KTX texture should be. - - TestEntry( std::string newFilename, int newExpectedWidth, int newExpectedHeight ) - : filename( newFilename ), + LoadFunctions loadFunctions; ///< Used to parse the header of a given type of image. + std::string filename; ///< Name of the compressed texture KTX file to load. + int expectedWidth; ///< The width the texture should be. + int expectedHeight; ///< The height the KTX texture should be. + + TestEntry( const LoadFunctions& newLoadFunctions, std::string newFilename, int newExpectedWidth, int newExpectedHeight ) + : loadFunctions( newLoadFunctions ), + filename( newFilename ), expectedWidth( newExpectedWidth ), expectedHeight( newExpectedHeight ) { @@ -102,7 +121,8 @@ class KtxTestFixture unsigned int width( 0 ), height( 0 ); const Dali::TizenPlatform::ImageLoader::Input input( fileDescriptor ); - DALI_TEST_CHECK( TizenPlatform::LoadKtxHeader( input, width, height ) ); + // Use the given loader to parse the image header. + DALI_TEST_CHECK( testEntry.loadFunctions.header( input, width, height ) ); DALI_TEST_EQUALS( width, testEntry.expectedWidth, TEST_LOCATION ); DALI_TEST_EQUALS( height, testEntry.expectedHeight, TEST_LOCATION ); @@ -110,17 +130,18 @@ class KtxTestFixture private: - TestContainer mTests; ///< Holds all tests to be run. + TestContainer mTests; ///< Holds all tests to be run. }; +// KTX files (KTX is a wrapper, so can contain different compressed texture types): int UtcDaliKtxLoaderETC(void) { KtxTestFixture fixture; - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-ETC1_RGB8_OES-45x80.ktx", 45u, 80u ) ); - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-RGB8_ETC2-45x80.ktx", 45u, 80u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-ETC1_RGB8_OES-45x80.ktx", 45u, 80u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGB8_ETC2-45x80.ktx", 45u, 80u ) ); fixture.RunTests(); @@ -131,7 +152,7 @@ int UtcDaliKtxLoaderPVRTC(void) { KtxTestFixture fixture; - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx", 32u, 64u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx", 32u, 64u ) ); fixture.RunTests(); @@ -142,7 +163,7 @@ int UtcDaliKtxLoaderEAC(void) { KtxTestFixture fixture; - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-R11_EAC-45x80.ktx", 45u, 80u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-R11_EAC-45x80.ktx", 45u, 80u ) ); fixture.RunTests(); @@ -153,10 +174,24 @@ int UtcDaliKtxLoaderASTC(void) { KtxTestFixture fixture; - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) ); - fixture.AddTest( KtxTestFixture::TestEntry( TEST_IMAGE_DIR "/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) ); + fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) ); fixture.RunTests(); END_TEST; } + + +// ASTC (Native) files: +int UtcDaliAstcLoader(void) +{ + KtxTestFixture fixture; + + fixture.AddTest( KtxTestFixture::TestEntry( AstcLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc", 32u, 64u ) ); + + fixture.RunTests(); + + END_TEST; +} + diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h index 9c709a9..d82f98e 100644 --- a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h +++ b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2016 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,12 +57,14 @@ const char* const VALID_IMAGES[] = { TEST_IMAGE_DIR "/frac.24.bmp", TEST_IMAGE_DIR "/frac.png", TEST_IMAGE_DIR "/interlaced.gif", - TEST_IMAGE_DIR "/pattern.gif" + TEST_IMAGE_DIR "/pattern.gif", + TEST_IMAGE_DIR "/fractal-compressed-ETC1_RGB8_OES-45x80.ktx", + TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc", + TEST_IMAGE_DIR "/test-image-4x4-32bpp.ico", + TEST_IMAGE_DIR "/test-image.wbmp" }; const unsigned NUM_VALID_IMAGES = sizeof(VALID_IMAGES) / sizeof(VALID_IMAGES[0]); -///@ToDo: Add valid ktx, ico, and wbmp image examples. - /** Returns elapsed milliseconds. */ double GetTimeMilliseconds( Integration::PlatformAbstraction& abstraction ) { diff --git a/platform-abstractions/tizen/file.list b/platform-abstractions/tizen/file.list index b9efdd8..c76bcfd 100755 --- a/platform-abstractions/tizen/file.list +++ b/platform-abstractions/tizen/file.list @@ -16,9 +16,10 @@ tizen_platform_abstraction_src_files = \ \ $(tizen_platform_abstraction_src_dir)/resource-loader/debug/resource-loader-debug.cpp \ \ + $(tizen_platform_abstraction_src_dir)/image-loaders/loader-astc.cpp \ $(tizen_platform_abstraction_src_dir)/image-loaders/loader-bmp.cpp \ $(tizen_platform_abstraction_src_dir)/image-loaders/loader-gif.cpp \ - $(tizen_platform_abstraction_src_dir)/image-loaders/loader-ico.cpp \ + $(tizen_platform_abstraction_src_dir)/image-loaders/loader-ico.cpp \ $(tizen_platform_abstraction_src_dir)/image-loaders/loader-jpeg-turbo.cpp \ $(tizen_platform_abstraction_src_dir)/image-loaders/loader-ktx.cpp \ $(tizen_platform_abstraction_src_dir)/image-loaders/loader-png.cpp \ diff --git a/platform-abstractions/tizen/image-loaders/image-loader.cpp b/platform-abstractions/tizen/image-loaders/image-loader.cpp index a87f31f..d1fb566 100644 --- a/platform-abstractions/tizen/image-loaders/image-loader.cpp +++ b/platform-abstractions/tizen/image-loaders/image-loader.cpp @@ -20,12 +20,13 @@ #include #include +#include "loader-astc.h" #include "loader-bmp.h" #include "loader-gif.h" -#include "loader-jpeg.h" -#include "loader-png.h" #include "loader-ico.h" +#include "loader-jpeg.h" #include "loader-ktx.h" +#include "loader-png.h" #include "loader-wbmp.h" #include "image-operations.h" #include "image-loader-input.h" @@ -74,6 +75,7 @@ enum FileFormats FORMAT_BMP, FORMAT_GIF, FORMAT_KTX, + FORMAT_ASTC, FORMAT_ICO, FORMAT_MAGIC_BYTE_COUNT, @@ -93,6 +95,7 @@ const BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_COUNT] = { Bmp::MAGIC_BYTE_1, Bmp::MAGIC_BYTE_2, LoadBitmapFromBmp, LoadBmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS }, { Gif::MAGIC_BYTE_1, Gif::MAGIC_BYTE_2, LoadBitmapFromGif, LoadGifHeader, Bitmap::BITMAP_2D_PACKED_PIXELS }, { Ktx::MAGIC_BYTE_1, Ktx::MAGIC_BYTE_2, LoadBitmapFromKtx, LoadKtxHeader, Bitmap::BITMAP_COMPRESSED }, + { Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED }, { Ico::MAGIC_BYTE_1, Ico::MAGIC_BYTE_2, LoadBitmapFromIco, LoadIcoHeader, Bitmap::BITMAP_2D_PACKED_PIXELS }, { 0x0, 0x0, LoadBitmapFromWbmp, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS }, }; @@ -115,6 +118,7 @@ const FormatExtension FORMAT_EXTENSIONS[] = { ".bmp", FORMAT_BMP }, { ".gif", FORMAT_GIF }, { ".ktx", FORMAT_KTX }, + { ".astc", FORMAT_ASTC }, { ".ico", FORMAT_ICO }, { ".wbmp", FORMAT_WBMP } }; diff --git a/platform-abstractions/tizen/image-loaders/loader-astc.cpp b/platform-abstractions/tizen/image-loaders/loader-astc.cpp new file mode 100755 index 0000000..5d3e758 --- /dev/null +++ b/platform-abstractions/tizen/image-loaders/loader-astc.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include "loader-astc.h" + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Dali +{ +using Integration::Bitmap; +using Dali::Integration::PixelBuffer; + +namespace TizenPlatform +{ + +namespace +{ + +// Max width or height of an image. +const unsigned MAX_TEXTURE_DIMENSION = 4096; +// Max bytes of image data allowed. Not a precise number, just a sanity check. +const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION; + +// Minimum and maximum possible sizes for ASTC blocks. +const unsigned int MINIMUM_ASTC_BLOCK_SIZE = 4; +const unsigned int MAXIMUM_ASTC_BLOCK_SIZE = 12; + +typedef uint8_t Byte; + +// This bytes identify an ASTC native file. +const Byte FileIdentifier[] = { + 0x13, 0xAB, 0xA1, 0x5C +}; + + +/** + * @brief This struct defines the ASTC file header values. From ASTC specifications. + * Packed attribute stops the structure from being aligned to compiler defaults + * so we can be sure of reading the whole header from file in one call to fread(). + * Note: members to not conform to coding standards in order to be consistent with ASTC spec. + */ +struct AstcFileHeader +{ + unsigned char magic[ 4 ]; + unsigned char blockdim_x; + unsigned char blockdim_y; + unsigned char blockdim_z; + unsigned char xsize[ 3 ]; + unsigned char ysize[ 3 ]; + unsigned char zsize[ 3 ]; +} __attribute__ ( (__packed__)); + +using namespace Pixel; + +/** + * @brief This table allows fast conversion from an ASTC block size ([height][width]) to a pixel format. + * This could be done within a switch, but this way we have a constant time function. + * Note: As 4 is the minimum block size, 4 is subtracted from both the width and height to optimise size. + * IE. Table format is: Increasing order of block width from left-to-right: 4 -> 12 + * Increasing order of block height from top-to-bottom: 4 -> 12 + */ +Pixel::Format AstcLinearBlockSizeToPixelFormatTable[][( MAXIMUM_ASTC_BLOCK_SIZE - MINIMUM_ASTC_BLOCK_SIZE ) + 1] = { + { COMPRESSED_RGBA_ASTC_4x4_KHR, COMPRESSED_RGBA_ASTC_5x4_KHR, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID }, + { INVALID, COMPRESSED_RGBA_ASTC_5x5_KHR, COMPRESSED_RGBA_ASTC_6x5_KHR, INVALID, COMPRESSED_RGBA_ASTC_8x5_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x5_KHR, INVALID, INVALID }, + { INVALID, INVALID, COMPRESSED_RGBA_ASTC_6x6_KHR, INVALID, COMPRESSED_RGBA_ASTC_8x6_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x6_KHR, INVALID, INVALID }, + { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID }, + { INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_8x8_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x8_KHR, INVALID, INVALID }, + { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID }, + { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_10x10_KHR, INVALID, COMPRESSED_RGBA_ASTC_12x10_KHR }, + { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID }, + { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_12x12_KHR } +}; + +/** + * @brief Uses header information to return the respective ASTC pixel format. + * + * @param[in] header A populated AstcFileHeader struct + * @return The pixel format, or INVALID if the block size was invalid + */ +Pixel::Format GetAstcPixelFormat( AstcFileHeader& header ) +{ + // Check the block size is valid. This will also prevent an invalid read from the conversion table. + if( ( header.blockdim_x < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_x > MAXIMUM_ASTC_BLOCK_SIZE ) || + ( header.blockdim_y < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_y > MAXIMUM_ASTC_BLOCK_SIZE ) ) + { + return Pixel::INVALID; + } + + // Read the equivalent pixel format from the conversion table. + return AstcLinearBlockSizeToPixelFormatTable[ header.blockdim_y - MINIMUM_ASTC_BLOCK_SIZE ][ header.blockdim_x - MINIMUM_ASTC_BLOCK_SIZE ]; +} + +/** + * @brief Internal method to load ASTC header info from a file. + * + * @param[in] filePointer The file pointer to the ASTC file to read + * @param[out] width The width is output to this value + * @param[out] height The height is output to this value + * @param[out] fileHeader This will be populated with the header data + * @return True if the file is valid, false otherwise + */ +bool LoadAstcHeader( FILE * const filePointer, unsigned int &width, unsigned int &height, AstcFileHeader &fileHeader ) +{ + // Pull the bytes of the file header in as a block: + unsigned int readLength = sizeof( AstcFileHeader ); + if( fread( (void*)&fileHeader, 1, readLength, filePointer ) != readLength ) + { + return false; + } + + // Check the header contains the ASTC native file identifier. + bool headerIsValid = memcmp( fileHeader.magic, FileIdentifier, sizeof( fileHeader.magic ) ) == 0; + if( !headerIsValid ) + { + DALI_LOG_ERROR( "File is not a valid ASTC native file\n" ); + // Return here as otherwise, if not a valid ASTC file, we are likely to pick up other header errors spuriously. + return false; + } + + // Convert the 3-byte values for width and height to a single resultant value. + width = fileHeader.xsize[0] | ( fileHeader.xsize[1] << 8 ) | ( fileHeader.xsize[2] << 16 ); + height = fileHeader.ysize[0] | ( fileHeader.ysize[1] << 8 ) | ( fileHeader.ysize[2] << 16 ); + + const unsigned int zDepth = fileHeader.zsize[0] + ( fileHeader.zsize[1] << 8 ) + ( fileHeader.zsize[2] << 16 ); + + // Check image dimensions are within limits. + if( ( width > MAX_TEXTURE_DIMENSION ) || ( height > MAX_TEXTURE_DIMENSION ) ) + { + DALI_LOG_ERROR( "ASTC file has larger than supported dimensions: %d,%d\n", width, height ); + headerIsValid = false; + } + + // Confirm the ASTC block does not have any Z depth. + if( zDepth != 1 ) + { + DALI_LOG_ERROR( "ASTC files with z size other than 1 are not supported. Z size is: %d\n", zDepth ); + headerIsValid = false; + } + + return headerIsValid; +} + +} // Unnamed namespace. + + +// File loading API entry-point: +bool LoadAstcHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height ) +{ + AstcFileHeader fileHeader; + return LoadAstcHeader( input.file, width, height, fileHeader ); +} + +// File loading API entry-point: +bool LoadBitmapFromAstc( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap ) +{ + FILE* const filePointer = input.file; + if( !filePointer ) + { + DALI_LOG_ERROR( "Null file handle passed to ASTC compressed bitmap file loader.\n" ); + return false; + } + + // Load the header info. + AstcFileHeader fileHeader; + unsigned int width, height; + + if( !LoadAstcHeader( filePointer, width, height, fileHeader ) ) + { + DALI_LOG_ERROR( "Could not load ASTC Header from file.\n" ); + return false; + } + + // Retrieve the pixel format from the ASTC block size. + Pixel::Format pixelFormat = GetAstcPixelFormat( fileHeader ); + if( pixelFormat == Pixel::INVALID ) + { + DALI_LOG_ERROR( "No internal pixel format supported for ASTC file pixel format.\n" ); + return false; + } + + // Retrieve the file size. + fseek( filePointer, 0L, SEEK_END ); + off_t fileSize = ftell( filePointer ); + if( fileSize == -1L ) + { + DALI_LOG_ERROR( "Could not determine ASTC file size.\n" ); + return false; + } + fseek( filePointer, sizeof( AstcFileHeader ), SEEK_SET ); + + // Data size is file size - header size. + size_t imageByteCount = fileSize - sizeof( AstcFileHeader ); + + // Sanity-check the image data is not too large and that it is at less than 2 bytes per texel: + if( ( imageByteCount > MAX_IMAGE_DATA_SIZE ) || ( imageByteCount > ( ( width * height ) << 1 ) ) ) + { + DALI_LOG_ERROR( "ASTC file has too large image-data field.\n" ); + return false; + } + + // Allocate space to load the image data in to. + PixelBuffer* const pixels = bitmap.GetCompressedProfile()->ReserveBufferOfSize( pixelFormat, width, height, imageByteCount ); + if( !pixels ) + { + DALI_LOG_ERROR( "Unable to reserve a pixel buffer to load the requested bitmap into.\n" ); + return false; + } + + // Load the image data. + const size_t bytesRead = fread( pixels, 1, imageByteCount, filePointer ); + // Check the size of loaded data is what we expected. + if( bytesRead != imageByteCount ) + { + DALI_LOG_ERROR( "Read of image pixel data failed.\n" ); + return false; + } + + return true; +} + +} // namespace TizenPlatform + +} // namespace Dali diff --git a/platform-abstractions/tizen/image-loaders/loader-astc.h b/platform-abstractions/tizen/image-loaders/loader-astc.h new file mode 100644 index 0000000..6b43542 --- /dev/null +++ b/platform-abstractions/tizen/image-loaders/loader-astc.h @@ -0,0 +1,69 @@ +#ifndef __DALI_TIZEN_PLATFORM_LOADER_ASTC_H__ +#define __DALI_TIZEN_PLATFORM_LOADER_ASTC_H__ + +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include "image-loader-input.h" + +namespace Dali +{ + +namespace Integration +{ + class Bitmap; +} + +namespace TizenPlatform +{ + +class ResourceLoadingClient; + +namespace Astc +{ +const unsigned char MAGIC_BYTE_1 = 0x13; +const unsigned char MAGIC_BYTE_2 = 0xAB; +} // namespace Astc + + +/** + * Loads a compressed bitmap image from a ASTC file without decoding it. + * This function checks the header first + * and if it is not a ASTC file, or the header contents are invalid, it will return a failure. + * @param[in] client todor + * @param[in] input Information about the input image (including file pointer) + * @param[in/out] bitmap The bitmap class where the decoded image will be stored + * @return True if file loaded successfully, false otherwise + */ +bool LoadBitmapFromAstc( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap ); + +/** + * Loads the header of a ASTC file and fills in the width and height appropriately. + * @param[in] input Information about the input image (including file pointer) + * @param[out] width Is set with the width of the image + * @param[out] height Is set with the height of the image + * @return True if the header was read successfully, false otherwise + */ +bool LoadAstcHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height ); + + +} // namespace TizenPlatform + +} // namespace Dali + +#endif // __DALI_TIZEN_PLATFORM_LOADER_ASTC_H__ -- 2.7.4