Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libktx/lib/texture2.c
21337 views
1
/* -*- tab-width: 4; -*- */
2
/* vi: set sw=2 ts=4 expandtab: */
3
4
/*
5
* Copyright 2019-2020 The Khronos Group Inc.
6
* SPDX-License-Identifier: Apache-2.0
7
*/
8
9
/**
10
* @internal
11
* @file
12
* @~English
13
*
14
* @brief ktxTexture2 implementation. Support for KTX2 format.
15
*
16
* @author Mark Callow, github.com/MarkCallow
17
*/
18
19
#if defined(_WIN32)
20
#define _CRT_SECURE_NO_WARNINGS
21
#endif
22
23
#include <assert.h>
24
#include <stdlib.h>
25
#include <string.h>
26
#include <math.h>
27
#include <zstd.h>
28
#include <zstd_errors.h>
29
#include <KHR/khr_df.h>
30
31
#include "dfdutils/dfd.h"
32
#include "ktx.h"
33
#include "ktxint.h"
34
#include "filestream.h"
35
#include "memstream.h"
36
#include "texture2.h"
37
#include "unused.h"
38
39
// FIXME: Test this #define and put it in a header somewhere.
40
//#define IS_BIG_ENDIAN (1 == *(unsigned char *)&(const int){0x01000000ul})
41
#define IS_BIG_ENDIAN 0
42
43
extern uint32_t vkFormatTypeSize(VkFormat format);
44
extern bool isProhibitedFormat(VkFormat format);
45
46
struct ktxTexture_vtbl ktxTexture2_vtbl;
47
struct ktxTexture_vtblInt ktxTexture2_vtblInt;
48
49
#if !defined(BITFIELD_ORDER_FROM_MSB)
50
// Most compilers, including all those tested so far, including clang, gcc
51
// and msvc, order bitfields from the lsb so these struct declarations work.
52
// Could this be because I've only tested on little-endian machines?
53
// These are preferred as they are much easier to manually initialize
54
// and verify.
55
struct sampleType {
56
uint32_t bitOffset: 16;
57
uint32_t bitLength: 8;
58
// MSVC 14.44 introduced a warning when mixing enums of different types.
59
// To avoid doing that make separate channelId and qualifier fields.
60
uint32_t channelId : 4;
61
uint32_t datatypeQualifiers : 4;
62
uint32_t samplePosition0 : 8;
63
uint32_t samplePosition1: 8;
64
uint32_t samplePosition2: 8;
65
uint32_t samplePosition3: 8;
66
uint32_t lower;
67
uint32_t upper;
68
};
69
70
struct BDFD {
71
uint32_t vendorId: 17;
72
uint32_t descriptorType: 15;
73
uint32_t versionNumber: 16;
74
uint32_t descriptorBlockSize: 16;
75
uint32_t model: 8;
76
uint32_t primaries: 8;
77
uint32_t transfer: 8;
78
uint32_t flags: 8;
79
uint32_t texelBlockDimension0: 8;
80
uint32_t texelBlockDimension1: 8;
81
uint32_t texelBlockDimension2: 8;
82
uint32_t texelBlockDimension3: 8;
83
uint32_t bytesPlane0: 8;
84
uint32_t bytesPlane1: 8;
85
uint32_t bytesPlane2: 8;
86
uint32_t bytesPlane3: 8;
87
uint32_t bytesPlane4: 8;
88
uint32_t bytesPlane5: 8;
89
uint32_t bytesPlane6: 8;
90
uint32_t bytesPlane7: 8;
91
struct sampleType samples[6];
92
};
93
94
struct BDFD e5b9g9r9_ufloat_comparator = {
95
.vendorId = 0,
96
.descriptorType = 0,
97
.versionNumber = 2,
98
.descriptorBlockSize = sizeof(struct BDFD),
99
.model = KHR_DF_MODEL_RGBSDA,
100
.primaries = KHR_DF_PRIMARIES_BT709,
101
.transfer = KHR_DF_TRANSFER_LINEAR,
102
.flags = KHR_DF_FLAG_ALPHA_STRAIGHT,
103
.texelBlockDimension0 = 0,
104
.texelBlockDimension1 = 0,
105
.texelBlockDimension2 = 0,
106
.texelBlockDimension3 = 0,
107
.bytesPlane0 = 4,
108
.bytesPlane1 = 0,
109
.bytesPlane2 = 0,
110
.bytesPlane3 = 0,
111
.bytesPlane4 = 0,
112
.bytesPlane5 = 0,
113
.bytesPlane6 = 0,
114
.bytesPlane7 = 0,
115
// gcc likes this way. It does not like, e.g.,
116
// .samples[0].bitOffset = 0, etc. which is accepted by both clang & msvc.
117
// I find the standards docs impenetrable so I don't know which is correct.
118
.samples[0] = {
119
.bitOffset = 0,
120
.bitLength = 8,
121
.channelId = KHR_DF_CHANNEL_RGBSDA_RED,
122
.datatypeQualifiers = 0,
123
.samplePosition0 = 0,
124
.samplePosition1 = 0,
125
.samplePosition2 = 0,
126
.samplePosition3 = 0,
127
.lower = 0,
128
.upper = 8448,
129
},
130
.samples[1] = {
131
.bitOffset = 27,
132
.bitLength = 4,
133
.channelId = KHR_DF_CHANNEL_RGBSDA_RED,
134
// The constant is defined to be ORed with a channelId into
135
// an 8-bit value. Shift to make it suitable for the 4-bit field.
136
.datatypeQualifiers = (KHR_DF_SAMPLE_DATATYPE_EXPONENT >> 4U),
137
.samplePosition0 = 0,
138
.samplePosition1 = 0,
139
.samplePosition2 = 0,
140
.samplePosition3 = 0,
141
.lower = 15,
142
.upper = 31,
143
},
144
.samples[2] = {
145
.bitOffset = 9,
146
.bitLength = 8,
147
.channelId = KHR_DF_CHANNEL_RGBSDA_GREEN,
148
.datatypeQualifiers = 0,
149
.samplePosition0 = 0,
150
.samplePosition1 = 0,
151
.samplePosition2 = 0,
152
.samplePosition3 = 0,
153
.lower = 0,
154
.upper = 8448,
155
},
156
.samples[3] = {
157
.bitOffset = 27,
158
.bitLength = 4,
159
.channelId = KHR_DF_CHANNEL_RGBSDA_GREEN,
160
// Ditto comment in samples[1].
161
.datatypeQualifiers = (KHR_DF_SAMPLE_DATATYPE_EXPONENT >> 4U),
162
.samplePosition0 = 0,
163
.samplePosition1 = 0,
164
.samplePosition2 = 0,
165
.samplePosition3 = 0,
166
.lower = 15,
167
.upper = 31,
168
},
169
.samples[4] = {
170
.bitOffset = 18,
171
.bitLength = 8,
172
.channelId = KHR_DF_CHANNEL_RGBSDA_BLUE,
173
.datatypeQualifiers = 0,
174
.samplePosition0 = 0,
175
.samplePosition1 = 0,
176
.samplePosition2 = 0,
177
.samplePosition3 = 0,
178
.lower = 0,
179
.upper = 8448,
180
},
181
.samples[5] = {
182
.bitOffset = 27,
183
.bitLength = 4,
184
.channelId = KHR_DF_CHANNEL_RGBSDA_BLUE,
185
// Ditto comment in samples[1].
186
.datatypeQualifiers = (KHR_DF_SAMPLE_DATATYPE_EXPONENT >> 4U),
187
.samplePosition0 = 0,
188
.samplePosition1 = 0,
189
.samplePosition2 = 0,
190
.samplePosition3 = 0,
191
.lower = 15,
192
.upper = 31,
193
}
194
};
195
#else
196
// For compilers which order bitfields from the msb rather than lsb.
197
#define shift(x,val) ((val) << KHR_DF_SHIFT_ ## x)
198
#define sampleshift(x,val) ((val) << KHR_DF_SAMPLESHIFT_ ## x)
199
#define e5b9g9r9_bdbwordcount KHR_DFDSIZEWORDS(6)
200
ktx_uint32_t e5b9g9r9_ufloat_comparator[e5b9g9r9_bdbwordcount] = {
201
0, // descriptorType & vendorId
202
shift(DESCRIPTORBLOCKSIZE, e5b9g9r9_bdbwordcount * sizeof(ktx_uint32_t)) | shift(VERSIONNUMBER, 2),
203
// N.B. Allow various values of primaries, transfer & flags
204
shift(FLAGS, KHR_DF_FLAG_ALPHA_STRAIGHT) | shift(TRANSFER, KHR_DF_TRANSFER_LINEAR) | shift(PRIMARIES, KHR_DF_PRIMARIES_BT709) | shift(MODEL, KHR_DF_MODEL_RGBSDA),
205
0, // texelBlockDimension3~0
206
shift(BYTESPLANE0, 4), // All other bytesPlane fields are 0.
207
0, // bytesPlane7~4
208
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 0),
209
0, // samplePosition3~0
210
0, // sampleLower
211
8448, // sampleUpper
212
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_RED | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27),
213
0, // samplePosition3~0
214
15, // sampleLower
215
31, // sampleUpper
216
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_GREEN) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 9),
217
0, // samplePosition3~0
218
0, // sampleLower
219
8448, // sampleUpper
220
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_GREEN | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27),
221
0, // samplePosition3~0
222
15, // sampleLower
223
31, // sampleUpper
224
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_BLUE) | sampleshift(BITLENGTH, 8) | sampleshift(BITOFFSET, 18),
225
0, // samplePosition3~0
226
0, // sampleLower
227
8448, // sampleUpper
228
sampleshift(CHANNELID, KHR_DF_CHANNEL_RGBSDA_BLUE | KHR_DF_SAMPLE_DATATYPE_EXPONENT) | sampleshift(BITLENGTH, 4) | sampleshift(BITOFFSET, 27),
229
0, // samplePosition3~0
230
15, // sampleLower
231
31, // sampleUpper
232
};
233
#endif
234
235
/* Helper constant:
236
Minimal size of basic descriptor block to safely read its size */
237
#define KHR_DFD_SIZEFOR_DESCRIPTORBLOCKSIZE \
238
((KHR_DF_WORD_DESCRIPTORBLOCKSIZE + 1) * sizeof(uint32_t))
239
240
/**
241
* @private
242
* @~English
243
* @brief Initialize a ktxFormatSize object from the info in a DFD.
244
*
245
* This is used instead of referring to the DFD directly so code dealing
246
* with format info can be common to KTX 1 & 2.
247
*
248
* @param[in] This pointer the ktxFormatSize to initialize.
249
* @param[in] pDFD pointer to the DFD whose data to use.
250
*
251
* @return KTX_TRUE on success, otherwise KTX_FALSE.
252
*/
253
bool
254
ktxFormatSize_initFromDfd(ktxFormatSize* This, ktx_uint32_t* pDfd)
255
{
256
uint32_t* pBdb = pDfd + 1;
257
// pDfd[0] contains totalSize in bytes, check if it has at least
258
// KHR_DFD_SIZEFOR_DESCRIPTORBLOCKSIZE bytes
259
if (pDfd[0] < KHR_DFD_SIZEFOR_DESCRIPTORBLOCKSIZE || *pBdb != 0) {
260
// Either decriptorType or vendorId is not 0
261
return false;
262
}
263
// Iterate through all block descriptors and check if sum of their sizes
264
// is equal to the totalSize in pDfd[0]
265
uint32_t descriptorSize = pDfd[0] - sizeof(uint32_t);
266
while(descriptorSize > KHR_DFD_SIZEFOR_DESCRIPTORBLOCKSIZE) {
267
uint32_t descriptorBlockSize = KHR_DFDVAL(pBdb, DESCRIPTORBLOCKSIZE);
268
if (descriptorBlockSize <= descriptorSize) {
269
descriptorSize -= descriptorBlockSize;
270
pBdb += descriptorBlockSize / sizeof(uint32_t);
271
} else {
272
break;
273
}
274
}
275
if (descriptorSize != 0) {
276
return false;
277
}
278
279
// reset pBdb pointer to the first block descriptor
280
pBdb = pDfd + 1;
281
282
// Check the DFD is of the expected version.
283
if (KHR_DFDVAL(pBdb, VERSIONNUMBER) != KHR_DF_VERSIONNUMBER_1_3) {
284
return false;
285
}
286
287
// DFD has supported type and version. Process it.
288
This->blockWidth = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION0) + 1;
289
This->blockHeight = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION1) + 1;
290
This->blockDepth = KHR_DFDVAL(pBdb, TEXELBLOCKDIMENSION2) + 1;
291
if (KHR_DFDVAL(pBdb, BYTESPLANE0) == 0) {
292
// The DFD uses the deprecated way of indicating a supercompressed
293
// texture. Reconstruct the original values.
294
reconstructDFDBytesPlanesFromSamples(pDfd);
295
}
296
This->blockSizeInBits = KHR_DFDVAL(pBdb, BYTESPLANE0) * 8;
297
// Account for ETC1S with possible second slice.
298
This->blockSizeInBits += KHR_DFDVAL(pBdb, BYTESPLANE1) * 8;
299
This->paletteSizeInBits = 0; // No paletted formats in ktx v2.
300
This->flags = 0;
301
This->minBlocksX = This->minBlocksY = 1;
302
if (KHR_DFDVAL(pBdb, MODEL) >= KHR_DF_MODEL_DXT1A) {
303
// A block compressed format. Entire block is a single sample.
304
This->flags |= KTX_FORMAT_SIZE_COMPRESSED_BIT;
305
if (KHR_DFDVAL(pBdb, MODEL) == KHR_DF_MODEL_ETC1S) {
306
// Special case the only multi-plane format we handle.
307
This->blockSizeInBits += KHR_DFDVAL(pBdb, BYTESPLANE1) * 8;
308
}
309
if (KHR_DFDVAL(pBdb, MODEL) == KHR_DF_MODEL_PVRTC) {
310
This->minBlocksX = This->minBlocksY = 2;
311
}
312
} else {
313
// An uncompressed format.
314
315
// Special case depth & depth stencil formats
316
if (KHR_DFDSVAL(pBdb, 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_DEPTH) {
317
if (KHR_DFDSAMPLECOUNT(pBdb) == 1) {
318
This->flags |= KTX_FORMAT_SIZE_DEPTH_BIT;
319
} else if (KHR_DFDSAMPLECOUNT(pBdb) == 2) {
320
This->flags |= KTX_FORMAT_SIZE_STENCIL_BIT;
321
This->flags |= KTX_FORMAT_SIZE_DEPTH_BIT;
322
This->flags |= KTX_FORMAT_SIZE_PACKED_BIT;
323
} else {
324
return false;
325
}
326
} else if (KHR_DFDSVAL(pBdb, 0, CHANNELID) == KHR_DF_CHANNEL_RGBSDA_STENCIL) {
327
This->flags |= KTX_FORMAT_SIZE_STENCIL_BIT;
328
} else if (KHR_DFDSAMPLECOUNT(pBdb) == 6
329
#if !defined(BITFIELD_ORDER_FROM_MSB)
330
&& !memcmp(((uint32_t*)&e5b9g9r9_ufloat_comparator) + KHR_DF_WORD_TEXELBLOCKDIMENSION0, &pBdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0], sizeof(e5b9g9r9_ufloat_comparator)-(KHR_DF_WORD_TEXELBLOCKDIMENSION0)*sizeof(uint32_t))) {
331
#else
332
&& !memcmp(&e5b9g9r9_ufloat_comparator[KHR_DF_WORD_TEXELBLOCKDIMENSION0], &pBdb[KHR_DF_WORD_TEXELBLOCKDIMENSION0], sizeof(e5b9g9r9_ufloat_comparator)-(KHR_DF_WORD_TEXELBLOCKDIMENSION0)*sizeof(uint32_t))) {
333
#endif
334
// Special case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 as interpretDFD
335
// only handles "simple formats", i.e. where channels are described
336
// in contiguous bits.
337
This->flags |= KTX_FORMAT_SIZE_PACKED_BIT;
338
} else {
339
InterpretedDFDChannel rgba[4];
340
uint32_t wordBytes;
341
enum InterpretDFDResult result;
342
343
result = interpretDFD(pDfd, &rgba[0], &rgba[1], &rgba[2], &rgba[3],
344
&wordBytes);
345
if (result >= i_UNSUPPORTED_ERROR_BIT)
346
return false;
347
if (result & i_PACKED_FORMAT_BIT)
348
This->flags |= KTX_FORMAT_SIZE_PACKED_BIT;
349
if (result & i_COMPRESSED_FORMAT_BIT)
350
This->flags |= KTX_FORMAT_SIZE_COMPRESSED_BIT;
351
if (result & i_YUVSDA_FORMAT_BIT)
352
This->flags |= KTX_FORMAT_SIZE_YUVSDA_BIT;
353
}
354
}
355
return true;
356
}
357
358
/**
359
* @private
360
* @~English
361
* @brief Create a DFD for a VkFormat.
362
*
363
* This KTX-specific function adds support for combined depth stencil formats
364
* which are not supported by @e dfdutils' @c vk2dfd function because they
365
* are not seen outside a Vulkan device. KTX has its own definitions for
366
* these that enable uploading, with some effort.
367
*
368
* @param[in] vkFormat the format for which to create a DFD.
369
*/
370
static uint32_t*
371
ktxVk2dfd(ktx_uint32_t vkFormat)
372
{
373
return vk2dfd(vkFormat);
374
}
375
376
/**
377
* @memberof ktxTexture2 @private
378
* @~English
379
* @brief Do the part of ktxTexture2 construction that is common to
380
* new textures and those constructed from a stream.
381
*
382
* @param[in] This pointer to a ktxTexture2-sized block of memory to
383
* initialize.
384
* @param[in] numLevels the number of levels the texture must have.
385
*
386
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
387
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data.
388
*/
389
static KTX_error_code
390
ktxTexture2_constructCommon(ktxTexture2* This, ktx_uint32_t numLevels)
391
{
392
assert(This != NULL);
393
ktx_size_t privateSize;
394
395
This->classId = ktxTexture2_c;
396
This->vtbl = &ktxTexture2_vtbl;
397
This->_protected->_vtbl = ktxTexture2_vtblInt;
398
privateSize = sizeof(ktxTexture2_private)
399
+ sizeof(ktxLevelIndexEntry) * (numLevels - 1);
400
This->_private = (ktxTexture2_private*)malloc(privateSize);
401
if (This->_private == NULL) {
402
return KTX_OUT_OF_MEMORY;
403
}
404
memset(This->_private, 0, privateSize);
405
return KTX_SUCCESS;
406
}
407
408
/*
409
* In hindsight this function should have been `#if KTX_FEATURE_WRITE`.
410
* In the interest of not breaking an app that may be using this via
411
* `ktxTexture2_Create` in `libktx_read` we won't change it.
412
*/
413
/**
414
* @memberof ktxTexture2 @private
415
* @~English
416
* @brief Construct a new, empty, ktxTexture2.
417
*
418
* @param[in] This pointer to a ktxTexture2-sized block of memory to
419
* initialize.
420
* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
421
* information describing the texture.
422
* @param[in] storageAllocation
423
* enum indicating whether or not to allocate storage
424
* for the texture images.
425
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
426
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture or image data.
427
* @exception KTX_UNSUPPORTED_TEXTURE_TYPE
428
* The request VkFormat is one of the
429
* prohibited formats or is otherwise
430
* unsupported.
431
*/
432
static KTX_error_code
433
ktxTexture2_construct(ktxTexture2* This,
434
const ktxTextureCreateInfo* const createInfo,
435
ktxTextureCreateStorageEnum storageAllocation)
436
{
437
ktxFormatSize formatSize;
438
KTX_error_code result;
439
440
memset(This, 0, sizeof(*This));
441
442
if (createInfo->vkFormat != VK_FORMAT_UNDEFINED) {
443
if (isProhibitedFormat(createInfo->vkFormat))
444
return KTX_UNSUPPORTED_TEXTURE_TYPE;
445
This->pDfd = ktxVk2dfd(createInfo->vkFormat);
446
if (!This->pDfd)
447
return KTX_INVALID_VALUE; // Format is unknown or unsupported.
448
449
#ifdef _DEBUG
450
// If this fires, an unsupported format or incorrect DFD
451
// has crept into vk2dfd.
452
assert(ktxFormatSize_initFromDfd(&formatSize, This->pDfd));
453
#else
454
(void)ktxFormatSize_initFromDfd(&formatSize, This->pDfd);
455
#endif
456
457
} else {
458
// TODO: Validate createInfo->pDfd.
459
This->pDfd = (ktx_uint32_t*)malloc(*createInfo->pDfd);
460
if (!This->pDfd)
461
return KTX_OUT_OF_MEMORY;
462
memcpy(This->pDfd, createInfo->pDfd, *createInfo->pDfd);
463
if (!ktxFormatSize_initFromDfd(&formatSize, This->pDfd)) {
464
result = KTX_UNSUPPORTED_TEXTURE_TYPE;
465
goto cleanup;
466
}
467
}
468
469
result = ktxTexture_construct(ktxTexture(This), createInfo, &formatSize);
470
471
if (result != KTX_SUCCESS)
472
return result;
473
result = ktxTexture2_constructCommon(This, createInfo->numLevels);
474
if (result != KTX_SUCCESS)
475
goto cleanup;;
476
477
This->vkFormat = createInfo->vkFormat;
478
479
// The typeSize cannot be reconstructed just from the DFD as the BDFD
480
// does not capture the packing expressed by the [m]PACK[n] layout
481
// information in the VkFormat, so we calculate the typeSize directly
482
// from the vkFormat
483
This->_protected->_typeSize = vkFormatTypeSize(createInfo->vkFormat);
484
485
This->supercompressionScheme = KTX_SS_NONE;
486
487
This->_private->_requiredLevelAlignment
488
= ktxTexture2_calcRequiredLevelAlignment(This);
489
490
// Create levelIndex. Offsets are from start of the KTX2 stream.
491
ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex;
492
493
This->_private->_firstLevelFileOffset = 0;
494
495
for (ktx_uint32_t level = 0; level < This->numLevels; level++) {
496
levelIndex[level].uncompressedByteLength =
497
ktxTexture_calcLevelSize(ktxTexture(This), level,
498
KTX_FORMAT_VERSION_TWO);
499
levelIndex[level].byteLength =
500
levelIndex[level].uncompressedByteLength;
501
levelIndex[level].byteOffset =
502
ktxTexture_calcLevelOffset(ktxTexture(This), level);
503
}
504
505
// Allocate storage, if requested.
506
if (storageAllocation == KTX_TEXTURE_CREATE_ALLOC_STORAGE) {
507
This->dataSize
508
= ktxTexture_calcDataSizeTexture(ktxTexture(This));
509
This->pData = malloc(This->dataSize);
510
if (This->pData == NULL) {
511
result = KTX_OUT_OF_MEMORY;
512
goto cleanup;
513
}
514
}
515
return result;
516
517
cleanup:
518
ktxTexture2_destruct(This);
519
return result;
520
}
521
522
/**
523
* @memberof ktxTexture2 @private
524
* @~English
525
* @brief Construct a ktxTexture by copying a source ktxTexture.
526
*
527
* @param[in] This pointer to a ktxTexture2-sized block of memory to
528
* initialize.
529
* @param[in] orig pointer to the source texture to copy.
530
*
531
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
532
*
533
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data.
534
*/
535
KTX_error_code
536
ktxTexture2_constructCopy(ktxTexture2* This, ktxTexture2* orig)
537
{
538
KTX_error_code result;
539
540
memcpy(This, orig, sizeof(ktxTexture2));
541
// Zero all the pointers to make error handling easier
542
This->_protected = NULL;
543
This->_private = NULL;
544
This->pDfd = NULL;
545
This->kvData = NULL;
546
This->kvDataHead = NULL;
547
This->pData = NULL;
548
549
This->_protected =
550
(ktxTexture_protected*)malloc(sizeof(ktxTexture_protected));
551
if (!This->_protected)
552
return KTX_OUT_OF_MEMORY;
553
// Must come before memcpy of _protected so as to close an active stream.
554
if (!orig->pData && ktxTexture_isActiveStream((ktxTexture*)orig))
555
ktxTexture2_LoadImageData(orig, NULL, 0);
556
memcpy(This->_protected, orig->_protected, sizeof(ktxTexture_protected));
557
558
ktx_size_t privateSize = sizeof(ktxTexture2_private)
559
+ sizeof(ktxLevelIndexEntry) * (orig->numLevels - 1);
560
This->_private = (ktxTexture2_private*)malloc(privateSize);
561
if (This->_private == NULL) {
562
result = KTX_OUT_OF_MEMORY;
563
goto cleanup;
564
}
565
memcpy(This->_private, orig->_private, privateSize);
566
if (orig->_private->_sgdByteLength > 0) {
567
This->_private->_supercompressionGlobalData
568
= (ktx_uint8_t*)malloc(orig->_private->_sgdByteLength);
569
if (!This->_private->_supercompressionGlobalData) {
570
result = KTX_OUT_OF_MEMORY;
571
goto cleanup;
572
}
573
memcpy(This->_private->_supercompressionGlobalData,
574
orig->_private->_supercompressionGlobalData,
575
orig->_private->_sgdByteLength);
576
}
577
578
This->pDfd = (ktx_uint32_t*)malloc(*orig->pDfd);
579
if (!This->pDfd) {
580
result = KTX_OUT_OF_MEMORY;
581
goto cleanup;
582
}
583
memcpy(This->pDfd, orig->pDfd, *orig->pDfd);
584
585
if (orig->kvDataHead) {
586
ktxHashList_ConstructCopy(&This->kvDataHead, orig->kvDataHead);
587
} else if (orig->kvData) {
588
This->kvData = (ktx_uint8_t*)malloc(orig->kvDataLen);
589
if (!This->kvData) {
590
result = KTX_OUT_OF_MEMORY;
591
goto cleanup;
592
}
593
memcpy(This->kvData, orig->kvData, orig->kvDataLen);
594
}
595
596
// Can't share the image data as the data pointer is exposed in the
597
// ktxTexture2 structure. Changing it to a ref-counted pointer would
598
// break code. Maybe that's okay as we're still pre-release. But,
599
// since this constructor will be mostly be used when transcoding
600
// supercompressed images, it is probably not too big a deal to make
601
// a copy of the data.
602
This->pData = (ktx_uint8_t*)malloc(This->dataSize);
603
if (This->pData == NULL) {
604
result = KTX_OUT_OF_MEMORY;
605
goto cleanup;
606
}
607
memcpy(This->pData, orig->pData, orig->dataSize);
608
return KTX_SUCCESS;
609
610
cleanup:
611
if (This->_protected) free(This->_protected);
612
if (This->_private) {
613
if (This->_private->_supercompressionGlobalData)
614
free(This->_private->_supercompressionGlobalData);
615
free(This->_private);
616
}
617
if (This->pDfd) free (This->pDfd);
618
if (This->kvDataHead) ktxHashList_Destruct(&This->kvDataHead);
619
620
return result;
621
}
622
623
bool isSrgbFormat(VkFormat format);
624
bool isNotSrgbFormatButHasSrgbVariant(VkFormat format);
625
626
/**
627
* @memberof ktxTexture2 @private
628
* @~English
629
* @brief Construct a ktxTexture from a ktxStream reading from a KTX source.
630
*
631
* The KTX header, which must have been read prior to calling this, is passed
632
* to the function.
633
*
634
* The stream object is copied into the constructed ktxTexture2.
635
*
636
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
637
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
638
* will minimize memory usage by allowing, for example, loading the images
639
* directly from the source into a Vulkan staging buffer.
640
*
641
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
642
* provided solely to enable implementation of the @e libktx v1 API on top of
643
* ktxTexture.
644
*
645
* If either KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT or
646
* KTX_TEXTURE_CREATE_RAW_KVDATA_BIT is set then the ktxTexture's orientation
647
* fields will be set to defaults even if the KTX source contains
648
* KTXorientation metadata.
649
*
650
* @param[in] This pointer to a ktxTexture2-sized block of memory to
651
* initialize.
652
* @param[in] pStream pointer to the stream to read.
653
* @param[in] pHeader pointer to a KTX header that has already been read from
654
* the stream.
655
* @param[in] createFlags bitmask requesting specific actions during creation.
656
*
657
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
658
*
659
* @exception KTX_FILE_DATA_ERROR
660
* Source data is inconsistent with the KTX
661
* specification.
662
* @exception KTX_FILE_READ_ERROR
663
* An error occurred while reading the source.
664
* @exception KTX_FILE_UNEXPECTED_EOF
665
* Not enough data in the source.
666
* @exception KTX_OUT_OF_MEMORY Not enough memory to load either the images or
667
* the key-value data.
668
* @exception KTX_UNKNOWN_FILE_FORMAT
669
* The source is not in KTX format.
670
* @exception KTX_UNSUPPORTED_TEXTURE_TYPE
671
* The source describes a texture type not
672
* supported by OpenGL or Vulkan, e.g, a 3D array.
673
*/
674
KTX_error_code
675
ktxTexture2_constructFromStreamAndHeader(ktxTexture2* This, ktxStream* pStream,
676
KTX_header2* pHeader,
677
ktxTextureCreateFlags createFlags)
678
{
679
ktxTexture2_private* private;
680
KTX_error_code result;
681
KTX_supplemental_info suppInfo;
682
ktxStream* stream;
683
struct BDFD* pBDFD;
684
ktx_size_t levelIndexSize;
685
686
assert(pHeader != NULL && pStream != NULL);
687
688
memset(This, 0, sizeof(*This));
689
result = ktxTexture_constructFromStream(ktxTexture(This), pStream,
690
createFlags);
691
if (result != KTX_SUCCESS)
692
return result;
693
694
result = ktxCheckHeader2_(pHeader, &suppInfo);
695
if (result != KTX_SUCCESS)
696
goto cleanup;
697
// ktxCheckHeader2_ has done the max(1, levelCount) on pHeader->levelCount.
698
result = ktxTexture2_constructCommon(This, pHeader->levelCount);
699
if (result != KTX_SUCCESS)
700
goto cleanup;
701
private = This->_private;
702
703
stream = ktxTexture2_getStream(This);
704
705
/*
706
* Initialize from pHeader->info.
707
*/
708
This->vkFormat = pHeader->vkFormat;
709
This->supercompressionScheme = pHeader->supercompressionScheme;
710
711
This->_protected->_typeSize = pHeader->typeSize;
712
// Can these be done by a ktxTexture_constructFromStream?
713
This->numDimensions = suppInfo.textureDimension;
714
This->baseWidth = pHeader->pixelWidth;
715
assert(suppInfo.textureDimension > 0 && suppInfo.textureDimension < 4);
716
switch (suppInfo.textureDimension) {
717
case 1:
718
This->baseHeight = This->baseDepth = 1;
719
break;
720
case 2:
721
This->baseHeight = pHeader->pixelHeight;
722
This->baseDepth = 1;
723
break;
724
case 3:
725
This->baseHeight = pHeader->pixelHeight;
726
This->baseDepth = pHeader->pixelDepth;
727
break;
728
}
729
if (pHeader->layerCount > 0) {
730
This->numLayers = pHeader->layerCount;
731
This->isArray = KTX_TRUE;
732
} else {
733
This->numLayers = 1;
734
This->isArray = KTX_FALSE;
735
}
736
This->numFaces = pHeader->faceCount;
737
if (pHeader->faceCount == 6)
738
This->isCubemap = KTX_TRUE;
739
else
740
This->isCubemap = KTX_FALSE;
741
// ktxCheckHeader2_ does the max(1, levelCount) and sets
742
// suppInfo.generateMipmaps when it was originally 0.
743
This->numLevels = pHeader->levelCount;
744
This->generateMipmaps = suppInfo.generateMipmaps;
745
746
// Read level index
747
levelIndexSize = sizeof(ktxLevelIndexEntry) * This->numLevels;
748
result = stream->read(stream, &private->_levelIndex, levelIndexSize);
749
if (result != KTX_SUCCESS)
750
goto cleanup;
751
// Rebase index to start of data and save file offset.
752
private->_firstLevelFileOffset
753
= private->_levelIndex[This->numLevels-1].byteOffset;
754
for (ktx_uint32_t level = 0; level < This->numLevels; level++) {
755
private->_levelIndex[level].byteOffset
756
-= private->_firstLevelFileOffset;
757
if (This->supercompressionScheme == KTX_SS_NONE &&
758
private->_levelIndex[level].byteLength != private->_levelIndex[level].uncompressedByteLength) {
759
// For non-supercompressed files the levels must have matching byte lengths
760
result = KTX_FILE_DATA_ERROR;
761
}
762
}
763
if (result != KTX_SUCCESS)
764
goto cleanup;
765
766
// Read DFD
767
if (pHeader->dataFormatDescriptor.byteOffset == 0 || pHeader->dataFormatDescriptor.byteLength < 16) {
768
// Missing or too small DFD
769
result = KTX_FILE_DATA_ERROR;
770
goto cleanup;
771
}
772
This->pDfd =
773
(ktx_uint32_t*)malloc(pHeader->dataFormatDescriptor.byteLength);
774
if (!This->pDfd) {
775
result = KTX_OUT_OF_MEMORY;
776
goto cleanup;
777
}
778
result = stream->read(stream, This->pDfd,
779
pHeader->dataFormatDescriptor.byteLength);
780
if (result != KTX_SUCCESS)
781
goto cleanup;
782
783
if (pHeader->dataFormatDescriptor.byteLength != This->pDfd[0]) {
784
// DFD byteLength does not match dfdTotalSize
785
result = KTX_FILE_DATA_ERROR;
786
goto cleanup;
787
}
788
pBDFD = (struct BDFD*)(This->pDfd + 1);
789
if (pBDFD->descriptorBlockSize < 24 || (pBDFD->descriptorBlockSize - 24) % 16 != 0) {
790
// BDFD has invalid size
791
result = KTX_FILE_DATA_ERROR;
792
goto cleanup;
793
}
794
if (pBDFD->transfer > KHR_DF_TRANSFER_HLG_UNNORMALIZED_OETF) {
795
// Invalid transfer function
796
result = KTX_FILE_DATA_ERROR;
797
goto cleanup;
798
}
799
// No test for VK_FORMAT_UNDEFINED is needed here because:
800
// - any transfer function is allowed when vkFormat is UNDEFINED as with,
801
// e.g., some Basis Universal formats;
802
// - the following tests return false for VK_FORMAT_UNDEFINED.
803
if (isSrgbFormat(This->vkFormat) && pBDFD->transfer != KHR_DF_TRANSFER_SRGB) {
804
// Invalid transfer function
805
result = KTX_FILE_DATA_ERROR;
806
goto cleanup;
807
}
808
if (isNotSrgbFormatButHasSrgbVariant(This->vkFormat)
809
&& pBDFD->transfer == KHR_DF_TRANSFER_SRGB) {
810
// Invalid transfer function
811
result = KTX_FILE_DATA_ERROR;
812
goto cleanup;
813
}
814
815
if (!ktxFormatSize_initFromDfd(&This->_protected->_formatSize, This->pDfd)) {
816
result = KTX_UNSUPPORTED_TEXTURE_TYPE;
817
goto cleanup;
818
}
819
This->isCompressed = (This->_protected->_formatSize.flags & KTX_FORMAT_SIZE_COMPRESSED_BIT);
820
821
if (This->supercompressionScheme == KTX_SS_BASIS_LZ && pBDFD->model != KHR_DF_MODEL_ETC1S) {
822
result = KTX_FILE_DATA_ERROR;
823
goto cleanup;
824
}
825
826
// Check compatibility with the KHR_texture_basisu glTF extension, if needed.
827
if (createFlags & KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT) {
828
uint32_t max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth);
829
uint32_t full_mip_pyramid_level_count = 1 + (uint32_t)log2(max_dim);
830
if (pHeader->levelCount != 1 && pHeader->levelCount != full_mip_pyramid_level_count) {
831
// KHR_texture_basisu requires full mip pyramid or single mip level
832
result = KTX_FILE_DATA_ERROR;
833
goto cleanup;
834
}
835
if (This->numDimensions != 2 || This->isArray || This->isCubemap) {
836
// KHR_texture_basisu requires 2D textures.
837
result = KTX_FILE_DATA_ERROR;
838
goto cleanup;
839
}
840
if ((This->baseWidth % 4) != 0 || (This->baseHeight % 4) != 0) {
841
// KHR_texture_basisu requires width and height to be a multiple of 4.
842
result = KTX_FILE_DATA_ERROR;
843
goto cleanup;
844
}
845
if (pBDFD->model != KHR_DF_MODEL_ETC1S && pBDFD->model != KHR_DF_MODEL_UASTC) {
846
// KHR_texture_basisu requires BasisLZ or UASTC
847
result = KTX_FILE_DATA_ERROR;
848
goto cleanup;
849
}
850
if (pBDFD->model == KHR_DF_MODEL_UASTC &&
851
This->supercompressionScheme != KTX_SS_NONE &&
852
This->supercompressionScheme != KTX_SS_ZSTD) {
853
// KHR_texture_basisu only allows NONE and ZSTD supercompression for UASTC
854
result = KTX_FILE_DATA_ERROR;
855
goto cleanup;
856
}
857
}
858
859
uint32_t sampleCount = KHR_DFDSAMPLECOUNT(This->pDfd + 1);
860
if (sampleCount == 0) {
861
// Invalid sample count
862
result = KTX_FILE_DATA_ERROR;
863
goto cleanup;
864
}
865
if (pBDFD->model == KHR_DF_MODEL_ETC1S || pBDFD->model == KHR_DF_MODEL_UASTC) {
866
if (sampleCount < 1 || sampleCount > 2 || (sampleCount == 2 && pBDFD->model == KHR_DF_MODEL_UASTC)) {
867
// Invalid sample count
868
result = KTX_FILE_DATA_ERROR;
869
goto cleanup;
870
}
871
if (pBDFD->texelBlockDimension0 != 3 || pBDFD->texelBlockDimension1 != 3 ||
872
pBDFD->texelBlockDimension2 != 0 || pBDFD->texelBlockDimension3 != 0) {
873
// Texel block dimension must be 4x4x1x1 (offset by one)
874
result = KTX_FILE_DATA_ERROR;
875
goto cleanup;
876
}
877
}
878
879
This->_private->_requiredLevelAlignment
880
= ktxTexture2_calcRequiredLevelAlignment(This);
881
882
// Make an empty hash list.
883
ktxHashList_Construct(&This->kvDataHead);
884
// Load KVData.
885
if (pHeader->keyValueData.byteLength > 0) {
886
uint32_t expectedOffset = pHeader->dataFormatDescriptor.byteOffset + pHeader->dataFormatDescriptor.byteLength;
887
expectedOffset = (expectedOffset + 3) & ~0x3; // 4 byte aligned
888
if (pHeader->keyValueData.byteOffset != expectedOffset) {
889
result = KTX_FILE_DATA_ERROR;
890
goto cleanup;
891
}
892
if (!(createFlags & KTX_TEXTURE_CREATE_SKIP_KVDATA_BIT)) {
893
ktx_uint32_t kvdLen = pHeader->keyValueData.byteLength;
894
ktx_uint8_t* pKvd;
895
896
pKvd = malloc(kvdLen);
897
if (pKvd == NULL) {
898
result = KTX_OUT_OF_MEMORY;
899
goto cleanup;
900
}
901
902
result = stream->read(stream, pKvd, kvdLen);
903
if (result != KTX_SUCCESS) {
904
free(pKvd);
905
goto cleanup;
906
}
907
908
if (IS_BIG_ENDIAN) {
909
/* Swap the counts inside the key & value data. */
910
ktx_uint8_t* src = pKvd;
911
ktx_uint8_t* end = pKvd + kvdLen;
912
while (src < end) {
913
ktx_uint32_t keyAndValueByteSize = *((ktx_uint32_t*)src);
914
_ktxSwapEndian32(&keyAndValueByteSize, 1);
915
src += _KTX_PAD4(keyAndValueByteSize);
916
}
917
}
918
919
if (!(createFlags & KTX_TEXTURE_CREATE_RAW_KVDATA_BIT)) {
920
char* orientationStr;
921
ktx_uint32_t orientationLen;
922
ktx_uint32_t animData[3];
923
ktx_uint32_t animDataLen;
924
925
result = ktxHashList_Deserialize(&This->kvDataHead,
926
kvdLen, pKvd);
927
free(pKvd);
928
if (result != KTX_SUCCESS) {
929
goto cleanup;
930
}
931
932
result = ktxHashList_FindValue(&This->kvDataHead,
933
KTX_ORIENTATION_KEY,
934
&orientationLen,
935
(void**)&orientationStr);
936
assert(result != KTX_INVALID_VALUE);
937
if (result == KTX_SUCCESS) {
938
// Length includes the terminating NUL.
939
if (orientationLen != This->numDimensions + 1) {
940
// There needs to be an entry for each dimension of
941
// the texture.
942
result = KTX_FILE_DATA_ERROR;
943
goto cleanup;
944
} else {
945
switch (This->numDimensions) {
946
case 3:
947
This->orientation.z = orientationStr[2];
948
FALLTHROUGH;
949
case 2:
950
This->orientation.y = orientationStr[1];
951
FALLTHROUGH;
952
case 1:
953
This->orientation.x = orientationStr[0];
954
}
955
}
956
} else {
957
result = KTX_SUCCESS; // Not finding orientation is okay.
958
}
959
result = ktxHashList_FindValue(&This->kvDataHead,
960
KTX_ANIMDATA_KEY,
961
&animDataLen,
962
(void**)animData);
963
assert(result != KTX_INVALID_VALUE);
964
if (result == KTX_SUCCESS) {
965
if (animDataLen != sizeof(animData)) {
966
result = KTX_FILE_DATA_ERROR;
967
goto cleanup;
968
}
969
if (This->isArray) {
970
This->isVideo = KTX_TRUE;
971
This->duration = animData[0];
972
This->timescale = animData[1];
973
This->loopcount = animData[2];
974
} else {
975
// animData is only valid for array textures.
976
result = KTX_FILE_DATA_ERROR;
977
goto cleanup;
978
}
979
} else {
980
result = KTX_SUCCESS; // Not finding video is okay.
981
}
982
} else {
983
This->kvDataLen = kvdLen;
984
This->kvData = pKvd;
985
}
986
} else {
987
stream->skip(stream, pHeader->keyValueData.byteLength);
988
}
989
} else if (pHeader->keyValueData.byteOffset != 0) {
990
// Non-zero KVD byteOffset with zero byteLength
991
result = KTX_FILE_DATA_ERROR;
992
goto cleanup;
993
}
994
995
if (pHeader->supercompressionGlobalData.byteLength > 0) {
996
switch (This->supercompressionScheme) {
997
case KTX_SS_BASIS_LZ:
998
break;
999
case KTX_SS_NONE:
1000
case KTX_SS_ZSTD:
1001
case KTX_SS_ZLIB:
1002
// In these cases SGD is not allowed
1003
result = KTX_FILE_DATA_ERROR;
1004
break;
1005
default:
1006
// We don't support other supercompression schemes
1007
result = KTX_UNSUPPORTED_FEATURE;
1008
break;
1009
}
1010
if (result != KTX_SUCCESS)
1011
goto cleanup;
1012
1013
// There could be padding here so seek to the next item.
1014
result = stream->setpos(stream,
1015
pHeader->supercompressionGlobalData.byteOffset);
1016
if (result != KTX_SUCCESS)
1017
goto cleanup;
1018
1019
// Read supercompressionGlobalData
1020
private->_supercompressionGlobalData =
1021
(ktx_uint8_t*)malloc(pHeader->supercompressionGlobalData.byteLength);
1022
if (!private->_supercompressionGlobalData) {
1023
result = KTX_OUT_OF_MEMORY;
1024
goto cleanup;
1025
}
1026
private->_sgdByteLength
1027
= pHeader->supercompressionGlobalData.byteLength;
1028
result = stream->read(stream, private->_supercompressionGlobalData,
1029
private->_sgdByteLength);
1030
1031
if (result != KTX_SUCCESS)
1032
goto cleanup;
1033
} else if (pHeader->supercompressionGlobalData.byteOffset != 0) {
1034
// Non-zero SGD byteOffset with zero byteLength
1035
result = KTX_FILE_DATA_ERROR;
1036
goto cleanup;
1037
} else if (This->supercompressionScheme == KTX_SS_BASIS_LZ) {
1038
// SGD is required for BasisLZ
1039
result = KTX_FILE_DATA_ERROR;
1040
goto cleanup;
1041
}
1042
1043
// Calculate size of the image data. Level 0 is the last level in the data.
1044
This->dataSize = private->_levelIndex[0].byteOffset
1045
+ private->_levelIndex[0].byteLength;
1046
1047
/*
1048
* Load the images, if requested.
1049
*/
1050
if (createFlags & KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT) {
1051
result = ktxTexture2_LoadImageData(This, NULL, 0);
1052
}
1053
if (result != KTX_SUCCESS)
1054
goto cleanup;
1055
1056
return result;
1057
1058
cleanup:
1059
ktxTexture2_destruct(This);
1060
return result;
1061
}
1062
1063
/**
1064
* @memberof ktxTexture2 @private
1065
* @~English
1066
* @brief Construct a ktxTexture from a ktxStream reading from a KTX source.
1067
*
1068
* The stream object is copied into the constructed ktxTexture2.
1069
*
1070
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
1071
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
1072
* will minimize memory usage by allowing, for example, loading the images
1073
* directly from the source into a Vulkan staging buffer.
1074
*
1075
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
1076
* provided solely to enable implementation of the @e libktx v1 API on top of
1077
* ktxTexture.
1078
*
1079
* @param[in] This pointer to a ktxTexture2-sized block of memory to
1080
* initialize.
1081
* @param[in] pStream pointer to the stream to read.
1082
* @param[in] createFlags bitmask requesting specific actions during creation.
1083
*
1084
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1085
*
1086
* @exception KTX_FILE_READ_ERROR
1087
* An error occurred while reading the source.
1088
*
1089
* For other exceptions see ktxTexture2_constructFromStreamAndHeader().
1090
*/
1091
static KTX_error_code
1092
ktxTexture2_constructFromStream(ktxTexture2* This, ktxStream* pStream,
1093
ktxTextureCreateFlags createFlags)
1094
{
1095
KTX_header2 header;
1096
KTX_error_code result;
1097
1098
// Read header.
1099
result = pStream->read(pStream, &header, KTX2_HEADER_SIZE);
1100
if (result != KTX_SUCCESS)
1101
return result;
1102
1103
#if IS_BIG_ENDIAN
1104
// byte swap the header
1105
#endif
1106
return ktxTexture2_constructFromStreamAndHeader(This, pStream,
1107
&header, createFlags);
1108
}
1109
1110
/**
1111
* @memberof ktxTexture2 @private
1112
* @~English
1113
* @brief Construct a ktxTexture from a stdio stream reading from a KTX source.
1114
*
1115
* See ktxTextureInt_constructFromStream for details.
1116
*
1117
* @note Do not close the stdio stream until you are finished with the texture
1118
* object.
1119
*
1120
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
1121
* initialize.
1122
* @param[in] stdioStream a stdio FILE pointer opened on the source.
1123
* @param[in] createFlags bitmask requesting specific actions during creation.
1124
*
1125
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1126
*
1127
* @exception KTX_INVALID_VALUE Either @p stdiostream or @p This is null.
1128
*
1129
* For other exceptions, see ktxTexture_constructFromStream().
1130
*/
1131
static KTX_error_code
1132
ktxTexture2_constructFromStdioStream(ktxTexture2* This, FILE* stdioStream,
1133
ktxTextureCreateFlags createFlags)
1134
{
1135
KTX_error_code result;
1136
ktxStream stream;
1137
1138
if (stdioStream == NULL || This == NULL)
1139
return KTX_INVALID_VALUE;
1140
1141
result = ktxFileStream_construct(&stream, stdioStream, KTX_FALSE);
1142
if (result == KTX_SUCCESS)
1143
result = ktxTexture2_constructFromStream(This, &stream, createFlags);
1144
return result;
1145
}
1146
1147
/**
1148
* @memberof ktxTexture2 @private
1149
* @~English
1150
* @brief Construct a ktxTexture from a named KTX file.
1151
*
1152
* The file name must be encoded in utf-8. On Windows convert unicode names
1153
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
1154
*
1155
* See ktxTextureInt_constructFromStream for details.
1156
*
1157
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
1158
* initialize.
1159
* @param[in] filename pointer to a char array containing the file name.
1160
* @param[in] createFlags bitmask requesting specific actions during creation.
1161
*
1162
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1163
*
1164
* @exception KTX_FILE_OPEN_FAILED The file could not be opened.
1165
* @exception KTX_INVALID_VALUE @p filename is @c NULL.
1166
*
1167
* For other exceptions, see ktxTexture_constructFromStream().
1168
*/
1169
static KTX_error_code
1170
ktxTexture2_constructFromNamedFile(ktxTexture2* This,
1171
const char* const filename,
1172
ktxTextureCreateFlags createFlags)
1173
{
1174
KTX_error_code result;
1175
ktxStream stream;
1176
FILE* file;
1177
1178
if (This == NULL || filename == NULL)
1179
return KTX_INVALID_VALUE;
1180
1181
file = ktxFOpenUTF8(filename, "rb");
1182
if (!file)
1183
return KTX_FILE_OPEN_FAILED;
1184
1185
result = ktxFileStream_construct(&stream, file, KTX_TRUE);
1186
if (result == KTX_SUCCESS)
1187
result = ktxTexture2_constructFromStream(This, &stream, createFlags);
1188
1189
return result;
1190
}
1191
1192
/**
1193
* @memberof ktxTexture2 @private
1194
* @~English
1195
* @brief Construct a ktxTexture from KTX-formatted data in memory.
1196
*
1197
* See ktxTextureInt_constructFromStream for details.
1198
*
1199
* @param[in] This pointer to a ktxTextureInt-sized block of memory to
1200
* initialize.
1201
* @param[in] bytes pointer to the memory containing the serialized KTX data.
1202
* @param[in] size length of the KTX data in bytes.
1203
* @param[in] createFlags bitmask requesting specific actions during creation.
1204
*
1205
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1206
*
1207
* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
1208
*
1209
* For other exceptions, see ktxTexture_constructFromStream().
1210
*/
1211
static KTX_error_code
1212
ktxTexture2_constructFromMemory(ktxTexture2* This,
1213
const ktx_uint8_t* bytes, ktx_size_t size,
1214
ktxTextureCreateFlags createFlags)
1215
{
1216
KTX_error_code result;
1217
ktxStream stream;
1218
1219
if (bytes == NULL || size == 0)
1220
return KTX_INVALID_VALUE;
1221
1222
result = ktxMemStream_construct_ro(&stream, bytes, size);
1223
if (result == KTX_SUCCESS)
1224
result = ktxTexture2_constructFromStream(This, &stream, createFlags);
1225
1226
return result;
1227
}
1228
1229
/**
1230
* @memberof ktxTexture2 @private
1231
* @~English
1232
* @brief Destruct a ktxTexture2, freeing and internal memory.
1233
*
1234
* @param[in] This pointer to a ktxTexture2-sized block of memory to
1235
* initialize.
1236
*/
1237
void
1238
ktxTexture2_destruct(ktxTexture2* This)
1239
{
1240
if (This->pDfd) free(This->pDfd);
1241
if (This->_private) {
1242
ktx_uint8_t* sgd = This->_private->_supercompressionGlobalData;
1243
if (sgd) free(sgd);
1244
free(This->_private);
1245
}
1246
ktxTexture_destruct(ktxTexture(This));
1247
}
1248
1249
/*
1250
* In hindsight this function should have been `#if KTX_FEATURE_WRITE`.
1251
* In the interest of not breaking an app that may be using this in
1252
* `libktx_read` we won't change it.
1253
*/
1254
/**
1255
* @memberof ktxTexture2
1256
* @ingroup writer
1257
* @~English
1258
* @brief Create a new empty ktxTexture2.
1259
*
1260
* The address of the newly created ktxTexture2 is written to the location
1261
* pointed at by @p newTex.
1262
*
1263
* @param[in] createInfo pointer to a ktxTextureCreateInfo struct with
1264
* information describing the texture.
1265
* @param[in] storageAllocation
1266
* enum indicating whether or not to allocate storage
1267
* for the texture images.
1268
* @param[in,out] newTex pointer to a location in which store the address of
1269
* the newly created texture.
1270
*
1271
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1272
*
1273
* @exception KTX_INVALID_VALUE @c glInternalFormat in @p createInfo is not a
1274
* valid OpenGL internal format value.
1275
* @exception KTX_INVALID_VALUE @c numDimensions in @p createInfo is not 1, 2
1276
* or 3.
1277
* @exception KTX_INVALID_VALUE One of <tt>base{Width,Height,Depth}</tt> in
1278
* @p createInfo is 0.
1279
* @exception KTX_INVALID_VALUE @c numFaces in @p createInfo is not 1 or 6.
1280
* @exception KTX_INVALID_VALUE @c numLevels in @p createInfo is 0.
1281
* @exception KTX_INVALID_OPERATION
1282
* The <tt>base{Width,Height,Depth}</tt> specified
1283
* in @p createInfo are inconsistent with
1284
* @c numDimensions.
1285
* @exception KTX_INVALID_OPERATION
1286
* @p createInfo is requesting a 3D array or
1287
* 3D cubemap texture.
1288
* @exception KTX_INVALID_OPERATION
1289
* @p createInfo is requesting a cubemap with
1290
* non-square or non-2D images.
1291
* @exception KTX_INVALID_OPERATION
1292
* @p createInfo is requesting more mip levels
1293
* than needed for the specified
1294
* <tt>base{Width,Height,Depth}</tt>.
1295
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture's images.
1296
*/
1297
KTX_error_code
1298
ktxTexture2_Create(const ktxTextureCreateInfo* const createInfo,
1299
ktxTextureCreateStorageEnum storageAllocation,
1300
ktxTexture2** newTex)
1301
{
1302
KTX_error_code result;
1303
1304
if (newTex == NULL)
1305
return KTX_INVALID_VALUE;
1306
1307
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1308
if (tex == NULL)
1309
return KTX_OUT_OF_MEMORY;
1310
1311
result = ktxTexture2_construct(tex, createInfo, storageAllocation);
1312
if (result != KTX_SUCCESS) {
1313
free(tex);
1314
} else {
1315
*newTex = tex;
1316
}
1317
return result;
1318
}
1319
1320
/**
1321
* @memberof ktxTexture2
1322
* @ingroup writer
1323
* @~English
1324
* @brief Create a ktxTexture2 by making a copy of a ktxTexture2.
1325
*
1326
* The address of the newly created ktxTexture2 is written to the location
1327
* pointed at by @p newTex.
1328
*
1329
* @param[in] orig pointer to the texture to copy.
1330
* @param[in,out] newTex pointer to a location in which store the address of
1331
* the newly created texture.
1332
*
1333
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1334
*
1335
* @exception KTX_OUT_OF_MEMORY Not enough memory for the texture data.
1336
*/
1337
KTX_error_code
1338
ktxTexture2_CreateCopy(ktxTexture2* orig, ktxTexture2** newTex)
1339
{
1340
KTX_error_code result;
1341
1342
if (newTex == NULL)
1343
return KTX_INVALID_VALUE;
1344
1345
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1346
if (tex == NULL)
1347
return KTX_OUT_OF_MEMORY;
1348
1349
result = ktxTexture2_constructCopy(tex, orig);
1350
if (result != KTX_SUCCESS) {
1351
free(tex);
1352
} else {
1353
*newTex = tex;
1354
}
1355
return result;
1356
1357
}
1358
1359
/**
1360
* @defgroup reader Reader
1361
* @brief Read KTX-formatted data.
1362
* @{
1363
*/
1364
1365
/**
1366
* @memberof ktxTexture2
1367
* @~English
1368
* @brief Create a ktxTexture2 from a stdio stream reading from a KTX source.
1369
*
1370
* The address of a newly created ktxTexture2 reflecting the contents of the
1371
* stdio stream is written to the location pointed at by @p newTex.
1372
*
1373
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
1374
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
1375
* will minimize memory usage by allowing, for example, loading the images
1376
* directly from the source into a Vulkan staging buffer.
1377
*
1378
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
1379
* provided solely to enable implementation of the @e libktx v1 API on top of
1380
* ktxTexture.
1381
*
1382
* @param[in] stdioStream stdio FILE pointer created from the desired file.
1383
* @param[in] createFlags bitmask requesting specific actions during creation.
1384
* @param[in,out] newTex pointer to a location in which store the address of
1385
* the newly created texture.
1386
*
1387
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1388
*
1389
* @exception KTX_INVALID_VALUE @p newTex is @c NULL.
1390
* @exception KTX_FILE_DATA_ERROR
1391
* Source data is inconsistent with the KTX
1392
* specification.
1393
* @exception KTX_FILE_READ_ERROR
1394
* An error occurred while reading the source.
1395
* @exception KTX_FILE_UNEXPECTED_EOF
1396
* Not enough data in the source.
1397
* @exception KTX_OUT_OF_MEMORY Not enough memory to create the texture object,
1398
* load the images or load the key-value data.
1399
* @exception KTX_UNKNOWN_FILE_FORMAT
1400
* The source is not in KTX format.
1401
* @exception KTX_UNSUPPORTED_TEXTURE_TYPE
1402
* The source describes a texture type not
1403
* supported by OpenGL or Vulkan, e.g, a 3D array.
1404
*/
1405
KTX_error_code
1406
ktxTexture2_CreateFromStdioStream(FILE* stdioStream,
1407
ktxTextureCreateFlags createFlags,
1408
ktxTexture2** newTex)
1409
{
1410
KTX_error_code result;
1411
if (newTex == NULL)
1412
return KTX_INVALID_VALUE;
1413
1414
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1415
if (tex == NULL)
1416
return KTX_OUT_OF_MEMORY;
1417
1418
result = ktxTexture2_constructFromStdioStream(tex, stdioStream,
1419
createFlags);
1420
if (result == KTX_SUCCESS)
1421
*newTex = (ktxTexture2*)tex;
1422
else {
1423
free(tex);
1424
*newTex = NULL;
1425
}
1426
return result;
1427
}
1428
1429
/**
1430
* @memberof ktxTexture2
1431
* @~English
1432
* @brief Create a ktxTexture2 from a named KTX file.
1433
*
1434
* The address of a newly created ktxTexture2 reflecting the contents of the
1435
* file is written to the location pointed at by @p newTex.
1436
*
1437
* The file name must be encoded in utf-8. On Windows convert unicode names
1438
* to utf-8 with @c WideCharToMultiByte(CP_UTF8, ...) before calling.
1439
*
1440
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
1441
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
1442
* will minimize memory usage by allowing, for example, loading the images
1443
* directly from the source into a Vulkan staging buffer.
1444
*
1445
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
1446
* provided solely to enable implementation of the @e libktx v1 API on top of
1447
* ktxTexture.
1448
*
1449
* @param[in] filename pointer to a char array containing the file name.
1450
* @param[in] createFlags bitmask requesting specific actions during creation.
1451
* @param[in,out] newTex pointer to a location in which store the address of
1452
* the newly created texture.
1453
*
1454
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1455
1456
* @exception KTX_FILE_OPEN_FAILED The file could not be opened.
1457
* @exception KTX_INVALID_VALUE @p filename is @c NULL.
1458
*
1459
* For other exceptions, see ktxTexture2_CreateFromStdioStream().
1460
*/
1461
KTX_error_code
1462
ktxTexture2_CreateFromNamedFile(const char* const filename,
1463
ktxTextureCreateFlags createFlags,
1464
ktxTexture2** newTex)
1465
{
1466
KTX_error_code result;
1467
1468
if (newTex == NULL)
1469
return KTX_INVALID_VALUE;
1470
1471
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1472
if (tex == NULL)
1473
return KTX_OUT_OF_MEMORY;
1474
1475
result = ktxTexture2_constructFromNamedFile(tex, filename, createFlags);
1476
if (result == KTX_SUCCESS)
1477
*newTex = (ktxTexture2*)tex;
1478
else {
1479
free(tex);
1480
*newTex = NULL;
1481
}
1482
return result;
1483
}
1484
1485
/**
1486
* @memberof ktxTexture2
1487
* @~English
1488
* @brief Create a ktxTexture2 from KTX-formatted data in memory.
1489
*
1490
* The address of a newly created ktxTexture2 reflecting the contents of the
1491
* serialized KTX data is written to the location pointed at by @p newTex.
1492
*
1493
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
1494
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
1495
* will minimize memory usage by allowing, for example, loading the images
1496
* directly from the source into a Vulkan staging buffer.
1497
*
1498
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
1499
* provided solely to enable implementation of the @e libktx v1 API on top of
1500
* ktxTexture.
1501
*
1502
* @param[in] bytes pointer to the memory containing the serialized KTX data.
1503
* @param[in] size length of the KTX data in bytes.
1504
* @param[in] createFlags bitmask requesting specific actions during creation.
1505
* @param[in,out] newTex pointer to a location in which store the address of
1506
* the newly created texture.
1507
*
1508
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1509
*
1510
* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
1511
*
1512
* For other exceptions, see ktxTexture2_CreateFromStdioStream().
1513
*/
1514
KTX_error_code
1515
ktxTexture2_CreateFromMemory(const ktx_uint8_t* bytes, ktx_size_t size,
1516
ktxTextureCreateFlags createFlags,
1517
ktxTexture2** newTex)
1518
{
1519
KTX_error_code result;
1520
if (newTex == NULL)
1521
return KTX_INVALID_VALUE;
1522
1523
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1524
if (tex == NULL)
1525
return KTX_OUT_OF_MEMORY;
1526
1527
result = ktxTexture2_constructFromMemory(tex, bytes, size,
1528
createFlags);
1529
if (result == KTX_SUCCESS)
1530
*newTex = (ktxTexture2*)tex;
1531
else {
1532
free(tex);
1533
*newTex = NULL;
1534
}
1535
return result;
1536
}
1537
1538
/**
1539
* @memberof ktxTexture2
1540
* @~English
1541
* @brief Create a ktxTexture2 from KTX-formatted data from a stream.
1542
*
1543
* The address of a newly created ktxTexture2 reflecting the contents of the
1544
* serialized KTX data is written to the location pointed at by @p newTex.
1545
*
1546
* The create flag KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT should not be set,
1547
* if the ktxTexture is ultimately to be uploaded to OpenGL or Vulkan. This
1548
* will minimize memory usage by allowing, for example, loading the images
1549
* directly from the source into a Vulkan staging buffer.
1550
*
1551
* The create flag KTX_TEXTURE_CREATE_RAW_KVDATA_BIT should not be used. It is
1552
* provided solely to enable implementation of the @e libktx v1 API on top of
1553
* ktxTexture.
1554
*
1555
* @param[in] stream pointer to the stream to read KTX data from.
1556
* @param[in] createFlags bitmask requesting specific actions during creation.
1557
* @param[in,out] newTex pointer to a location in which store the address of
1558
* the newly created texture.
1559
*
1560
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1561
*
1562
* @exception KTX_INVALID_VALUE Either @p bytes is NULL or @p size is 0.
1563
*
1564
* For other exceptions, see ktxTexture2_CreateFromStdioStream().
1565
*/
1566
KTX_error_code
1567
ktxTexture2_CreateFromStream(ktxStream* stream,
1568
ktxTextureCreateFlags createFlags,
1569
ktxTexture2** newTex)
1570
{
1571
KTX_error_code result;
1572
if (newTex == NULL)
1573
return KTX_INVALID_VALUE;
1574
1575
ktxTexture2* tex = (ktxTexture2*)malloc(sizeof(ktxTexture2));
1576
if (tex == NULL)
1577
return KTX_OUT_OF_MEMORY;
1578
1579
result = ktxTexture2_constructFromStream(tex, stream, createFlags);
1580
if (result == KTX_SUCCESS)
1581
*newTex = (ktxTexture2*)tex;
1582
else {
1583
free(tex);
1584
*newTex = NULL;
1585
}
1586
return result;
1587
}
1588
1589
/**
1590
* @memberof ktxTexture2
1591
* @~English
1592
* @brief Destroy a ktxTexture2 object.
1593
*
1594
* This frees the memory associated with the texture contents and the memory
1595
* of the ktxTexture2 object. This does @e not delete any OpenGL or Vulkan
1596
* texture objects created by ktxTexture2_GLUpload or ktxTexture2_VkUpload.
1597
*
1598
* @param[in] This pointer to the ktxTexture2 object to destroy
1599
*/
1600
void
1601
ktxTexture2_Destroy(ktxTexture2* This)
1602
{
1603
ktxTexture2_destruct(This);
1604
free(This);
1605
}
1606
1607
/**
1608
* @memberof ktxTexture2 @private
1609
* @~English
1610
* @brief Calculate the size of the image data for the specified number
1611
* of levels.
1612
*
1613
* The data size is the sum of the sizes of each level up to the number
1614
* specified and includes any @c mipPadding between levels. It does
1615
* not include initial @c mipPadding required in the file.
1616
*
1617
* @param[in] This pointer to the ktxTexture object of interest.
1618
* @param[in] levels number of levels whose data size to return.
1619
*
1620
* @return the data size in bytes.
1621
*/
1622
ktx_size_t
1623
ktxTexture2_calcDataSizeLevels(ktxTexture2* This, ktx_uint32_t levels)
1624
{
1625
ktx_size_t dataSize = 0;
1626
1627
assert(This != NULL);
1628
assert(This->supercompressionScheme == KTX_SS_NONE);
1629
assert(levels <= This->numLevels);
1630
for (ktx_uint32_t i = levels - 1; i > 0; i--) {
1631
ktx_size_t levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i,
1632
KTX_FORMAT_VERSION_TWO);
1633
dataSize += _KTX_PADN(This->_private->_requiredLevelAlignment,
1634
levelSize);
1635
}
1636
dataSize += ktxTexture_calcLevelSize(ktxTexture(This), 0,
1637
KTX_FORMAT_VERSION_TWO);
1638
return dataSize;
1639
}
1640
1641
/**
1642
* @memberof ktxTexture2 @private
1643
* @~English
1644
*
1645
* @copydoc ktxTexture::ktxTexture_doCalcFaceLodSize
1646
*/
1647
ktx_size_t
1648
ktxTexture2_calcFaceLodSize(ktxTexture2* This, ktx_uint32_t level)
1649
{
1650
assert(This != NULL);
1651
assert(This->supercompressionScheme == KTX_SS_NONE);
1652
/*
1653
* For non-array cubemaps this is the size of a face. For everything
1654
* else it is the size of the level.
1655
*/
1656
if (This->isCubemap && !This->isArray)
1657
return ktxTexture_calcImageSize(ktxTexture(This), level,
1658
KTX_FORMAT_VERSION_TWO);
1659
else
1660
return This->_private->_levelIndex[level].uncompressedByteLength;
1661
}
1662
1663
/**
1664
* @memberof ktxTexture2 @private
1665
* @~English
1666
* @brief Return the offset of a level in bytes from the start of the image
1667
* data in a ktxTexture.
1668
*
1669
* Since the offset is from the start of the image data, it does not include the initial
1670
* @c mipPadding required in the file.
1671
*
1672
* @param[in] This pointer to the ktxTexture object of interest.
1673
* @param[in] level level whose offset to return.
1674
*
1675
* @return the data size in bytes.
1676
*/
1677
ktx_size_t
1678
ktxTexture2_calcLevelOffset(ktxTexture2* This, ktx_uint32_t level)
1679
{
1680
assert (This != NULL);
1681
assert(This->supercompressionScheme == KTX_SS_NONE);
1682
assert (level < This->numLevels);
1683
ktx_size_t levelOffset = 0;
1684
for (ktx_uint32_t i = This->numLevels - 1; i > level; i--) {
1685
ktx_size_t levelSize;
1686
levelSize = ktxTexture_calcLevelSize(ktxTexture(This), i,
1687
KTX_FORMAT_VERSION_TWO);
1688
levelOffset += _KTX_PADN(This->_private->_requiredLevelAlignment,
1689
levelSize);
1690
}
1691
return levelOffset;
1692
}
1693
1694
1695
/**
1696
* @memberof ktxTexture2 @private
1697
* @~English
1698
* @brief Retrieve the offset of a level's first image within the KTX2 file.
1699
*
1700
* @param[in] This pointer to the ktxTexture object of interest.
1701
*/
1702
ktx_uint64_t ktxTexture2_levelFileOffset(ktxTexture2* This, ktx_uint32_t level)
1703
{
1704
assert(This->_private->_firstLevelFileOffset != 0);
1705
return This->_private->_levelIndex[level].byteOffset
1706
+ This->_private->_firstLevelFileOffset;
1707
}
1708
1709
// Recursive function to return the greatest common divisor of a and b.
1710
static uint32_t
1711
gcd(uint32_t a, uint32_t b) {
1712
if (a == 0)
1713
return b;
1714
return gcd(b % a, a);
1715
}
1716
1717
// Function to return the least common multiple of a & 4.
1718
uint32_t
1719
lcm4(uint32_t a)
1720
{
1721
if (!(a & 0x03))
1722
return a; // a is a multiple of 4.
1723
return (a*4) / gcd(a, 4);
1724
}
1725
1726
/**
1727
* @memberof ktxTexture2 @private
1728
* @~English
1729
* @brief Return the required alignment for levels of this texture.
1730
*
1731
* @param[in] This pointer to the ktxTexture2 object of interest.
1732
*
1733
* @return The required alignment for levels.
1734
*/
1735
ktx_uint32_t
1736
ktxTexture2_calcRequiredLevelAlignment(ktxTexture2* This)
1737
{
1738
ktx_uint32_t alignment;
1739
if (This->supercompressionScheme != KTX_SS_NONE)
1740
alignment = 1;
1741
else
1742
alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8);
1743
return alignment;
1744
}
1745
1746
/**
1747
* @memberof ktxTexture2 @private
1748
* @~English
1749
* @brief Return what the required alignment for levels of this texture will be after inflation.
1750
*
1751
* @param[in] This pointer to the ktxTexture2 object of interest.
1752
*
1753
* @return The required alignment for levels.
1754
*/
1755
ktx_uint32_t
1756
ktxTexture2_calcPostInflationLevelAlignment(ktxTexture2* This)
1757
{
1758
ktx_uint32_t alignment;
1759
1760
// Should actually work for none supercompressed but don't want to
1761
// encourage use of it.
1762
assert(This->supercompressionScheme != KTX_SS_NONE && This->supercompressionScheme != KTX_SS_BASIS_LZ);
1763
1764
if (This->vkFormat != VK_FORMAT_UNDEFINED)
1765
alignment = lcm4(This->_protected->_formatSize.blockSizeInBits / 8);
1766
else
1767
alignment = 16;
1768
1769
return alignment;
1770
}
1771
1772
1773
/**
1774
* @memberof ktxTexture2
1775
* @~English
1776
* @brief Return information about the components of an image in a texture.
1777
*
1778
* @param[in] This pointer to the ktxTexture object of interest.
1779
* @param[in,out] pNumComponents pointer to location in which to write the
1780
* number of components in the textures images.
1781
* @param[in,out] pComponentByteLength
1782
* pointer to the location in which to write
1783
* byte length of a component.
1784
*/
1785
void
1786
ktxTexture2_GetComponentInfo(ktxTexture2* This, uint32_t* pNumComponents,
1787
uint32_t* pComponentByteLength)
1788
{
1789
// FIXME Need to handle packed case.
1790
getDFDComponentInfoUnpacked(This->pDfd, pNumComponents,
1791
pComponentByteLength);
1792
}
1793
1794
/**
1795
* @memberof ktxTexture2
1796
* @~English
1797
* @brief Return the number of components in an image of the texture.
1798
*
1799
* Returns the number of components indicated by the DFD's sample information
1800
* in accordance with the color model. For uncompressed formats it will be the actual
1801
* number of components in the image. For block-compressed formats, it will be 1 or 2
1802
* according to the format's DFD color model. For Basis compressed textures, the
1803
* function examines the ids of the channels indicated by the DFD and uses that
1804
* information to determine and return the number of components in the image
1805
* @e before encoding and deflation so it can be used to help choose a suitable
1806
* transcode target format.
1807
*
1808
* @param[in] This pointer to the ktxTexture object of interest.
1809
*
1810
* @return the number of components.
1811
*/
1812
ktx_uint32_t
1813
ktxTexture2_GetNumComponents(ktxTexture2* This)
1814
{
1815
uint32_t* pBdb = This->pDfd + 1;
1816
uint32_t dfdNumComponents = getDFDNumComponents(This->pDfd);
1817
uint32_t colorModel = KHR_DFDVAL(pBdb, MODEL);
1818
if (colorModel < KHR_DF_MODEL_DXT1A) {
1819
return dfdNumComponents;
1820
} else {
1821
switch (colorModel) {
1822
case KHR_DF_MODEL_ETC1S:
1823
{
1824
uint32_t channel0Id = KHR_DFDSVAL(pBdb, 0, CHANNELID);
1825
if (dfdNumComponents == 1) {
1826
if (channel0Id == KHR_DF_CHANNEL_ETC1S_RGB)
1827
return 3;
1828
else
1829
return 1;
1830
} else {
1831
uint32_t channel1Id = KHR_DFDSVAL(pBdb, 1, CHANNELID);
1832
if (channel0Id == KHR_DF_CHANNEL_ETC1S_RGB
1833
&& channel1Id == KHR_DF_CHANNEL_ETC1S_AAA)
1834
return 4;
1835
else {
1836
// An invalid combination of channel Ids should never
1837
// have been set during creation or should have been
1838
// caught when the file was loaded.
1839
assert(channel0Id == KHR_DF_CHANNEL_ETC1S_RRR
1840
&& channel1Id == KHR_DF_CHANNEL_ETC1S_GGG);
1841
return 2;
1842
}
1843
}
1844
break;
1845
}
1846
case KHR_DF_MODEL_UASTC:
1847
switch (KHR_DFDSVAL(pBdb, 0, CHANNELID)) {
1848
case KHR_DF_CHANNEL_UASTC_RRR:
1849
return 1;
1850
case KHR_DF_CHANNEL_UASTC_RRRG:
1851
return 2;
1852
case KHR_DF_CHANNEL_UASTC_RGB:
1853
return 3;
1854
case KHR_DF_CHANNEL_UASTC_RGBA:
1855
return 4;
1856
default:
1857
// Same comment as for the assert in the ETC1 case.
1858
assert(false);
1859
return 1;
1860
}
1861
break;
1862
default:
1863
return dfdNumComponents;
1864
}
1865
}
1866
}
1867
1868
/**
1869
* @memberof ktxTexture2
1870
* @~English
1871
* @brief Find the offset of an image within a ktxTexture's image data.
1872
*
1873
* As there is no such thing as a 3D cubemap we make the 3rd location parameter
1874
* do double duty. Only works for non-supercompressed textures as
1875
* there is no way to tell where an image is for a supercompressed one.
1876
*
1877
* @param[in] This pointer to the ktxTexture object of interest.
1878
* @param[in] level mip level of the image.
1879
* @param[in] layer array layer of the image.
1880
* @param[in] faceSlice cube map face or depth slice of the image.
1881
* @param[in,out] pOffset pointer to location to store the offset.
1882
*
1883
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
1884
*
1885
* @exception KTX_INVALID_OPERATION
1886
* @p level, @p layer or @p faceSlice exceed the
1887
* dimensions of the texture.
1888
* @exception KTX_INVALID_OPERATION Texture is supercompressed.
1889
* @exception KTX_INVALID_VALID @p This is NULL.
1890
*/
1891
KTX_error_code
1892
ktxTexture2_GetImageOffset(ktxTexture2* This, ktx_uint32_t level,
1893
ktx_uint32_t layer, ktx_uint32_t faceSlice,
1894
ktx_size_t* pOffset)
1895
{
1896
if (This == NULL)
1897
return KTX_INVALID_VALUE;
1898
1899
if (level >= This->numLevels || layer >= This->numLayers)
1900
return KTX_INVALID_OPERATION;
1901
1902
if (This->supercompressionScheme != KTX_SS_NONE)
1903
return KTX_INVALID_OPERATION;
1904
1905
if (This->isCubemap) {
1906
if (faceSlice >= This->numFaces)
1907
return KTX_INVALID_OPERATION;
1908
} else {
1909
ktx_uint32_t maxSlice = MAX(1, This->baseDepth >> level);
1910
if (faceSlice >= maxSlice)
1911
return KTX_INVALID_OPERATION;
1912
}
1913
1914
// Get the offset of the start of the level.
1915
*pOffset = ktxTexture2_levelDataOffset(This, level);
1916
1917
// All layers, faces & slices within a level are the same size.
1918
if (layer != 0) {
1919
ktx_size_t layerSize;
1920
layerSize = ktxTexture_layerSize(ktxTexture(This), level,
1921
KTX_FORMAT_VERSION_TWO);
1922
*pOffset += layer * layerSize;
1923
}
1924
if (faceSlice != 0) {
1925
ktx_size_t imageSize;
1926
imageSize = ktxTexture2_GetImageSize(This, level);
1927
*pOffset += faceSlice * imageSize;
1928
}
1929
return KTX_SUCCESS;
1930
}
1931
1932
/**
1933
* @memberof ktxTexture2
1934
* @~English
1935
* @brief Retrieve the transfer function of the images.
1936
*
1937
* @param[in] This pointer to the ktxTexture2 object of interest.
1938
*
1939
* @return A @c khr_df_transfer enum value specifying the transfer function.
1940
*/
1941
khr_df_transfer_e
1942
ktxTexture2_GetTransferFunction_e(ktxTexture2* This)
1943
{
1944
return KHR_DFDVAL(This->pDfd+1, TRANSFER);
1945
}
1946
1947
/**
1948
* @memberof ktxTexture2
1949
* @~English
1950
* @brief Retrieve the transfer function of the images.
1951
* @deprecated Use ktxTexture2\_GetTransferFunction\_e. Now that the KTX
1952
* specification allows setting of non-linear transfer functions other than
1953
* sRGB, it is possible for the transfer function to be an EOTF so this
1954
* name is no longer appropriate.
1955
*
1956
* @param[in] This pointer to the ktxTexture2 object of interest.
1957
*
1958
* @return A @c khr_df_transfer enum value specifying the transfer function.
1959
*/
1960
khr_df_transfer_e
1961
ktxTexture2_GetOETF_e(ktxTexture2* This)
1962
{
1963
return KHR_DFDVAL(This->pDfd+1, TRANSFER);
1964
}
1965
1966
/**
1967
* @memberof ktxTexture2
1968
* @~English
1969
* @brief Retrieve the transfer function of the images.
1970
* @deprecated Use ktxTexture2\_GetTransferFunction\_e.
1971
*
1972
* @param[in] This pointer to the ktxTexture2 object of interest.
1973
*
1974
* @return A @c khr_df_transfer enum value specifying the transfer function,
1975
* returned as @c ktx_uint32_t.
1976
*/
1977
ktx_uint32_t
1978
ktxTexture2_GetOETF(ktxTexture2* This)
1979
{
1980
return KHR_DFDVAL(This->pDfd+1, TRANSFER);
1981
}
1982
1983
/**
1984
* @memberof ktxTexture2
1985
* @~English
1986
* @brief Retrieve the DFD color model of the images.
1987
*
1988
* @param[in] This pointer to the ktxTexture2 object of interest.
1989
*
1990
* @return A @c khr_df_transfer enum value specifying the color model.
1991
*/
1992
khr_df_model_e
1993
ktxTexture2_GetColorModel_e(ktxTexture2* This)
1994
{
1995
return KHR_DFDVAL(This->pDfd+1, MODEL);
1996
}
1997
1998
/**
1999
* @memberof ktxTexture2
2000
* @~English
2001
* @brief Retrieve whether the RGB components have been premultiplied by the alpha component.
2002
*
2003
* @param[in] This pointer to the ktxTexture2 object of interest.
2004
*
2005
* @return KTX\_TRUE if the components are premultiplied, KTX_FALSE otherwise.
2006
*/
2007
ktx_bool_t
2008
ktxTexture2_GetPremultipliedAlpha(ktxTexture2* This)
2009
{
2010
return KHR_DFDVAL(This->pDfd+1, FLAGS) & KHR_DF_FLAG_ALPHA_PREMULTIPLIED;
2011
}
2012
2013
/**
2014
* @memberof ktxTexture2
2015
* @~English
2016
* @brief Retrieve the color primaries of the images.
2017
*
2018
* @param[in] This pointer to the ktxTexture2 object of interest.
2019
*
2020
* @return A @c khr_df_primaries enum value specifying the primaries.
2021
*/
2022
khr_df_primaries_e
2023
ktxTexture2_GetPrimaries_e(ktxTexture2* This)
2024
{
2025
return KHR_DFDVAL(This->pDfd+1, PRIMARIES);
2026
}
2027
2028
/**
2029
* @memberof ktxTexture2
2030
* @~English
2031
* @brief Query if the images are in a transcodable format.
2032
*
2033
* @param[in] This pointer to the ktxTexture2 object of interest.
2034
*/
2035
ktx_bool_t
2036
ktxTexture2_NeedsTranscoding(ktxTexture2* This)
2037
{
2038
if (KHR_DFDVAL(This->pDfd + 1, MODEL) == KHR_DF_MODEL_ETC1S)
2039
return true;
2040
else if (KHR_DFDVAL(This->pDfd + 1, MODEL) == KHR_DF_MODEL_UASTC)
2041
return true;
2042
else
2043
return false;
2044
}
2045
2046
#if KTX_FEATURE_WRITE
2047
/*
2048
* @memberof ktxTexture2
2049
* @ingroup writer
2050
* @~English
2051
* @brief Set the transfer function for the images in a texture.
2052
*
2053
* @param[in] This pointer to the ktxTexture2
2054
* @param[in] tf enumerator of the transfer function to set
2055
*
2056
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
2057
*
2058
* @exception KTX_INVALID_OPERATION The transfer function is not valid for the
2059
* vkFormat of the texture.
2060
* @exception KTX_INVALID_VALUE The transfer function is not allowed by the
2061
* KTX spec.
2062
*/
2063
ktx_error_code_e
2064
ktxTexture2_SetTransferFunction(ktxTexture2* This, khr_df_transfer_e tf)
2065
{
2066
if (isSrgbFormat(This->vkFormat) && tf != KHR_DF_TRANSFER_SRGB)
2067
return KTX_INVALID_OPERATION;
2068
2069
if (isNotSrgbFormatButHasSrgbVariant(This->vkFormat) && tf == KHR_DF_TRANSFER_SRGB)
2070
return KTX_INVALID_OPERATION;
2071
2072
KHR_DFDSETVAL(This->pDfd + 1, TRANSFER, tf);
2073
return KTX_SUCCESS;
2074
}
2075
2076
/**
2077
* @memberof ktxTexture2
2078
* @ingroup writer
2079
* @~English
2080
* @brief Set the transfer function for the images in a texture.
2081
* @deprecated Use ktxTexture2\_SetTransferFunction.
2082
*
2083
* @param[in] This pointer to the ktxTexture2
2084
* @param[in] tf enumerator of the transfer function to set
2085
*/
2086
ktx_error_code_e
2087
ktxTexture2_SetOETF(ktxTexture2* This, khr_df_transfer_e tf)
2088
{
2089
return ktxTexture2_SetTransferFunction(This, tf);
2090
}
2091
2092
/**
2093
* @memberof ktxTexture2
2094
* @ingroup writer
2095
* @~English
2096
* @brief Set the primaries for the images in a texture.
2097
*
2098
* @param[in] This pointer to the ktxTexture2
2099
* @param[in] primaries enumerator of the primaries to set
2100
*/
2101
ktx_error_code_e
2102
ktxTexture2_SetPrimaries(ktxTexture2* This, khr_df_primaries_e primaries)
2103
{
2104
KHR_DFDSETVAL(This->pDfd + 1, PRIMARIES, primaries);
2105
return KTX_SUCCESS;
2106
}
2107
#endif
2108
2109
/**
2110
* @memberof ktxTexture2
2111
* @~English
2112
* @brief Return the total size in bytes of the uncompressed data of a
2113
* ktxTexture2.
2114
*
2115
* If supercompressionScheme == @c KTX_SS_NONE or
2116
* @c KTX_SS_BASIS_LZ, returns the value of @c This->dataSize
2117
* else if supercompressionScheme == @c KTX_SS_ZSTD or @c KTX_SS_ZLIB, it
2118
* returns the sum of the uncompressed sizes of each mip level plus space for
2119
* the level padding. With no supercompression the data size and uncompressed
2120
* data size are the same. For Basis supercompression the uncompressed size
2121
* cannot be known until the data is transcoded so the compressed size is
2122
* returned.
2123
*
2124
* @param[in] This pointer to the ktxTexture1 object of interest.
2125
*/
2126
ktx_size_t
2127
ktxTexture2_GetDataSizeUncompressed(ktxTexture2* This)
2128
{
2129
switch (This->supercompressionScheme) {
2130
case KTX_SS_BASIS_LZ:
2131
case KTX_SS_NONE:
2132
return This->dataSize;
2133
case KTX_SS_ZSTD:
2134
case KTX_SS_ZLIB:
2135
{
2136
ktx_size_t uncompressedSize = 0;
2137
ktx_uint32_t uncompressedLevelAlignment;
2138
ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex;
2139
2140
uncompressedLevelAlignment =
2141
ktxTexture2_calcPostInflationLevelAlignment(This);
2142
2143
for (ktx_int32_t level = This->numLevels - 1; level >= 1; level--) {
2144
ktx_size_t uncompressedLevelSize;
2145
uncompressedLevelSize = levelIndex[level].uncompressedByteLength;
2146
uncompressedLevelSize = _KTX_PADN(uncompressedLevelAlignment,
2147
uncompressedLevelSize);
2148
uncompressedSize += uncompressedLevelSize;
2149
}
2150
uncompressedSize += levelIndex[0].uncompressedByteLength;
2151
return uncompressedSize;
2152
}
2153
case KTX_SS_BEGIN_VENDOR_RANGE:
2154
case KTX_SS_END_VENDOR_RANGE:
2155
case KTX_SS_BEGIN_RESERVED:
2156
default:
2157
return 0;
2158
}
2159
}
2160
2161
/**
2162
* @memberof ktxTexture2
2163
* @~English
2164
* @brief Calculate & return the size in bytes of an image at the specified
2165
* mip level.
2166
*
2167
* For arrays, this is the size of a layer, for cubemaps, the size of a face
2168
* and for 3D textures, the size of a depth slice.
2169
*
2170
* The size reflects the padding of each row to KTX_GL_UNPACK_ALIGNMENT.
2171
*
2172
* @param[in] This pointer to the ktxTexture2 object of interest.
2173
* @param[in] level level of interest. *
2174
*/
2175
ktx_size_t
2176
ktxTexture2_GetImageSize(ktxTexture2* This, ktx_uint32_t level)
2177
{
2178
return ktxTexture_calcImageSize(ktxTexture(This), level,
2179
KTX_FORMAT_VERSION_TWO);
2180
}
2181
2182
/**
2183
* @memberof ktxTexture2
2184
* @~English
2185
* @brief Calculate & return the size in bytes of all the images in the specified
2186
* mip level.
2187
*
2188
* For arrays, this is the size of all layers in the level, for cubemaps, the size of all
2189
* faces in the level and for 3D textures, the size of all depth slices in the level.
2190
*
2191
* @param[in] This pointer to the ktxTexture2 object of interest.
2192
* @param[in] level level of interest. *
2193
*/
2194
ktx_size_t
2195
ktxTexture2_GetLevelSize(ktxTexture2* This, ktx_uint32_t level)
2196
{
2197
return ktxTexture_calcLevelSize(ktxTexture(This), level,
2198
KTX_FORMAT_VERSION_TWO);
2199
}
2200
2201
/**
2202
* @memberof ktxTexture2
2203
* @~English
2204
* @brief Iterate over the mip levels in a ktxTexture2 object.
2205
*
2206
* This is almost identical to ktxTexture_IterateLevelFaces(). The difference is
2207
* that the blocks of image data for non-array cube maps include all faces of
2208
* a mip level.
2209
*
2210
* This function works even if @p This->pData == 0 so it can be used to
2211
* obtain offsets and sizes for each level by callers who have loaded the data
2212
* externally.
2213
*
2214
* Intended for use only when supercompressionScheme == SUPERCOMPRESSION_NONE.
2215
*
2216
* @param[in] This handle of the ktxTexture opened on the data.
2217
* @param[in,out] iterCb the address of a callback function which is called
2218
* with the data for each image block.
2219
* @param[in,out] userdata the address of application-specific data which is
2220
* passed to the callback along with the image data.
2221
*
2222
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
2223
* following are returned directly by this function. @p iterCb may
2224
* return these for other causes or may return additional errors.
2225
*
2226
* @exception KTX_FILE_DATA_ERROR Mip level sizes are increasing not
2227
* decreasing
2228
* @exception KTX_INVALID_OPERATION supercompressionScheme != SUPERCOMPRESSION_NONE.
2229
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
2230
*
2231
*/
2232
KTX_error_code
2233
ktxTexture2_IterateLevels(ktxTexture2* This, PFNKTXITERCB iterCb, void* userdata)
2234
{
2235
KTX_error_code result = KTX_SUCCESS;
2236
//ZSTD_DCtx* dctx;
2237
//ktx_uint8_t* decompBuf;
2238
ktxLevelIndexEntry* levelIndex = This->_private->_levelIndex;
2239
2240
if (This == NULL)
2241
return KTX_INVALID_VALUE;
2242
2243
if (iterCb == NULL)
2244
return KTX_INVALID_VALUE;
2245
2246
if (This->supercompressionScheme != KTX_SS_NONE)
2247
return KTX_INVALID_OPERATION;
2248
2249
for (ktx_int32_t level = This->numLevels - 1; level >= 0; level--)
2250
{
2251
ktx_uint32_t width, height, depth;
2252
ktx_uint64_t levelSize;
2253
ktx_uint64_t offset;
2254
2255
/* Array textures have the same number of layers at each mip level. */
2256
width = MAX(1, This->baseWidth >> level);
2257
height = MAX(1, This->baseHeight >> level);
2258
depth = MAX(1, This->baseDepth >> level);
2259
2260
levelSize = levelIndex[level].uncompressedByteLength;
2261
offset = ktxTexture2_levelDataOffset(This, level);
2262
2263
/* All array layers are passed in a group because that is how
2264
* GL & Vulkan need them. Hence no
2265
* for (layer = 0; layer < This->numLayers)
2266
*/
2267
result = iterCb(level, 0, width, height, depth,
2268
levelSize, This->pData + offset, userdata);
2269
if (result != KTX_SUCCESS)
2270
break;
2271
}
2272
2273
return result;
2274
}
2275
2276
/**
2277
* @memberof ktxTexture2
2278
* @~English
2279
* @brief Iterate over the images in a ktxTexture2 object while loading the
2280
* image data.
2281
*
2282
* This operates similarly to ktxTexture_IterateLevelFaces() except that it
2283
* loads the images from the ktxTexture2's source to a temporary buffer
2284
* while iterating. If supercompressionScheme == KTX_SS_ZSTD or KTX_SS_ZLIB,
2285
* it will inflate the data before passing it to the callback. The callback function
2286
* must copy the image data if it wishes to preserve it as the temporary buffer
2287
* is reused for each level and is freed when this function exits.
2288
*
2289
* This function is helpful for reducing memory usage when uploading the data
2290
* to a graphics API.
2291
*
2292
* Intended for use only when supercompressionScheme == KTX_SS_NONE,
2293
* KTX_SS_ZSTD or KTX_SS_ZLIB. As there is no access to the ktxTexture's data on
2294
* conclusion of this function, destroying the texture on completion is recommended.
2295
*
2296
* @param[in] This pointer to the ktxTexture2 object of interest.
2297
* @param[in,out] iterCb the address of a callback function which is called
2298
* with the data for each image.
2299
* @param[in,out] userdata the address of application-specific data which is
2300
* passed to the callback along with the image data.
2301
*
2302
* @return KTX_SUCCESS on success, other KTX_* enum values on error. The
2303
* following are returned directly by this function. @p iterCb may
2304
* return these for other causes or may return additional errors.
2305
*
2306
* @exception KTX_FILE_DATA_ERROR mip level sizes are increasing not
2307
* decreasing
2308
* @exception KTX_INVALID_OPERATION the ktxTexture2 was not created from a
2309
* stream, i.e there is no data to load, or
2310
* this ktxTexture2's images have already
2311
* been loaded.
2312
* @exception KTX_INVALID_OPERATION
2313
* supercompressionScheme != KTX_SS_NONE,
2314
* supercompressionScheme != KTX_SS_ZSTD, and
2315
* supercompressionScheme != KTX_SS_ZLIB.
2316
* @exception KTX_INVALID_VALUE @p This is @c NULL or @p iterCb is @c NULL.
2317
* @exception KTX_OUT_OF_MEMORY not enough memory to allocate a block to
2318
* hold the base level image.
2319
*/
2320
KTX_error_code
2321
ktxTexture2_IterateLoadLevelFaces(ktxTexture2* This, PFNKTXITERCB iterCb,
2322
void* userdata)
2323
{
2324
DECLARE_PROTECTED(ktxTexture);
2325
ktxStream* stream = (ktxStream *)&prtctd->_stream;
2326
ktxLevelIndexEntry* levelIndex;
2327
ktx_size_t dataSize = 0, uncompressedDataSize = 0;
2328
KTX_error_code result = KTX_SUCCESS;
2329
ktx_uint8_t* dataBuf = NULL;
2330
ktx_uint8_t* uncompressedDataBuf = NULL;
2331
ktx_uint8_t* pData;
2332
ZSTD_DCtx* dctx = NULL;
2333
2334
if (This == NULL)
2335
return KTX_INVALID_VALUE;
2336
2337
if (This->classId != ktxTexture2_c)
2338
return KTX_INVALID_OPERATION;
2339
2340
if (This->supercompressionScheme != KTX_SS_NONE &&
2341
This->supercompressionScheme != KTX_SS_ZSTD &&
2342
This->supercompressionScheme != KTX_SS_ZLIB)
2343
return KTX_INVALID_OPERATION;
2344
2345
if (iterCb == NULL)
2346
return KTX_INVALID_VALUE;
2347
2348
if (prtctd->_stream.data.file == NULL)
2349
// This Texture not created from a stream or images are already loaded.
2350
return KTX_INVALID_OPERATION;
2351
2352
levelIndex = This->_private->_levelIndex;
2353
2354
// Allocate memory sufficient for the base level
2355
dataSize = levelIndex[0].byteLength;
2356
dataBuf = malloc(dataSize);
2357
if (!dataBuf)
2358
return KTX_OUT_OF_MEMORY;
2359
if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB) {
2360
uncompressedDataSize = levelIndex[0].uncompressedByteLength;
2361
uncompressedDataBuf = malloc(uncompressedDataSize);
2362
if (!uncompressedDataBuf) {
2363
result = KTX_OUT_OF_MEMORY;
2364
goto cleanup;
2365
}
2366
if (This->supercompressionScheme == KTX_SS_ZSTD) {
2367
dctx = ZSTD_createDCtx();
2368
}
2369
pData = uncompressedDataBuf;
2370
} else {
2371
pData = dataBuf;
2372
}
2373
2374
for (ktx_int32_t level = This->numLevels - 1; level >= 0; --level)
2375
{
2376
ktx_size_t levelSize;
2377
GLsizei width, height, depth;
2378
2379
// Array textures have the same number of layers at each mip level.
2380
width = MAX(1, This->baseWidth >> level);
2381
height = MAX(1, This->baseHeight >> level);
2382
depth = MAX(1, This->baseDepth >> level);
2383
2384
levelSize = levelIndex[level].byteLength;
2385
if (dataSize < levelSize) {
2386
// Levels cannot be larger than the base level
2387
result = KTX_FILE_DATA_ERROR;
2388
goto cleanup;
2389
}
2390
2391
// Use setpos so we skip any padding.
2392
result = stream->setpos(stream,
2393
ktxTexture2_levelFileOffset(This, level));
2394
if (result != KTX_SUCCESS)
2395
goto cleanup;
2396
2397
result = stream->read(stream, dataBuf, levelSize);
2398
if (result != KTX_SUCCESS)
2399
goto cleanup;
2400
2401
if (This->supercompressionScheme == KTX_SS_ZSTD) {
2402
levelSize =
2403
ZSTD_decompressDCtx(dctx, uncompressedDataBuf,
2404
uncompressedDataSize,
2405
dataBuf,
2406
levelSize);
2407
if (ZSTD_isError(levelSize)) {
2408
ZSTD_ErrorCode error = ZSTD_getErrorCode(levelSize);
2409
switch(error) {
2410
case ZSTD_error_dstSize_tooSmall:
2411
result = KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small.
2412
goto cleanup;
2413
case ZSTD_error_checksum_wrong:
2414
result = KTX_DECOMPRESS_CHECKSUM_ERROR;
2415
goto cleanup;
2416
case ZSTD_error_memory_allocation:
2417
result = KTX_OUT_OF_MEMORY;
2418
goto cleanup;
2419
default:
2420
result = KTX_FILE_DATA_ERROR;
2421
goto cleanup;
2422
}
2423
}
2424
2425
// We don't fix up the texture's dataSize, levelIndex or
2426
// _requiredAlignment because after this function completes there
2427
// is no way to get at the texture's data.
2428
//nindex[level].byteOffset = levelOffset;
2429
//nindex[level].uncompressedByteLength = nindex[level].byteLength =
2430
//levelByteLength;
2431
} else if (This->supercompressionScheme == KTX_SS_ZLIB) {
2432
result = ktxUncompressZLIBInt(uncompressedDataBuf,
2433
&uncompressedDataSize,
2434
dataBuf,
2435
levelSize);
2436
if (result != KTX_SUCCESS)
2437
return result;
2438
}
2439
2440
if (levelIndex[level].uncompressedByteLength != levelSize) {
2441
result = KTX_DECOMPRESS_LENGTH_ERROR;
2442
goto cleanup;
2443
}
2444
2445
2446
#if IS_BIG_ENDIAN
2447
switch (prtctd->_typeSize) {
2448
case 2:
2449
_ktxSwapEndian16((ktx_uint16_t*)pData, levelSize / 2);
2450
break;
2451
case 4:
2452
_ktxSwapEndian32((ktx_uint32_t*)pDest, levelSize / 4);
2453
break;
2454
case 8:
2455
_ktxSwapEndian64((ktx_uint64_t*)pDest, levelSize / 8);
2456
break;
2457
}
2458
#endif
2459
2460
// With the exception of non-array cubemaps the entire level
2461
// is passed at once because that is how OpenGL and Vulkan need them.
2462
// Vulkan could take all the faces at once too but we iterate
2463
// them separately for OpenGL.
2464
if (This->isCubemap && !This->isArray) {
2465
ktx_uint8_t* pFace = pData;
2466
struct blockCount {
2467
ktx_uint32_t x, y;
2468
} blockCount;
2469
ktx_size_t faceSize;
2470
2471
blockCount.x
2472
= (uint32_t)ceilf((float)width / prtctd->_formatSize.blockWidth);
2473
blockCount.y
2474
= (uint32_t)ceilf((float)height / prtctd->_formatSize.blockHeight);
2475
blockCount.x = MAX(prtctd->_formatSize.minBlocksX, blockCount.x);
2476
blockCount.y = MAX(prtctd->_formatSize.minBlocksX, blockCount.y);
2477
faceSize = blockCount.x * blockCount.y
2478
* prtctd->_formatSize.blockSizeInBits / 8;
2479
2480
for (ktx_uint32_t face = 0; face < This->numFaces; ++face) {
2481
result = iterCb(level, face,
2482
width, height, depth,
2483
(ktx_uint32_t)faceSize, pFace, userdata);
2484
pFace += faceSize;
2485
if (result != KTX_SUCCESS)
2486
goto cleanup;
2487
}
2488
} else {
2489
result = iterCb(level, 0,
2490
width, height, depth,
2491
(ktx_uint32_t)levelSize, pData, userdata);
2492
if (result != KTX_SUCCESS)
2493
goto cleanup;
2494
}
2495
}
2496
2497
// No further need for this.
2498
stream->destruct(stream);
2499
This->_private->_firstLevelFileOffset = 0;
2500
cleanup:
2501
free(dataBuf);
2502
if (uncompressedDataBuf) free(uncompressedDataBuf);
2503
if (dctx) ZSTD_freeDCtx(dctx);
2504
2505
return result;
2506
}
2507
2508
KTX_error_code
2509
ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData,
2510
ktx_uint8_t* pInflatedData,
2511
ktx_size_t inflatedDataCapacity);
2512
2513
KTX_error_code
2514
ktxTexture2_inflateZLIBInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData,
2515
ktx_uint8_t* pInflatedData,
2516
ktx_size_t inflatedDataCapacity);
2517
2518
typedef enum {
2519
LOADDATA_DONT_INFLATE_ON_LOAD,
2520
LOADDATA_INFLATE_ON_LOAD
2521
} ktxTexture2InflateFlagEnum;
2522
2523
/**
2524
* @memberof ktxTexture2
2525
* @internal
2526
* @~English
2527
* @brief Load all the image data from the ktxTexture2's source.
2528
*
2529
* The data will be inflated if requested and supercompressionScheme == @c KTX_SS_ZSTD
2530
* or @c KTX_SS_ZLIB.
2531
* The data is loaded into the provided buffer or to an internally allocated
2532
* buffer, if @p pBuffer is @c NULL. Callers providing their own buffer must
2533
* ensure the buffer large enough to hold the inflated data for files deflated
2534
* with Zstd or ZLIB. See ktxTexture2\_GetDataSizeUncompressed().
2535
*
2536
* The texture's levelIndex, dataSize, DFD and supercompressionScheme will
2537
* all be updated after successful inflation to reflect the inflated data.
2538
*
2539
* @param[in] This pointer to the ktxTexture object of interest.
2540
* @param[in] pBuffer pointer to the buffer in which to load the image data.
2541
* @param[in] bufSize size of the buffer pointed at by @p pBuffer.
2542
* @param[in] inflateHandling enum indicating whether or not to inflate
2543
* supercompressed data.
2544
*
2545
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
2546
*
2547
* @exception KTX_INVALID_VALUE @p This is NULL.
2548
* @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size.
2549
* @exception KTX_INVALID_OPERATION
2550
* The data has already been loaded or the
2551
* ktxTexture was not created from a KTX source.
2552
* @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data.
2553
*/
2554
ktx_error_code_e
2555
ktxTexture2_loadImageDataInt(ktxTexture2* This,
2556
ktx_uint8_t* pBuffer, ktx_size_t bufSize,
2557
ktxTexture2InflateFlagEnum inflateHandling)
2558
{
2559
DECLARE_PROTECTED(ktxTexture);
2560
DECLARE_PRIVATE(ktxTexture2);
2561
ktx_uint8_t* pDest;
2562
ktx_uint8_t* pDeflatedData = NULL;
2563
ktx_uint8_t* pReadBuf;
2564
KTX_error_code result = KTX_SUCCESS;
2565
ktx_size_t outputDataCapacity;
2566
ktx_bool_t doInflate = false;
2567
2568
if (This == NULL)
2569
return KTX_INVALID_VALUE;
2570
2571
if (This->pData != NULL)
2572
return KTX_INVALID_OPERATION; // Data already loaded.
2573
2574
if (prtctd->_stream.data.file == NULL)
2575
// This Texture not created from a stream or images already loaded;
2576
return KTX_INVALID_OPERATION;
2577
2578
if (inflateHandling == LOADDATA_INFLATE_ON_LOAD) {
2579
outputDataCapacity = ktxTexture2_GetDataSizeUncompressed(This);
2580
if (This->supercompressionScheme == KTX_SS_ZSTD || This->supercompressionScheme == KTX_SS_ZLIB)
2581
doInflate = true;
2582
} else {
2583
outputDataCapacity = This->dataSize;
2584
}
2585
2586
if (pBuffer == NULL) {
2587
This->pData = malloc(outputDataCapacity);
2588
if (This->pData == NULL)
2589
return KTX_OUT_OF_MEMORY;
2590
pDest = This->pData;
2591
} else if (bufSize < outputDataCapacity) {
2592
return KTX_INVALID_VALUE;
2593
} else {
2594
pDest = pBuffer;
2595
}
2596
2597
if (doInflate) {
2598
// Create buffer to hold deflated data.
2599
pDeflatedData = malloc(This->dataSize);
2600
if (pDeflatedData == NULL)
2601
return KTX_OUT_OF_MEMORY;
2602
pReadBuf = pDeflatedData;
2603
} else {
2604
pReadBuf = pDest;
2605
}
2606
2607
// Seek to data for first level as there may be padding between the
2608
// metadata/sgd and the image data.
2609
2610
result = prtctd->_stream.setpos(&prtctd->_stream,
2611
private->_firstLevelFileOffset);
2612
if (result != KTX_SUCCESS)
2613
goto cleanup;
2614
2615
result = prtctd->_stream.read(&prtctd->_stream, pReadBuf,
2616
This->dataSize);
2617
if (result != KTX_SUCCESS)
2618
goto cleanup;
2619
2620
if (doInflate) {
2621
assert(pDeflatedData != NULL);
2622
if (This->supercompressionScheme == KTX_SS_ZSTD) {
2623
result = ktxTexture2_inflateZstdInt(This, pDeflatedData, pDest,
2624
outputDataCapacity);
2625
} else if (This->supercompressionScheme == KTX_SS_ZLIB) {
2626
result = ktxTexture2_inflateZLIBInt(This, pDeflatedData, pDest,
2627
outputDataCapacity);
2628
}
2629
if (result != KTX_SUCCESS) {
2630
if (pBuffer == NULL) {
2631
free(This->pData);
2632
This->pData = 0;
2633
}
2634
goto cleanup;
2635
}
2636
}
2637
2638
if (IS_BIG_ENDIAN) {
2639
// Perform endianness conversion on texture data.
2640
// To avoid mip padding, need to convert each level individually.
2641
for (ktx_uint32_t level = 0; level < This->numLevels; ++level)
2642
{
2643
ktx_size_t levelOffset;
2644
ktx_size_t levelByteLength;
2645
2646
levelByteLength = private->_levelIndex[level].byteLength;
2647
levelOffset = ktxTexture2_levelDataOffset(This, level);
2648
pDest = This->pData + levelOffset;
2649
switch (prtctd->_typeSize) {
2650
case 2:
2651
_ktxSwapEndian16((ktx_uint16_t*)pDest, levelByteLength / 2);
2652
break;
2653
case 4:
2654
_ktxSwapEndian32((ktx_uint32_t*)pDest, levelByteLength / 4);
2655
break;
2656
case 8:
2657
_ktxSwapEndian64((ktx_uint64_t*)pDest, levelByteLength / 8);
2658
break;
2659
}
2660
}
2661
}
2662
2663
// No further need for stream or file offset.
2664
prtctd->_stream.destruct(&prtctd->_stream);
2665
private->_firstLevelFileOffset = 0;
2666
2667
cleanup:
2668
free(pDeflatedData);
2669
2670
return result;
2671
}
2672
2673
/**
2674
* @memberof ktxTexture2
2675
* @~English
2676
* @brief Load all the image data from the ktxTexture2's source.
2677
*
2678
* The data will be inflated if supercompressionScheme == @c KTX_SS_ZSTD or
2679
* @c KTX_SS_ZLIB.
2680
* The data is loaded into the provided buffer or to an internally allocated
2681
* buffer, if @p pBuffer is @c NULL. Callers providing their own buffer must
2682
* ensure the buffer large enough to hold the inflated data for files deflated
2683
* with Zstd or ZLIB. See ktxTexture2\_GetDataSizeUncompressed().
2684
*
2685
* The texture's levelIndex, dataSize, DFD and supercompressionScheme will
2686
* all be updated after successful inflation to reflect the inflated data.
2687
*
2688
* @param[in] This pointer to the ktxTexture object of interest.
2689
* @param[in] pBuffer pointer to the buffer in which to load the image data.
2690
* @param[in] bufSize size of the buffer pointed at by @p pBuffer.
2691
*
2692
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
2693
*
2694
* @exception KTX_INVALID_VALUE @p This is NULL.
2695
* @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size.
2696
* @exception KTX_INVALID_OPERATION
2697
* The data has already been loaded or the
2698
* ktxTexture was not created from a KTX source.
2699
* @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data.
2700
*/
2701
ktx_error_code_e
2702
ktxTexture2_LoadImageData(ktxTexture2* This,
2703
ktx_uint8_t* pBuffer, ktx_size_t bufSize)
2704
{
2705
return ktxTexture2_loadImageDataInt(This, pBuffer, bufSize, LOADDATA_INFLATE_ON_LOAD);
2706
}
2707
2708
/**
2709
* @memberof ktxTexture2
2710
* @~English
2711
* @brief Load all the image data from the ktxTexture2's source without inflatiion..
2712
*
2713
* The data will be not be inflated if supercompressionScheme == @c KTX_SS_ZSTD or
2714
* @c KTX_SS_ZLIB. This function is provided to support some rare testing scenarios.
2715
* Generally use of ktxTexture2\_LoadImageData is highly recommended. For supercompressionScheme
2716
* values other than those mentioned, the result of this function is the same as
2717
* ktxTexture2\_LoadImageData.
2718
*
2719
* The data is loaded into the provided buffer or to an internally allocated
2720
* buffer, if @p pBuffer is @c NULL.
2721
*
2722
* @param[in] This pointer to the ktxTexture object of interest.
2723
* @param[in] pBuffer pointer to the buffer in which to load the image data.
2724
* @param[in] bufSize size of the buffer pointed at by @p pBuffer.
2725
*
2726
* @return KTX_SUCCESS on success, other KTX_* enum values on error.
2727
*
2728
* @exception KTX_INVALID_VALUE @p This is NULL.
2729
* @exception KTX_INVALID_VALUE @p bufSize is less than the the image data size.
2730
* @exception KTX_INVALID_OPERATION
2731
* The data has already been loaded or the
2732
* ktxTexture was not created from a KTX source.
2733
* @exception KTX_OUT_OF_MEMORY Insufficient memory for the image data.
2734
*/
2735
ktx_error_code_e
2736
ktxTexture2_LoadDeflatedImageData(ktxTexture2* This,
2737
ktx_uint8_t* pBuffer, ktx_size_t bufSize)
2738
{
2739
return ktxTexture2_loadImageDataInt(This, pBuffer, bufSize, LOADDATA_DONT_INFLATE_ON_LOAD);
2740
}
2741
2742
/**
2743
* @memberof ktxTexture2 @private
2744
* @~English
2745
* @brief Retrieve the offset of a level's first image within the ktxTexture2's
2746
* image data.
2747
*
2748
* @param[in] This pointer to the ktxTexture2 object of interest.
2749
*/
2750
ktx_uint64_t ktxTexture2_levelDataOffset(ktxTexture2* This, ktx_uint32_t level)
2751
{
2752
return This->_private->_levelIndex[level].byteOffset;
2753
}
2754
2755
/**
2756
* @memberof ktxTexture2 @private
2757
* @~English
2758
* @brief Inflate the data in a ktxTexture2 object using Zstandard.
2759
*
2760
* The texture's levelIndex, dataSize, DFD, data pointer, and supercompressionScheme will
2761
* all be updated after successful inflation to reflect the inflated data.
2762
*
2763
* @param[in] This pointer to the ktxTexture2 object of interest.
2764
* @param[in] pDeflatedData pointer to a buffer containing the deflated data
2765
* of the entire texture.
2766
* @param[in,out] pInflatedData pointer to a buffer in which to write the inflated
2767
* data.
2768
* @param[in] inflatedDataCapacity capacity of the buffer pointed at by
2769
* @p pInflatedData.
2770
*/
2771
KTX_error_code
2772
ktxTexture2_inflateZstdInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData,
2773
ktx_uint8_t* pInflatedData,
2774
ktx_size_t inflatedDataCapacity)
2775
{
2776
ktx_uint32_t levelIndexByteLength =
2777
This->numLevels * sizeof(ktxLevelIndexEntry);
2778
uint64_t levelOffset = 0;
2779
ktxLevelIndexEntry* cindex = This->_private->_levelIndex;
2780
ktxLevelIndexEntry* nindex = NULL;
2781
ktx_uint32_t uncompressedLevelAlignment;
2782
ktx_error_code_e result = KTX_SUCCESS;
2783
2784
ZSTD_DCtx* dctx = NULL;
2785
2786
if (pDeflatedData == NULL)
2787
return KTX_INVALID_VALUE;
2788
2789
if (pInflatedData == NULL)
2790
return KTX_INVALID_VALUE;
2791
2792
if (This->supercompressionScheme != KTX_SS_ZSTD)
2793
return KTX_INVALID_OPERATION;
2794
2795
nindex = malloc(levelIndexByteLength);
2796
if (nindex == NULL)
2797
return KTX_OUT_OF_MEMORY;
2798
2799
uncompressedLevelAlignment =
2800
ktxTexture2_calcPostInflationLevelAlignment(This);
2801
2802
ktx_size_t inflatedByteLength = 0;
2803
dctx = ZSTD_createDCtx();
2804
if (dctx == NULL) {
2805
result = KTX_OUT_OF_MEMORY;
2806
goto cleanup;
2807
}
2808
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
2809
size_t levelByteLength =
2810
ZSTD_decompressDCtx(dctx, pInflatedData + levelOffset,
2811
inflatedDataCapacity,
2812
&pDeflatedData[cindex[level].byteOffset],
2813
cindex[level].byteLength);
2814
if (ZSTD_isError(levelByteLength)) {
2815
ZSTD_ErrorCode error = ZSTD_getErrorCode(levelByteLength);
2816
switch(error) {
2817
case ZSTD_error_dstSize_tooSmall:
2818
result = KTX_DECOMPRESS_LENGTH_ERROR; // inflatedDataCapacity too small.
2819
goto cleanup;
2820
case ZSTD_error_checksum_wrong:
2821
result = KTX_DECOMPRESS_CHECKSUM_ERROR;
2822
goto cleanup;
2823
case ZSTD_error_memory_allocation:
2824
result = KTX_OUT_OF_MEMORY;
2825
goto cleanup;
2826
default:
2827
result = KTX_FILE_DATA_ERROR;
2828
goto cleanup;
2829
}
2830
}
2831
2832
if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) {
2833
result = KTX_DECOMPRESS_LENGTH_ERROR;
2834
goto cleanup;
2835
}
2836
2837
nindex[level].byteOffset = levelOffset;
2838
nindex[level].uncompressedByteLength = nindex[level].byteLength =
2839
levelByteLength;
2840
ktx_size_t paddedLevelByteLength
2841
= _KTX_PADN(uncompressedLevelAlignment, levelByteLength);
2842
inflatedByteLength += paddedLevelByteLength;
2843
levelOffset += paddedLevelByteLength;
2844
inflatedDataCapacity -= paddedLevelByteLength;
2845
}
2846
2847
// Now modify the texture.
2848
2849
This->dataSize = inflatedByteLength;
2850
This->supercompressionScheme = KTX_SS_NONE;
2851
memcpy(cindex, nindex, levelIndexByteLength); // Update level index
2852
This->_private->_requiredLevelAlignment = uncompressedLevelAlignment;
2853
2854
cleanup:
2855
ZSTD_freeDCtx(dctx);
2856
free(nindex);
2857
return result;
2858
}
2859
2860
/**
2861
* @memberof ktxTexture2 @private
2862
* @~English
2863
* @brief Inflate the data in a ktxTexture2 object using miniz (ZLIB).
2864
*
2865
* The texture's levelIndex, dataSize, DFD, data pointer, and supercompressionScheme will
2866
* all be updated after successful inflation to reflect the inflated data.
2867
*
2868
* @param[in] This pointer to the ktxTexture2 object of interest.
2869
* @param[in] pDeflatedData pointer to a buffer containing the deflated
2870
* data of the entire texture.
2871
* @param[in,out] pInflatedData pointer to a buffer in which to write the
2872
* inflated data.
2873
* @param[in] inflatedDataCapacity capacity of the buffer pointed at by
2874
* @p pInflatedData.
2875
*/
2876
KTX_error_code
2877
ktxTexture2_inflateZLIBInt(ktxTexture2* This, ktx_uint8_t* pDeflatedData,
2878
ktx_uint8_t* pInflatedData,
2879
ktx_size_t inflatedDataCapacity)
2880
{
2881
ktx_uint32_t levelIndexByteLength =
2882
This->numLevels * sizeof(ktxLevelIndexEntry);
2883
uint64_t levelOffset = 0;
2884
ktxLevelIndexEntry* cindex = This->_private->_levelIndex;
2885
ktxLevelIndexEntry* nindex;
2886
ktx_uint32_t uncompressedLevelAlignment;
2887
2888
if (pDeflatedData == NULL)
2889
return KTX_INVALID_VALUE;
2890
2891
if (pInflatedData == NULL)
2892
return KTX_INVALID_VALUE;
2893
2894
if (This->supercompressionScheme != KTX_SS_ZLIB)
2895
return KTX_INVALID_OPERATION;
2896
2897
nindex = malloc(levelIndexByteLength);
2898
if (nindex == NULL)
2899
return KTX_OUT_OF_MEMORY;
2900
2901
uncompressedLevelAlignment =
2902
ktxTexture2_calcPostInflationLevelAlignment(This);
2903
2904
ktx_size_t inflatedByteLength = 0;
2905
for (int32_t level = This->numLevels - 1; level >= 0; level--) {
2906
size_t levelByteLength = inflatedDataCapacity;
2907
KTX_error_code result = ktxUncompressZLIBInt(pInflatedData + levelOffset,
2908
&levelByteLength,
2909
&pDeflatedData[cindex[level].byteOffset],
2910
cindex[level].byteLength);
2911
if (result != KTX_SUCCESS) {
2912
free(nindex);
2913
return result;
2914
}
2915
2916
if (This->_private->_levelIndex[level].uncompressedByteLength != levelByteLength) {
2917
free(nindex);
2918
return KTX_DECOMPRESS_LENGTH_ERROR;
2919
}
2920
2921
nindex[level].byteOffset = levelOffset;
2922
nindex[level].uncompressedByteLength = nindex[level].byteLength =
2923
levelByteLength;
2924
ktx_size_t paddedLevelByteLength
2925
= _KTX_PADN(uncompressedLevelAlignment, levelByteLength);
2926
inflatedByteLength += paddedLevelByteLength;
2927
levelOffset += paddedLevelByteLength;
2928
inflatedDataCapacity -= paddedLevelByteLength;
2929
}
2930
2931
// Now modify the texture.
2932
2933
This->dataSize = inflatedByteLength;
2934
This->supercompressionScheme = KTX_SS_NONE;
2935
memcpy(cindex, nindex, levelIndexByteLength); // Update level index
2936
free(nindex);
2937
This->_private->_requiredLevelAlignment = uncompressedLevelAlignment;
2938
2939
return KTX_SUCCESS;
2940
}
2941
2942
#if !KTX_FEATURE_WRITE
2943
2944
/*
2945
* Stubs for writer functions that return a proper error code
2946
*/
2947
2948
KTX_error_code
2949
ktxTexture2_SetImageFromMemory(ktxTexture2* This, ktx_uint32_t level,
2950
ktx_uint32_t layer, ktx_uint32_t faceSlice,
2951
const ktx_uint8_t* src, ktx_size_t srcSize)
2952
{
2953
UNUSED(This);
2954
UNUSED(level);
2955
UNUSED(layer);
2956
UNUSED(faceSlice);
2957
UNUSED(src);
2958
UNUSED(srcSize);
2959
return KTX_INVALID_OPERATION;
2960
}
2961
2962
KTX_error_code
2963
ktxTexture2_SetImageFromStdioStream(ktxTexture2* This, ktx_uint32_t level,
2964
ktx_uint32_t layer, ktx_uint32_t faceSlice,
2965
FILE* src, ktx_size_t srcSize)
2966
{
2967
UNUSED(This);
2968
UNUSED(level);
2969
UNUSED(layer);
2970
UNUSED(faceSlice);
2971
UNUSED(src);
2972
UNUSED(srcSize);
2973
return KTX_INVALID_OPERATION;
2974
}
2975
2976
KTX_error_code
2977
ktxTexture2_WriteToStdioStream(ktxTexture2* This, FILE* dstsstr)
2978
{
2979
UNUSED(This);
2980
UNUSED(dstsstr);
2981
return KTX_INVALID_OPERATION;
2982
}
2983
2984
KTX_error_code
2985
ktxTexture2_WriteToNamedFile(ktxTexture2* This, const char* const dstname)
2986
{
2987
UNUSED(This);
2988
UNUSED(dstname);
2989
return KTX_INVALID_OPERATION;
2990
}
2991
2992
KTX_error_code
2993
ktxTexture2_WriteToMemory(ktxTexture2* This,
2994
ktx_uint8_t** ppDstBytes, ktx_size_t* pSize)
2995
{
2996
UNUSED(This);
2997
UNUSED(ppDstBytes);
2998
UNUSED(pSize);
2999
return KTX_INVALID_OPERATION;
3000
}
3001
3002
KTX_error_code
3003
ktxTexture2_WriteToStream(ktxTexture2* This,
3004
ktxStream* dststr)
3005
{
3006
UNUSED(This);
3007
UNUSED(dststr);
3008
return KTX_INVALID_OPERATION;
3009
}
3010
3011
#endif
3012
3013
/*
3014
* Initialized here at the end to avoid the need for multiple declarations of
3015
* the virtual functions.
3016
*/
3017
3018
struct ktxTexture_vtblInt ktxTexture2_vtblInt = {
3019
(PFNCALCDATASIZELEVELS)ktxTexture2_calcDataSizeLevels,
3020
(PFNCALCFACELODSIZE)ktxTexture2_calcFaceLodSize,
3021
(PFNCALCLEVELOFFSET)ktxTexture2_calcLevelOffset
3022
};
3023
3024
struct ktxTexture_vtbl ktxTexture2_vtbl = {
3025
(PFNKTEXDESTROY)ktxTexture2_Destroy,
3026
(PFNKTEXGETIMAGEOFFSET)ktxTexture2_GetImageOffset,
3027
(PFNKTEXGETDATASIZEUNCOMPRESSED)ktxTexture2_GetDataSizeUncompressed,
3028
(PFNKTEXGETIMAGESIZE)ktxTexture2_GetImageSize,
3029
(PFNKTEXGETLEVELSIZE)ktxTexture2_GetLevelSize,
3030
(PFNKTEXITERATELEVELS)ktxTexture2_IterateLevels,
3031
(PFNKTEXITERATELOADLEVELFACES)ktxTexture2_IterateLoadLevelFaces,
3032
(PFNKTEXNEEDSTRANSCODING)ktxTexture2_NeedsTranscoding,
3033
(PFNKTEXLOADIMAGEDATA)ktxTexture2_LoadImageData,
3034
(PFNKTEXSETIMAGEFROMMEMORY)ktxTexture2_SetImageFromMemory,
3035
(PFNKTEXSETIMAGEFROMSTDIOSTREAM)ktxTexture2_SetImageFromStdioStream,
3036
(PFNKTEXWRITETOSTDIOSTREAM)ktxTexture2_WriteToStdioStream,
3037
(PFNKTEXWRITETONAMEDFILE)ktxTexture2_WriteToNamedFile,
3038
(PFNKTEXWRITETOMEMORY)ktxTexture2_WriteToMemory,
3039
(PFNKTEXWRITETOSTREAM)ktxTexture2_WriteToStream,
3040
};
3041
3042
/** @} */
3043
3044
3045