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