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