0e0881bed0af60b185fd761330704bdf922bd580
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / loader-ktx.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/imaging/common/loader-ktx.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring>
23 #include <dali/public-api/common/compile-time-assert.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
26 #include <dali/internal/imaging/common/pixel-buffer-impl.h>
27
28 #include <dali/internal/system/common/file-closer.h>
29
30 using namespace Dali::Internal::Platform;
31
32 namespace Dali
33 {
34
35 namespace TizenPlatform
36 {
37
38 namespace
39 {
40
41 /** Max width or height of an image. */
42 const unsigned MAX_TEXTURE_DIMENSION = 4096;
43 /** Max bytes of image data allowed. Not a precise number, just a sanity check. */
44 const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION;
45 /** We don't read any of this but limit it to a resonable amount in order to be
46  * friendly to files from random tools. */
47 const unsigned MAX_BYTES_OF_KEYVALUE_DATA = 65536U;
48
49 typedef uint8_t Byte;
50
51 const Byte FileIdentifier[] = {
52    0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
53 };
54
55
56 /** The formats we support inside a KTX file container.
57  *  Currently only compressed formats are allowed as we'd rather
58  *  use a PNG or JPEG with their own compression for the general
59  *  cases. */
60 enum KtxInternalFormat
61 {
62   KTX_NOTEXIST = 0,
63
64   // GLES 2 Extension formats:
65   KTX_ETC1_RGB8_OES                               = 0x8D64,
66   KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG             = 0x8C00,
67
68   // GLES 3 Standard compressed formats (values same as in gl3.h):
69   KTX_COMPRESSED_R11_EAC                          = 0x9270,
70   KTX_COMPRESSED_SIGNED_R11_EAC                   = 0x9271,
71   KTX_COMPRESSED_RG11_EAC                         = 0x9272,
72   KTX_COMPRESSED_SIGNED_RG11_EAC                  = 0x9273,
73   KTX_COMPRESSED_RGB8_ETC2                        = 0x9274,
74   KTX_COMPRESSED_SRGB8_ETC2                       = 0x9275,
75   KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2    = 0x9276,
76   KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2   = 0x9277,
77   KTX_COMPRESSED_RGBA8_ETC2_EAC                   = 0x9278,
78   KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC            = 0x9279,
79
80   // GLES 3.1 compressed formats:
81   KTX_COMPRESSED_RGBA_ASTC_4x4_KHR                = 0x93B0,
82   KTX_COMPRESSED_RGBA_ASTC_5x4_KHR                = 0x93B1,
83   KTX_COMPRESSED_RGBA_ASTC_5x5_KHR                = 0x93B2,
84   KTX_COMPRESSED_RGBA_ASTC_6x5_KHR                = 0x93B3,
85   KTX_COMPRESSED_RGBA_ASTC_6x6_KHR                = 0x93B4,
86   KTX_COMPRESSED_RGBA_ASTC_8x5_KHR                = 0x93B5,
87   KTX_COMPRESSED_RGBA_ASTC_8x6_KHR                = 0x93B6,
88   KTX_COMPRESSED_RGBA_ASTC_8x8_KHR                = 0x93B7,
89   KTX_COMPRESSED_RGBA_ASTC_10x5_KHR               = 0x93B8,
90   KTX_COMPRESSED_RGBA_ASTC_10x6_KHR               = 0x93B9,
91   KTX_COMPRESSED_RGBA_ASTC_10x8_KHR               = 0x93BA,
92   KTX_COMPRESSED_RGBA_ASTC_10x10_KHR              = 0x93BB,
93   KTX_COMPRESSED_RGBA_ASTC_12x10_KHR              = 0x93BC,
94   KTX_COMPRESSED_RGBA_ASTC_12x12_KHR              = 0x93BD,
95   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR        = 0x93D0,
96   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR        = 0x93D1,
97   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR        = 0x93D2,
98   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR        = 0x93D3,
99   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR        = 0x93D4,
100   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR        = 0x93D5,
101   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR        = 0x93D6,
102   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR        = 0x93D7,
103   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR       = 0x93D8,
104   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR       = 0x93D9,
105   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR       = 0x93DA,
106   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR      = 0x93DB,
107   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR      = 0x93DC,
108   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR      = 0x93DD,
109
110   // Uncompressed Alpha format
111   KTX_UNCOMPRESSED_ALPHA8                         = 0x1906,
112
113   KTX_SENTINEL = ~0u
114 };
115
116 const unsigned KtxInternalFormats[] =
117 {
118   // GLES 2 Extension formats:
119   KTX_ETC1_RGB8_OES,
120   KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
121
122   // GLES 3 Standard compressed formats:
123   KTX_COMPRESSED_R11_EAC,
124   KTX_COMPRESSED_SIGNED_R11_EAC,
125   KTX_COMPRESSED_RG11_EAC,
126   KTX_COMPRESSED_SIGNED_RG11_EAC,
127   KTX_COMPRESSED_RGB8_ETC2,
128   KTX_COMPRESSED_SRGB8_ETC2,
129   KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
130   KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
131   KTX_COMPRESSED_RGBA8_ETC2_EAC,
132   KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
133
134   // GLES 3.1 Compressed formats:
135   KTX_COMPRESSED_RGBA_ASTC_4x4_KHR,
136   KTX_COMPRESSED_RGBA_ASTC_5x4_KHR,
137   KTX_COMPRESSED_RGBA_ASTC_5x5_KHR,
138   KTX_COMPRESSED_RGBA_ASTC_6x5_KHR,
139   KTX_COMPRESSED_RGBA_ASTC_6x6_KHR,
140   KTX_COMPRESSED_RGBA_ASTC_8x5_KHR,
141   KTX_COMPRESSED_RGBA_ASTC_8x6_KHR,
142   KTX_COMPRESSED_RGBA_ASTC_8x8_KHR,
143   KTX_COMPRESSED_RGBA_ASTC_10x5_KHR,
144   KTX_COMPRESSED_RGBA_ASTC_10x6_KHR,
145   KTX_COMPRESSED_RGBA_ASTC_10x8_KHR,
146   KTX_COMPRESSED_RGBA_ASTC_10x10_KHR,
147   KTX_COMPRESSED_RGBA_ASTC_12x10_KHR,
148   KTX_COMPRESSED_RGBA_ASTC_12x12_KHR,
149   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
150   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
151   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
152   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
153   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
154   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
155   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
156   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
157   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
158   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
159   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
160   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
161   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
162   KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
163
164   // Uncompressed Alpha format
165   KTX_UNCOMPRESSED_ALPHA8,
166
167   KTX_SENTINEL
168 };
169
170 struct KtxFileHeader
171 {
172   Byte   identifier[12];
173   uint32_t endianness;
174   uint32_t glType;
175   uint32_t glTypeSize;
176   uint32_t glFormat;
177   uint32_t glInternalFormat;
178   uint32_t glBaseInternalFormat;
179   uint32_t pixelWidth;
180   uint32_t pixelHeight;
181   uint32_t pixelDepth;
182   uint32_t numberOfArrayElements;
183   uint32_t numberOfFaces;
184   uint32_t numberOfMipmapLevels;
185   uint32_t bytesOfKeyValueData;
186 } __attribute__ ( (__packed__));
187 // Packed attribute stops the structure from being aligned to compiler defaults
188 // so we can be sure of reading the whole thing from file in one call to fread.
189
190 /**
191  * Function to read from the file directly into our structure.
192  * @param[in]  fp     The file to read from
193  * @param[out] header The structure we want to store our information in
194  * @return true, if read successful, false otherwise
195  */
196 inline bool ReadHeader( FILE* filePointer, KtxFileHeader& header )
197 {
198   const unsigned int readLength = sizeof( KtxFileHeader );
199
200   // Load the information directly into our structure
201   if( InternalFile::fread( &header, 1, readLength, filePointer ) != readLength )
202   {
203     return false;
204   }
205
206   return true;
207 }
208
209 /** Check whether the array passed in is the right size and matches the magic
210  *  values defined to be at the start of a KTX file by the specification.*/
211 template<int BYTES_IN_SIGNATURE>
212 bool CheckFileIdentifier(const Byte * const signature)
213 {
214   const unsigned signatureSize = BYTES_IN_SIGNATURE;
215   const unsigned identifierSize = sizeof(FileIdentifier);
216   DALI_COMPILE_TIME_ASSERT(signatureSize == identifierSize);
217   const bool signatureGood = 0 == memcmp( signature, FileIdentifier, std::min( signatureSize, identifierSize ) );
218   return signatureGood;
219 }
220
221 /**
222  * @returns True if the argument is a GLES compressed texture format that we support.
223  */
224 bool ValidInternalFormat(const unsigned format)
225 {
226   unsigned candidateFormat = 0;
227   for(unsigned iFormat = 0; (candidateFormat = KtxInternalFormats[iFormat]) != KTX_SENTINEL; ++iFormat)
228   {
229     if(format == candidateFormat)
230     {
231       return true;
232     }
233   }
234   DALI_LOG_ERROR("Rejecting unsupported compressed format when loading compressed texture from KTX file: 0x%x.\n", format);
235   return false;
236 }
237
238 /**
239  * @returns The Pixel::Format Dali enum corresponding to the KTX internal format
240  *          passed in, or Pixel::INVALID_PIXEL_FORMAT if the format is not valid.
241  **/
242 bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
243 {
244   using namespace Dali::Pixel;
245   switch(ktxPixelFormat)
246   {
247     // GLES 2 extension compressed formats:
248     case KTX_ETC1_RGB8_OES:
249     {
250       format = COMPRESSED_RGB8_ETC1;
251       break;
252     }
253     case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
254     {
255       format = COMPRESSED_RGB_PVRTC_4BPPV1;
256       break;
257     }
258
259     // GLES 3 extension compressed formats:
260     case KTX_COMPRESSED_R11_EAC:
261     {
262       format = COMPRESSED_R11_EAC;
263       break;
264     }
265     case KTX_COMPRESSED_SIGNED_R11_EAC:
266     {
267       format = COMPRESSED_SIGNED_R11_EAC;
268       break;
269     }
270     case KTX_COMPRESSED_RG11_EAC:
271     {
272       format = COMPRESSED_RG11_EAC;
273       break;
274     }
275     case KTX_COMPRESSED_SIGNED_RG11_EAC:
276     {
277       format = COMPRESSED_SIGNED_RG11_EAC;
278       break;
279     }
280     case KTX_COMPRESSED_RGB8_ETC2:
281     {
282       format = COMPRESSED_RGB8_ETC2;
283       break;
284     }
285     case KTX_COMPRESSED_SRGB8_ETC2:
286     {
287       format = COMPRESSED_SRGB8_ETC2;
288       break;
289     }
290     case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
291     {
292       format = COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
293       break;
294     }
295     case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
296     {
297       format = COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
298       break;
299     }
300     case KTX_COMPRESSED_RGBA8_ETC2_EAC:
301     {
302       format = COMPRESSED_RGBA8_ETC2_EAC;
303       break;
304     }
305     case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
306     {
307       format = COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
308       break;
309     }
310
311     // GLES 3.1 extension compressed formats:
312     case KTX_COMPRESSED_RGBA_ASTC_4x4_KHR:
313     {
314       format = COMPRESSED_RGBA_ASTC_4x4_KHR;
315       break;
316     }
317     case KTX_COMPRESSED_RGBA_ASTC_5x4_KHR:
318     {
319       format = COMPRESSED_RGBA_ASTC_5x4_KHR;
320       break;
321     }
322     case KTX_COMPRESSED_RGBA_ASTC_5x5_KHR:
323     {
324       format = COMPRESSED_RGBA_ASTC_5x5_KHR;
325       break;
326     }
327     case KTX_COMPRESSED_RGBA_ASTC_6x5_KHR:
328     {
329       format = COMPRESSED_RGBA_ASTC_6x5_KHR;
330       break;
331     }
332     case KTX_COMPRESSED_RGBA_ASTC_6x6_KHR:
333     {
334       format = COMPRESSED_RGBA_ASTC_6x6_KHR;
335       break;
336     }
337     case KTX_COMPRESSED_RGBA_ASTC_8x5_KHR:
338     {
339       format = COMPRESSED_RGBA_ASTC_8x5_KHR;
340       break;
341     }
342     case KTX_COMPRESSED_RGBA_ASTC_8x6_KHR:
343     {
344       format = COMPRESSED_RGBA_ASTC_8x6_KHR;
345       break;
346     }
347     case KTX_COMPRESSED_RGBA_ASTC_8x8_KHR:
348     {
349       format = COMPRESSED_RGBA_ASTC_8x8_KHR;
350       break;
351     }
352     case KTX_COMPRESSED_RGBA_ASTC_10x5_KHR:
353     {
354       format = COMPRESSED_RGBA_ASTC_10x5_KHR;
355       break;
356     }
357     case KTX_COMPRESSED_RGBA_ASTC_10x6_KHR:
358     {
359       format = COMPRESSED_RGBA_ASTC_10x6_KHR;
360       break;
361     }
362     case KTX_COMPRESSED_RGBA_ASTC_10x8_KHR:
363     {
364       format = COMPRESSED_RGBA_ASTC_10x8_KHR;
365       break;
366     }
367     case KTX_COMPRESSED_RGBA_ASTC_10x10_KHR:
368     {
369       format = COMPRESSED_RGBA_ASTC_10x10_KHR;
370       break;
371     }
372     case KTX_COMPRESSED_RGBA_ASTC_12x10_KHR:
373     {
374       format = COMPRESSED_RGBA_ASTC_12x10_KHR;
375       break;
376     }
377     case KTX_COMPRESSED_RGBA_ASTC_12x12_KHR:
378     {
379       format = COMPRESSED_RGBA_ASTC_12x12_KHR;
380       break;
381     }
382     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
383     {
384       format = COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
385       break;
386     }
387     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
388     {
389       format = COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;
390       break;
391     }
392     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
393     {
394       format = COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;
395       break;
396     }
397     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
398     {
399       format = COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;
400       break;
401     }
402     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
403     {
404       format = COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;
405       break;
406     }
407     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
408     {
409       format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;
410       break;
411     }
412     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
413     {
414       format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;
415       break;
416     }
417     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
418     {
419       format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;
420       break;
421     }
422     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
423     {
424       format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;
425       break;
426     }
427     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
428     {
429       format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;
430       break;
431     }
432     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
433     {
434       format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;
435       break;
436     }
437     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
438     {
439       format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;
440       break;
441     }
442     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
443     {
444       format = COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;
445       break;
446     }
447     case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
448     {
449       format = COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;
450       break;
451     }
452
453     // Uncompressed Alpha format
454     case KTX_UNCOMPRESSED_ALPHA8:
455     {
456       format = A8;
457       break;
458     }
459
460     default:
461     {
462        return false;
463     }
464   }
465   return true;
466 }
467
468 bool LoadKtxHeader( FILE * const fp, unsigned int& width, unsigned int& height, KtxFileHeader& fileHeader )
469 {
470   // Pull the bytes of the file header in as a block:
471   if ( !ReadHeader( fp, fileHeader ) )
472   {
473     return false;
474   }
475   width = fileHeader.pixelWidth;
476   height = fileHeader.pixelHeight;
477
478   if ( width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION )
479   {
480     return false;
481   }
482
483   // Validate file header contents meet our minimal subset:
484   const bool signatureGood                            = CheckFileIdentifier<sizeof(fileHeader.identifier)>(fileHeader.identifier);
485   const bool fileEndiannessMatchesSystemEndianness    = fileHeader.endianness == 0x04030201; // Magic number from KTX spec.
486   const bool glTypeIsCompressed                       = fileHeader.glType == 0;
487   const bool glTypeSizeCompatibleWithCompressedTex    = fileHeader.glTypeSize == 1;
488   const bool glFormatCompatibleWithCompressedTex      = fileHeader.glFormat == 0;
489   const bool glInternalFormatIsSupportedCompressedTex = ValidInternalFormat(fileHeader.glInternalFormat);
490   // Ignore glBaseInternalFormat
491   const bool textureIsNot3D                           = fileHeader.pixelDepth == 0 || fileHeader.pixelDepth == 1;
492   const bool textureIsNotAnArray                      = fileHeader.numberOfArrayElements == 0 || fileHeader.numberOfArrayElements == 1;
493   const bool textureIsNotACubemap                     = fileHeader.numberOfFaces == 0 || fileHeader.numberOfFaces == 1;
494   const bool textureHasNoMipmapLevels                 = fileHeader.numberOfMipmapLevels == 0 || fileHeader.numberOfMipmapLevels == 1;
495   const bool keyValueDataNotTooLarge                  = fileHeader.bytesOfKeyValueData <= MAX_BYTES_OF_KEYVALUE_DATA;
496
497   bool headerIsValid = signatureGood && fileEndiannessMatchesSystemEndianness &&
498                      glTypeSizeCompatibleWithCompressedTex && textureIsNot3D && textureIsNotAnArray &&
499                      textureIsNotACubemap && textureHasNoMipmapLevels && keyValueDataNotTooLarge;
500
501   if( !glTypeIsCompressed )  // check for uncompressed Alpha
502   {
503     const bool isAlpha = ( ( fileHeader.glBaseInternalFormat == KTX_UNCOMPRESSED_ALPHA8 ) && ( fileHeader.glFormat == KTX_UNCOMPRESSED_ALPHA8 ) &&
504                          ( fileHeader.glInternalFormat == KTX_UNCOMPRESSED_ALPHA8 ) );
505     headerIsValid = headerIsValid && isAlpha;
506   }
507   else
508   {
509     headerIsValid = headerIsValid && glFormatCompatibleWithCompressedTex && glInternalFormatIsSupportedCompressedTex;
510   }
511
512   if( !headerIsValid )
513   {
514      DALI_LOG_ERROR( "KTX file invalid or using unsupported features. Header tests: sig: %d, endian: %d, gl_type: %d, gl_type_size: %d, gl_format: %d, internal_format: %d, depth: %d, array: %d, faces: %d, mipmap: %d, vey-vals: %d.\n", 0+signatureGood, 0+fileEndiannessMatchesSystemEndianness, 0+glTypeIsCompressed, 0+glTypeSizeCompatibleWithCompressedTex, 0+glFormatCompatibleWithCompressedTex, 0+glInternalFormatIsSupportedCompressedTex, 0+textureIsNot3D, 0+textureIsNotAnArray, 0+textureIsNotACubemap, 0+textureHasNoMipmapLevels, 0+keyValueDataNotTooLarge);
515   }
516
517   // Warn if there is space wasted in the file:
518   if( fileHeader.bytesOfKeyValueData > 0U )
519   {
520     DALI_LOG_WARNING("Loading of KTX file with key/value header data requested. This should be stripped in application asset/resource build.\n");
521   }
522
523   return headerIsValid;
524 }
525
526
527 } // unnamed namespace
528
529 // File loading API entry-point:
530 bool LoadKtxHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
531 {
532   KtxFileHeader fileHeader;
533   FILE* const fp = input.file;
534
535   bool ret = LoadKtxHeader(fp, width, height, fileHeader);
536   return ret;
537 }
538
539 // File loading API entry-point:
540 bool LoadBitmapFromKtx( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
541 {
542   DALI_COMPILE_TIME_ASSERT( sizeof(Byte) == 1);
543   DALI_COMPILE_TIME_ASSERT( sizeof(uint32_t) == 4);
544
545   FILE* const fp = input.file;
546   if( fp == NULL )
547   {
548     DALI_LOG_ERROR( "Null file handle passed to KTX compressed bitmap file loader.\n" );
549     return false;
550   }
551   KtxFileHeader fileHeader;
552
553   // Load the header info
554   unsigned int width, height;
555
556   if (!LoadKtxHeader(fp, width, height, fileHeader))
557   {
558       return false;
559   }
560
561   // Skip the key-values:
562   const long int imageSizeOffset = sizeof(KtxFileHeader) + fileHeader.bytesOfKeyValueData;
563   if(InternalFile::fseek(fp, imageSizeOffset, SEEK_SET))
564   {
565     DALI_LOG_ERROR( "Seek past key/vals in KTX compressed bitmap file failed.\n" );
566     return false;
567   }
568
569   // Load the size of the image data:
570   uint32_t imageByteCount = 0;
571   if ( InternalFile::fread( &imageByteCount, 1, 4, fp ) != 4 )
572   {
573     DALI_LOG_ERROR( "Read of image size failed.\n" );
574     return false;
575   }
576   // Sanity-check the image size:
577   if( imageByteCount > MAX_IMAGE_DATA_SIZE ||
578       // A compressed texture should certainly be less than 2 bytes per texel:
579       imageByteCount > width * height * 2)
580   {
581     DALI_LOG_ERROR( "KTX file with too-large image-data field.\n" );
582     return false;
583   }
584
585   Pixel::Format pixelFormat;
586   const bool pixelFormatKnown = ConvertPixelFormat(fileHeader.glInternalFormat, pixelFormat);
587   if(!pixelFormatKnown)
588   {
589     DALI_LOG_ERROR( "No internal pixel format supported for KTX file pixel format.\n" );
590     return false;
591   }
592
593   // Load up the image bytes:
594   bitmap = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
595
596   // Compressed format won't allocate the buffer
597   auto pixels = bitmap.GetBuffer();
598   if( !pixels )
599   {
600     // allocate buffer manually
601     auto &impl = GetImplementation(bitmap);
602     impl.AllocateFixedSize(imageByteCount);
603     pixels = bitmap.GetBuffer();
604   }
605
606   if(!pixels)
607   {
608     DALI_LOG_ERROR( "Unable to reserve a pixel buffer to load the requested bitmap into.\n" );
609     return false;
610   }
611
612   const size_t bytesRead = InternalFile::fread(pixels, 1, imageByteCount, fp);
613   if(bytesRead != imageByteCount)
614   {
615     DALI_LOG_ERROR( "Read of image pixel data failed.\n" );
616     return false;
617   }
618
619   return true;
620 }
621
622 } // namespace TizenPlatform
623
624 } // namespace Dali