From b2c73d2b9a4b30d14dec831decce0a4b69aed54a Mon Sep 17 00:00:00 2001 From: Mark Callow Date: Sat, 29 Jan 2022 16:57:02 +0900 Subject: [PATCH 1/2] Fix asserts in DeflateZstd so they fire as intended. --- lib/writer2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/writer2.c b/lib/writer2.c index 75d4b4db57..19389097fc 100644 --- a/lib/writer2.c +++ b/lib/writer2.c @@ -717,17 +717,22 @@ ktxTexture2_DeflateZstd(ktxTexture2* This, ktx_uint32_t compressionLevel) case ZSTD_error_parameter_outOfBound: return KTX_INVALID_VALUE; case ZSTD_error_dstSize_tooSmall: +#ifdef DEBUG + assert(false && "Deflate dstSize too small."); +#else + return KTX_OUT_OF_MEMORY; +#endif case ZSTD_error_workSpace_tooSmall: #ifdef DEBUG - assert(true); // inflatedDataCapacity too small. + assert(false && "Deflate workspace too small."); #else return KTX_OUT_OF_MEMORY; #endif case ZSTD_error_memory_allocation: return KTX_OUT_OF_MEMORY; default: - // The remaining errors look they should only occur during - // decompression but just in case. + // The remaining errors look like they should only + // occur during decompression but just in case. #ifdef DEBUG assert(true); #else From 71afc96014ba3652bc39c129a7a56b030c585862 Mon Sep 17 00:00:00 2001 From: Mark Callow Date: Sun, 30 Jan 2022 17:10:27 +0900 Subject: [PATCH 2/2] Calculate dst buffer size with ZSTD_compressBound. Fixes #512. --- lib/writer2.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/writer2.c b/lib/writer2.c index 19389097fc..7bc85dd921 100644 --- a/lib/writer2.c +++ b/lib/writer2.c @@ -684,25 +684,34 @@ ktxTexture2_DeflateZstd(ktxTexture2* This, ktx_uint32_t compressionLevel) { ktx_uint32_t levelIndexByteLength = This->numLevels * sizeof(ktxLevelIndexEntry); - // Allocate a temporary buffer the same size as the current data since - // that will clearly be big enough. - ktx_uint8_t* workBuf = malloc(This->dataSize + levelIndexByteLength); + ktx_uint8_t* workBuf; ktx_uint8_t* cmpData; - ktx_size_t dstRemainingByteLength = This->dataSize; + ktx_size_t dstRemainingByteLength = 0; ktx_size_t byteLengthCmp = 0; ktx_size_t levelOffset = 0; ktxLevelIndexEntry* cindex = This->_private->_levelIndex; - ktxLevelIndexEntry* nindex = (ktxLevelIndexEntry*)workBuf; - ktx_uint8_t* pCmpDst = &workBuf[levelIndexByteLength]; + ktxLevelIndexEntry* nindex; + ktx_uint8_t* pCmpDst; ZSTD_CCtx* cctx = ZSTD_createCCtx(); - if (workBuf == NULL) - return KTX_OUT_OF_MEMORY; - if (This->supercompressionScheme != KTX_SS_NONE) return KTX_INVALID_OPERATION; + // On rare occasions the deflated data can be a few bytes larger than + // the source data. Calculating the dst buffer size using + // ZSTD_compressBound provides a suitable size plus compression is said + // to run faster when the dst buffer is >= compressBound. + for (int32_t level = This->numLevels - 1; level >= 0; level--) { + dstRemainingByteLength += ZSTD_compressBound(cindex[level].byteLength); + } + + workBuf = malloc(dstRemainingByteLength + levelIndexByteLength); + if (workBuf == NULL) + return KTX_OUT_OF_MEMORY; + nindex = (ktxLevelIndexEntry*)workBuf; + pCmpDst = &workBuf[levelIndexByteLength]; + for (int32_t level = This->numLevels - 1; level >= 0; level--) { size_t levelByteLengthCmp = ZSTD_compressCCtx(cctx, pCmpDst + levelOffset,