From 78ca6c60e325f48033038f74ce3e8229f424cd1e Mon Sep 17 00:00:00 2001 From: Vlad Lazar Date: Mon, 22 Jan 2024 13:50:48 -0500 Subject: [PATCH] Implement the compressor inside OpenEXRCore (#5) * Whitespaces and licensing * WIP OpenEXRCore implementation * Brand new spanking blosc build. * Switch to single Scanline zstd compression and Single implementation * Fixed the tests * Undo whitespace changes * Last touches * Revert extra build changes --- src/lib/OpenEXR/CMakeLists.txt | 1 - src/lib/OpenEXR/ImfCompressor.cpp | 7 +- src/lib/OpenEXR/ImfMultiPartInputFile.cpp | 3 +- src/lib/OpenEXR/ImfZstdCompressor.cpp | 129 ++++------------------ src/lib/OpenEXR/ImfZstdCompressor.h | 25 +---- src/lib/OpenEXRCore/CMakeLists.txt | 4 +- src/lib/OpenEXRCore/decoding.c | 4 + src/lib/OpenEXRCore/encoding.c | 1 + src/lib/OpenEXRCore/internal_compress.h | 1 + src/lib/OpenEXRCore/internal_decompress.h | 7 ++ src/lib/OpenEXRCore/internal_zstd.c | 115 +++++++++++++++++++ src/lib/OpenEXRCore/openexr_attr.h | 1 + src/lib/OpenEXRCore/openexr_compression.h | 11 ++ src/lib/OpenEXRCore/parse_header.c | 2 + src/test/OpenEXRCoreTest/compression.cpp | 12 ++ src/test/OpenEXRCoreTest/compression.h | 2 + src/test/OpenEXRCoreTest/main.cpp | 2 + 17 files changed, 194 insertions(+), 133 deletions(-) create mode 100644 src/lib/OpenEXRCore/internal_zstd.c diff --git a/src/lib/OpenEXR/CMakeLists.txt b/src/lib/OpenEXR/CMakeLists.txt index 1cccbdd8be..c6759e7031 100644 --- a/src/lib/OpenEXR/CMakeLists.txt +++ b/src/lib/OpenEXR/CMakeLists.txt @@ -217,7 +217,6 @@ openexr_define_library(OpenEXR ImfXdr.h DEPENDENCIES Imath::Imath - Blosc2::blosc2_static OpenEXR::Config OpenEXR::Iex OpenEXR::IlmThread diff --git a/src/lib/OpenEXR/ImfCompressor.cpp b/src/lib/OpenEXR/ImfCompressor.cpp index dfb5ab8adf..db51021dc6 100644 --- a/src/lib/OpenEXR/ImfCompressor.cpp +++ b/src/lib/OpenEXR/ImfCompressor.cpp @@ -19,6 +19,7 @@ #include "ImfRleCompressor.h" #include "ImfZipCompressor.h" #include "ImfZstdCompressor.h" +#include "openexr_compression.h" OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER @@ -145,7 +146,7 @@ newCompressor (Compression c, size_t maxScanLineSize, const Header& hdr) DwaCompressor::STATIC_HUFFMAN); case ZSTD_COMPRESSION: - return new ZstdCompressor (hdr, maxScanLineSize, 32); + return new ZstdCompressor (hdr); default: return 0; } } @@ -167,7 +168,7 @@ numLinesInBuffer (Compression comp) case B44_COMPRESSION: case B44A_COMPRESSION: case DWAA_COMPRESSION: return 32; - case ZSTD_COMPRESSION: return 32; + case ZSTD_COMPRESSION: return (int)exr_get_zstd_lines_per_chunk(); case DWAB_COMPRESSION: return 256; default: throw IEX_NAMESPACE::ArgExc ("Unknown compression type"); @@ -190,7 +191,7 @@ newTileCompressor ( return new ZipCompressor (hdr, tileLineSize, numTileLines); case ZSTD_COMPRESSION: - return new ZstdCompressor (hdr, tileLineSize, numTileLines); + return new ZstdCompressor (hdr); case PIZ_COMPRESSION: diff --git a/src/lib/OpenEXR/ImfMultiPartInputFile.cpp b/src/lib/OpenEXR/ImfMultiPartInputFile.cpp index b9ed6d5d29..b6fb9aeb12 100644 --- a/src/lib/OpenEXR/ImfMultiPartInputFile.cpp +++ b/src/lib/OpenEXR/ImfMultiPartInputFile.cpp @@ -22,6 +22,7 @@ #include "ImfTiledMisc.h" #include "ImfTimeCodeAttribute.h" #include "ImfVersion.h" +#include "openexr_compression.h" #include @@ -547,7 +548,7 @@ MultiPartInputFile::Data::chunkOffsetReconstruction ( // (TODO) fix this so that it doesn't need to be revised for future compression types. switch (parts[i]->header.compression ()) { - case ZSTD_COMPRESSION: rowsizes[i] = 32; break; + case ZSTD_COMPRESSION: rowsizes[i] = (int)exr_get_zstd_lines_per_chunk(); break; case DWAB_COMPRESSION: rowsizes[i] = 256; break; case PIZ_COMPRESSION: case B44_COMPRESSION: diff --git a/src/lib/OpenEXR/ImfZstdCompressor.cpp b/src/lib/OpenEXR/ImfZstdCompressor.cpp index d35a3deecd..55b4a8cea1 100644 --- a/src/lib/OpenEXR/ImfZstdCompressor.cpp +++ b/src/lib/OpenEXR/ImfZstdCompressor.cpp @@ -4,75 +4,42 @@ // #include +#include +#include "openexr_compression.h" #include "ImfZstdCompressor.h" -#include "blosc2.h" #include "IlmThreadPool.h" #include "ImfChannelList.h" #include "ImfMisc.h" + namespace { -class BloscInit -{ -public: - static void Init () { getInstance (); } - BloscInit (const BloscInit&) = delete; - BloscInit& operator= (const BloscInit&) = delete; - -private: - BloscInit () { blosc2_init (); } - ~BloscInit () { blosc2_destroy (); } - static BloscInit& getInstance () - { - static BloscInit instance; - return instance; - } -}; -} // namespace - +std::mutex g_mutex; +} + OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER -ZstdCompressor::ZstdCompressor ( - const Header& hdr, size_t maxScanlineSize, size_t numScanLines) - : Compressor (hdr) - , _maxScanlineSize (maxScanlineSize) - , _numScanLines (numScanLines) - , _outBuffer (nullptr, &free) - , _schunk (nullptr, &blosc2_schunk_free) + +ZstdCompressor::ZstdCompressor (const Header& hdr) + : Compressor (hdr), _outBuffer () {} int ZstdCompressor::numScanLines () const { - return _numScanLines; // Needs to be in sync with ImfCompressor::numLinesInBuffer + return (int)exr_get_zstd_lines_per_chunk(); // Needs to be in sync with ImfCompressor::numLinesInBuffer } int ZstdCompressor::compress ( const char* inPtr, int inSize, int minY, const char*& outPtr) { - int typeSize = std::numeric_limits::min (); - for (auto it = header ().channels ().begin (); - it != header ().channels ().end (); - ++it) + outPtr = (char*) malloc (inSize); { - // BLOSC prefilter is affected by the typesize. Initializing to max will ensure that a channel is not split in 2 and filtered separately. - // probably compression can be improved for non-deep images by compressing every channel separately with the correct typeSize - // (much harder to do for Deep-Data). - typeSize = std::max (typeSize, Imf::pixelTypeSize (it.channel ().type)); + std::lock_guard lock (g_mutex); + _outBuffer.push_back (raw_ptr ((char*) outPtr, &free)); } - - auto ret = BLOSC_compress_impl (inPtr, inSize, typeSize, outPtr); - auto fullSize = Xdr::size () + ret; - auto data = malloc (fullSize); - auto write = (char*) data; - - Xdr::write (write, Versions::LATEST); - - memcpy (write, outPtr, ret); - outPtr = (char*) data; - - _outBuffer = raw_ptr ((char*) data, &free); - + auto fullSize = + exr_compress_zstd ((char*) (inPtr), inSize, (void*) outPtr, inSize); return fullSize; } @@ -80,67 +47,15 @@ int ZstdCompressor::uncompress ( const char* inPtr, int inSize, int minY, const char*& outPtr) { - auto read = (const char*) inPtr; - int v; - Xdr::read (read, v); - if (v == Versions::SINGLE_BLOB) + auto read = (const char*) inPtr; + void* write = nullptr; + auto ret = exr_uncompress_zstd (read, inSize, &write, 0); { - return BLOSC_uncompress_impl_single_blob ( - read, inSize - Xdr::size (), outPtr); + std::lock_guard lock (g_mutex); + _outBuffer.push_back (raw_ptr ((char*) write, &free)); } - else { throw Iex::InputExc ("Unsupported ZstdCompressor version"); } -} - -int -ZstdCompressor::BLOSC_compress_impl ( - const char* inPtr, int inSize, int typeSize, const char*& out) -{ - BloscInit::Init (); - blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS; - - cparams.typesize = typeSize; - // clevel 9 is about a 20% increase in compression compared to 5. - // Decompression speed is unchanged. - cparams.clevel = header ().zstdCompressionLevel (); - cparams.nthreads = 1; - cparams.compcode = BLOSC_ZSTD; // Codec - cparams.splitmode = - BLOSC_NEVER_SPLIT; // Split => multithreading, not split better compression - - blosc2_storage storage = BLOSC2_STORAGE_DEFAULTS; - storage.cparams = &cparams; - storage.contiguous = true; - - _schunk = schunk_ptr (blosc2_schunk_new (&storage), &blosc2_schunk_free); - - auto in = const_cast (inPtr); - blosc2_schunk_append_buffer (_schunk.get (), in, inSize); - - uint8_t* buffer; - bool shouldFree = true; - auto size = blosc2_schunk_to_buffer (_schunk.get (), &buffer, &shouldFree); - out = (char*) buffer; - if (shouldFree) { _outBuffer = raw_ptr ((char*) buffer, &free); } - return size; -} - -int -ZstdCompressor::BLOSC_uncompress_impl_single_blob ( - const char* inPtr, int inSize, const char*& out) -{ - auto in = const_cast (inPtr); - _schunk = schunk_ptr ( - blosc2_schunk_from_buffer ( - reinterpret_cast (in), inSize, true), - &blosc2_schunk_free); - - auto buffSize = _maxScanlineSize * numScanLines (); - _outBuffer = - Imf::ZstdCompressor::raw_ptr ((char*) malloc (buffSize), &free); - auto size = blosc2_schunk_decompress_chunk ( - _schunk.get (), 0, _outBuffer.get (), buffSize); - out = _outBuffer.get (); - return size; + outPtr = (const char*) write; + return ret; } OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT \ No newline at end of file diff --git a/src/lib/OpenEXR/ImfZstdCompressor.h b/src/lib/OpenEXR/ImfZstdCompressor.h index d9319e076c..c9f045cddd 100644 --- a/src/lib/OpenEXR/ImfZstdCompressor.h +++ b/src/lib/OpenEXR/ImfZstdCompressor.h @@ -1,45 +1,30 @@ -#pragma once - // // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) Contributors to the OpenEXR Project. // +#pragma once + #include #include "ImfNamespace.h" #include "ImfCompressor.h" #include "ImfHeader.h" #include "blosc2.h" +#include "vector" OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER class ZstdCompressor : public Compressor { public: - ZstdCompressor ( - const Header& hdr, size_t maxScanLines, size_t numScanLines); - + explicit ZstdCompressor (const Header& hdr); private: - using schunk_ptr = - std::unique_ptr; using raw_ptr = std::unique_ptr; - raw_ptr _outBuffer; - schunk_ptr _schunk; - size_t _maxScanlineSize; - size_t _numScanLines; + std::vector _outBuffer; int numScanLines () const override; // max int compress ( const char* inPtr, int inSize, int minY, const char*& outPtr) override; int uncompress ( const char* inPtr, int inSize, int minY, const char*& outPtr) override; - int BLOSC_compress_impl ( - const char* inPtr, int inSize, int typeSize, const char*& out); - int BLOSC_uncompress_impl_single_blob ( - const char* inPtr, int inSize, const char*& out); - enum Versions : int - { - SINGLE_BLOB = 1, - LATEST = SINGLE_BLOB - }; }; OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT \ No newline at end of file diff --git a/src/lib/OpenEXRCore/CMakeLists.txt b/src/lib/OpenEXRCore/CMakeLists.txt index f4bd54efb3..ecfc171202 100644 --- a/src/lib/OpenEXRCore/CMakeLists.txt +++ b/src/lib/OpenEXRCore/CMakeLists.txt @@ -45,6 +45,7 @@ openexr_define_library(OpenEXRCore internal_piz.c internal_dwa.c internal_huf.c + internal_zstd.c attributes.c string.c @@ -102,6 +103,7 @@ openexr_define_library(OpenEXRCore DEPENDENCIES Imath::Imath + Blosc2::blosc2_static ) if (DEFINED EXR_DEFLATE_LIB) @@ -110,4 +112,4 @@ if (DEFINED EXR_DEFLATE_LIB) else() target_link_libraries(OpenEXRCore PUBLIC ${EXR_DEFLATE_LIB}) endif() -endif() +endif() \ No newline at end of file diff --git a/src/lib/OpenEXRCore/decoding.c b/src/lib/OpenEXRCore/decoding.c index 322cbd8965..c7db79f755 100644 --- a/src/lib/OpenEXRCore/decoding.c +++ b/src/lib/OpenEXRCore/decoding.c @@ -263,6 +263,10 @@ decompress_data ( rv = internal_exr_undo_dwab ( decode, packbufptr, packsz, unpackbufptr, unpacksz); break; + case EXR_COMPRESSION_ZSTD: + rv = internal_exr_undo_zstd ( + decode, packbufptr, packsz, unpackbufptr, unpacksz); + break; case EXR_COMPRESSION_LAST_TYPE: default: return pctxt->print_error ( diff --git a/src/lib/OpenEXRCore/encoding.c b/src/lib/OpenEXRCore/encoding.c index b92e0ce356..6b017ed7b0 100644 --- a/src/lib/OpenEXRCore/encoding.c +++ b/src/lib/OpenEXRCore/encoding.c @@ -54,6 +54,7 @@ default_compress_chunk (exr_encode_pipeline_t* encode) case EXR_COMPRESSION_B44A: rv = internal_exr_apply_b44a (encode); break; case EXR_COMPRESSION_DWAA: rv = internal_exr_apply_dwaa (encode); break; case EXR_COMPRESSION_DWAB: rv = internal_exr_apply_dwab (encode); break; + case EXR_COMPRESSION_ZSTD: rv = internal_exr_apply_zstd (encode); break; case EXR_COMPRESSION_LAST_TYPE: default: return pctxt->print_error ( diff --git a/src/lib/OpenEXRCore/internal_compress.h b/src/lib/OpenEXRCore/internal_compress.h index 360015c120..27315f68a0 100644 --- a/src/lib/OpenEXRCore/internal_compress.h +++ b/src/lib/OpenEXRCore/internal_compress.h @@ -33,4 +33,5 @@ exr_result_t internal_exr_apply_dwaa (exr_encode_pipeline_t* encode); exr_result_t internal_exr_apply_dwab (exr_encode_pipeline_t* encode); +exr_result_t internal_exr_apply_zstd (exr_encode_pipeline_t* encode); #endif /* OPENEXR_CORE_COMPRESS_H */ diff --git a/src/lib/OpenEXRCore/internal_decompress.h b/src/lib/OpenEXRCore/internal_decompress.h index 834b854a3e..2726a4afd3 100644 --- a/src/lib/OpenEXRCore/internal_decompress.h +++ b/src/lib/OpenEXRCore/internal_decompress.h @@ -73,4 +73,11 @@ exr_result_t internal_exr_undo_dwab ( void* uncompressed_data, uint64_t uncompressed_size); +exr_result_t internal_exr_undo_zstd ( + exr_decode_pipeline_t* decode, + const void* compressed_data, + uint64_t comp_buf_size, + void* uncompressed_data, + uint64_t uncompressed_size); + #endif /* OPENEXR_CORE_DECOMPRESS_H */ diff --git a/src/lib/OpenEXRCore/internal_zstd.c b/src/lib/OpenEXRCore/internal_zstd.c new file mode 100644 index 0000000000..1fc845c6a0 --- /dev/null +++ b/src/lib/OpenEXRCore/internal_zstd.c @@ -0,0 +1,115 @@ +/* +** SPDX-License-Identifier: BSD-3-Clause +** Copyright Contributors to the OpenEXR Project. +*/ + +#include +#include "internal_compress.h" +#include "internal_decompress.h" +#include "blosc2.h" + +size_t +exr_get_zstd_lines_per_chunk () +{ + return 1; +} + +long +exr_compress_zstd (char* inPtr, int inSize, void* outPtr, int outPtrSize) +{ + if (inSize == 0) // Weird input data when subsampling + { + outPtr = NULL; + return 0; + } + + blosc2_cparams cparams = BLOSC2_CPARAMS_DEFAULTS; + int typeSize = inSize % 4 == 0 ? 4 : 2; + cparams.typesize = typeSize; + // clevel 9 is about a 20% increase in compression compared to 5. + // Decompression speed is unchanged. + int zstd_level; + exr_get_default_zstd_compression_level (&zstd_level); + cparams.clevel = zstd_level; + cparams.nthreads = 1; + cparams.compcode = BLOSC_ZSTD; // Codec + cparams.splitmode = + BLOSC_NEVER_SPLIT; // Split => multithreading, not split better compression + + blosc2_storage storage = BLOSC2_STORAGE_DEFAULTS; + storage.contiguous = true; + storage.cparams = &cparams; + + blosc2_schunk* _schunk = blosc2_schunk_new (&storage); + + blosc2_schunk_append_buffer (_schunk, inPtr, inSize); + + uint8_t* buffer; + bool shouldFree = true; + int64_t size = blosc2_schunk_to_buffer (_schunk, &buffer, &shouldFree); + + if (size <= inSize && size <= outPtrSize && size > 0) + { memcpy (outPtr, buffer, size); } + else + { + memcpy (outPtr, inPtr, inSize); + size = inSize; // We increased compression size + } + + if (shouldFree) { free (buffer); } + + blosc2_schunk_free (_schunk); + return size; +} + +long +exr_uncompress_zstd ( + const char* inPtr, uint64_t inSize, void** outPtr, uint64_t outPtrSize) +{ + blosc2_schunk* _schunk = blosc2_schunk_from_buffer ((uint8_t *)inPtr, inSize, true); + + if (_schunk == NULL) { return -1; } + + if (outPtrSize == 0) // we don't have any storage allocated + { + *outPtr = malloc (_schunk->nbytes); + outPtrSize = _schunk->nbytes; + } + + int size = blosc2_schunk_decompress_chunk (_schunk, 0, *outPtr, outPtrSize); + blosc2_schunk_free (_schunk); + + return size; +} + +exr_result_t +internal_exr_apply_zstd (exr_encode_pipeline_t* encode) +{ + long compressedSize = exr_compress_zstd ( + encode->packed_buffer, + encode->packed_bytes, + encode->compressed_buffer, + encode->compressed_alloc_size); + if (compressedSize < 0) { return EXR_ERR_UNKNOWN; } + + encode->compressed_bytes = compressedSize; + return EXR_ERR_SUCCESS; +} + +exr_result_t +internal_exr_undo_zstd ( + exr_decode_pipeline_t* decode, + const void* compressed_data, + uint64_t comp_buf_size, + void* uncompressed_data, + uint64_t uncompressed_size) +{ + + long uncompressedSize = exr_uncompress_zstd ( + (const char*) compressed_data, + comp_buf_size, + &uncompressed_data, + uncompressed_size); + if (uncompressed_size != uncompressedSize) { return EXR_ERR_CORRUPT_CHUNK; } + return EXR_ERR_SUCCESS; +} \ No newline at end of file diff --git a/src/lib/OpenEXRCore/openexr_attr.h b/src/lib/OpenEXRCore/openexr_attr.h index eabcd57d9c..e6aa7421ba 100644 --- a/src/lib/OpenEXRCore/openexr_attr.h +++ b/src/lib/OpenEXRCore/openexr_attr.h @@ -45,6 +45,7 @@ typedef enum EXR_COMPRESSION_B44A = 7, EXR_COMPRESSION_DWAA = 8, EXR_COMPRESSION_DWAB = 9, + EXR_COMPRESSION_ZSTD = 10, EXR_COMPRESSION_LAST_TYPE /**< Invalid value, provided for range checking. */ } exr_compression_t; diff --git a/src/lib/OpenEXRCore/openexr_compression.h b/src/lib/OpenEXRCore/openexr_compression.h index 67ae45004b..e5956cfc85 100644 --- a/src/lib/OpenEXRCore/openexr_compression.h +++ b/src/lib/OpenEXRCore/openexr_compression.h @@ -45,6 +45,17 @@ exr_result_t exr_uncompress_buffer ( size_t out_bytes_avail, size_t* actual_out); +EXR_EXPORT +long exr_compress_zstd ( + char* inPtr, int inSize, void * outPtr, int outPtrSize); + +EXR_EXPORT +long exr_uncompress_zstd ( + const char* inPtr, uint64_t inSize, void ** outPtr, uint64_t outPtrSize); + +EXR_EXPORT +size_t exr_get_zstd_lines_per_chunk(); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/lib/OpenEXRCore/parse_header.c b/src/lib/OpenEXRCore/parse_header.c index b85273a378..a7acc4621d 100644 --- a/src/lib/OpenEXRCore/parse_header.c +++ b/src/lib/OpenEXRCore/parse_header.c @@ -9,6 +9,7 @@ #include "internal_constants.h" #include "internal_structs.h" #include "internal_xdr.h" +#include "openexr_compression.h" #include #include @@ -2364,6 +2365,7 @@ internal_exr_compute_chunk_offset_size (struct _internal_exr_part* curpart) case EXR_COMPRESSION_B44A: case EXR_COMPRESSION_DWAA: linePerChunk = 32; break; case EXR_COMPRESSION_DWAB: linePerChunk = 256; break; + case EXR_COMPRESSION_ZSTD: linePerChunk = exr_get_zstd_lines_per_chunk(); break; case EXR_COMPRESSION_LAST_TYPE: default: /* ERROR CONDITION */ diff --git a/src/test/OpenEXRCoreTest/compression.cpp b/src/test/OpenEXRCoreTest/compression.cpp index 772111647f..e0764e9f0b 100644 --- a/src/test/OpenEXRCoreTest/compression.cpp +++ b/src/test/OpenEXRCoreTest/compression.cpp @@ -1419,6 +1419,7 @@ doWriteRead ( case EXR_COMPRESSION_RLE: case EXR_COMPRESSION_ZIP: case EXR_COMPRESSION_ZIPS: + case EXR_COMPRESSION_ZSTD: restore.compareExact (p, "orig", "C loaded C"); break; case EXR_COMPRESSION_PIZ: @@ -1681,6 +1682,12 @@ testDWABCompression (const std::string& tempdir) testComp (tempdir, EXR_COMPRESSION_DWAB); } +void +testZstdCompression (const std::string& tempdir) +{ + testComp (tempdir, EXR_COMPRESSION_ZSTD); +} + void testDeepNoCompression (const std::string& tempdir) {} @@ -1692,3 +1699,8 @@ testDeepZIPCompression (const std::string& tempdir) void testDeepZIPSCompression (const std::string& tempdir) {} + +void +testDeepZstdCompression (const std::string& tempdir) +{ +} \ No newline at end of file diff --git a/src/test/OpenEXRCoreTest/compression.h b/src/test/OpenEXRCoreTest/compression.h index 573e10f96c..ef5391a92b 100644 --- a/src/test/OpenEXRCoreTest/compression.h +++ b/src/test/OpenEXRCoreTest/compression.h @@ -18,9 +18,11 @@ void testB44Compression (const std::string& tempdir); void testB44ACompression (const std::string& tempdir); void testDWAACompression (const std::string& tempdir); void testDWABCompression (const std::string& tempdir); +void testZstdCompression (const std::string& tempdir); void testDeepNoCompression (const std::string& tempdir); void testDeepZIPCompression (const std::string& tempdir); void testDeepZIPSCompression (const std::string& tempdir); +void testDeepZstdCompression (const std::string& tempdir); #endif // OPENEXR_CORE_TEST_COMPRESSION_H diff --git a/src/test/OpenEXRCoreTest/main.cpp b/src/test/OpenEXRCoreTest/main.cpp index d12d6718f7..dae1ea29ae 100644 --- a/src/test/OpenEXRCoreTest/main.cpp +++ b/src/test/OpenEXRCoreTest/main.cpp @@ -202,10 +202,12 @@ main (int argc, char* argv[]) TEST (testB44ACompression, "core_compression"); TEST (testDWAACompression, "core_compression"); TEST (testDWABCompression, "core_compression"); + TEST (testZstdCompression, "core_compression"); TEST (testDeepNoCompression, "core_compression"); TEST (testDeepZIPCompression, "core_compression"); TEST (testDeepZIPSCompression, "core_compression"); + TEST (testDeepZstdCompression, "core_compression"); // empty dummy test if (helpMode) {