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