diff --git a/Package.swift b/Package.swift index 1bfe99a7..38a81e4a 100644 --- a/Package.swift +++ b/Package.swift @@ -26,6 +26,32 @@ struct Arch } } + enum CPU: String + { + case arm = "arm" + case arm64 = "arm64" + case x86_64 = "x86_64" + case i386 = "i386" + case powerpc = "powerpc" + case powerpc64 = "powerpc64" + case powerpc64le = "powerpc64le" + case s390x = "s390x" + case wasm32 = "wasm32" + case arm64_32 = "arm64_32" + + public var family: [CPU] + { + switch self + { + case .arm, .arm64, .arm64_32: [.arm, .arm64, .arm64_32] + case .x86_64, .i386: [.x86_64, .i386] + case .powerpc, .powerpc64, .powerpc64le: [.powerpc, .powerpc64, .powerpc64le] + case .s390x: [.s390x] + case .wasm32: [.wasm32] + } + } + } + /* ------------------------------------------------------------------------- * To detect platform triplets, we need to know the OS and CPU architecture. * -------------------------------------------------------------------------*/ @@ -59,28 +85,61 @@ struct Arch #endif #if arch(arm64) - static let cpuArch: String = "arm64" + static let cpuArch: CPU = .arm64 #elseif arch(x86_64) - static let cpuArch: String = "x86_64" + static let cpuArch: CPU = .x86_64 #elseif arch(i386) - static let cpuArch: String = "i386" + static let cpuArch: CPU = .i386 #elseif arch(arm) - static let cpuArch: String = "arm" + static let cpuArch: CPU = .arm #elseif arch(powerpc64) - static let cpuArch: String = "powerpc64" + static let cpuArch: CPU = .powerpc64 #elseif arch(powerpc64le) - static let cpuArch: String = "powerpc64le" + static let cpuArch: CPU = .powerpc64le #elseif arch(powerpc) - static let cpuArch: String = "powerpc" + static let cpuArch: CPU = .powerpc #elseif arch(s390x) - static let cpuArch: String = "s390x" + static let cpuArch: CPU = .s390x #elseif arch(wasm32) - static let cpuArch: String = "wasm32" + static let cpuArch: CPU = .wasm32 #elseif arch(arm64_32) - static let cpuArch: String = "arm64_32" + static let cpuArch: CPU = .arm64_32 #endif } +var chipsetExcludeDirs: [String] = [] +var chipsetDefinesC: [CSetting] = [] +var chipsetDefinesCXX: [CXXSetting] = [] +if (Arch.cpuArch.family.contains(.arm)) +{ + chipsetExcludeDirs.append("intel") + chipsetExcludeDirs.append("powerpc") + chipsetDefinesC.append(.define("WITH_ARM", to: "1")) + chipsetDefinesCXX.append(.define("WITH_ARM", to: "1")) +} +else if (Arch.cpuArch.family.contains(.x86_64)) +{ + chipsetExcludeDirs.append("arm") + chipsetExcludeDirs.append("powerpc") + chipsetDefinesC.append(.define("WITH_INTEL", to: "1")) + chipsetDefinesCXX.append(.define("WITH_INTEL", to: "1")) +} +else if (Arch.cpuArch.family.contains(.powerpc)) +{ + chipsetExcludeDirs.append("arm") + chipsetExcludeDirs.append("intel") + chipsetDefinesC.append(.define("WITH_POWERPC", to: "1")) + chipsetDefinesCXX.append(.define("WITH_POWERPC", to: "1")) +} +else /* a unicorn! 🦄 */ +{ + chipsetExcludeDirs.append("arm") + chipsetExcludeDirs.append("intel") + chipsetExcludeDirs.append("powerpc") + chipsetDefinesC.append(.define("WITH_UNICORNS", to: "1")) + chipsetDefinesCXX.append(.define("WITH_UNICORNS", to: "1")) +} + #if os(Windows) let platformGLFWExcludes: [String] = [ "xkb_unicode.c", @@ -317,6 +376,8 @@ struct Arch let platformTurboJPEGExcludes: [String] = [ "turbojpeg-jni.c", "tjunittest.c", + "tjexample.c", + "example.c" ] #endif /* os(macOS) || os(Linux) */ @@ -338,6 +399,18 @@ let package = Package( name: "OneTBB", targets: ["OneTBB"] ), + .library( + name: "MetaTBB", + targets: ["MetaTBB"] + ), + .library( + name: "TBBMalloc", + targets: ["TBBMalloc"] + ), + .library( + name: "TBBMallocProxy", + targets: ["TBBMallocProxy"] + ), .library( name: "Python", targets: ["Python"] @@ -588,9 +661,39 @@ let package = Package( ), .target( - name: "OneTBB", - dependencies: [], + name: "TBBMallocProxy", + dependencies: [ + .target(name: "OneTBB"), + ], + exclude: [], + publicHeadersPath: ".", + cxxSettings: [ + .define("_XOPEN_SOURCE"), + ], + swiftSettings: [ + .interoperabilityMode(.Cxx), + ] + ), + + .target( + name: "TBBMalloc", + dependencies: [ + .target(name: "OneTBB"), + .target(name: "TBBMallocProxy"), + ], exclude: [], + publicHeadersPath: ".", + cxxSettings: [ + .define("_XOPEN_SOURCE"), + .define("__TBBMALLOC_BUILD", to: "1"), + ], + swiftSettings: [ + .interoperabilityMode(.Cxx), + ] + ), + + .target( + name: "OneTBB", publicHeadersPath: "include", cxxSettings: [ .define("_XOPEN_SOURCE"), @@ -601,6 +704,23 @@ let package = Package( ] ), + .target( + name: "MetaTBB", + dependencies: [ + .target(name: "OneTBB"), + .target(name: "TBBMalloc"), + .target(name: "TBBMallocProxy"), + ], + exclude: [], + cxxSettings: [ + .define("_XOPEN_SOURCE"), + .define("TBB_USE_PROFILING_TOOLS", to: "2"), + ], + swiftSettings: [ + .interoperabilityMode(.Cxx), + ] + ), + .target( name: "Shaderc", dependencies: [ @@ -758,11 +878,14 @@ let package = Package( dependencies: [ .target(name: "ZLibDataCompression"), ], - exclude: [], + exclude: [ + "example.c", + "pngtest.c" + ] + chipsetExcludeDirs, publicHeadersPath: "include", cSettings: [ .headerSearchPath("."), - ], + ] + chipsetDefinesC, swiftSettings: [ .interoperabilityMode(.C), ] @@ -776,7 +899,11 @@ let package = Package( exclude: platformTurboJPEGExcludes, publicHeadersPath: "include/turbo", cSettings: [ - .headerSearchPath(".") + .headerSearchPath("."), + .define("C_LOSSLESS_SUPPORTED", to: "1"), + .define("D_LOSSLESS_SUPPORTED", to: "1"), + .define("PPM_SUPPORTED", to: "1"), + .define("BITS_IN_JSAMPLE", to: "12") ], swiftSettings: [ .interoperabilityMode(.C), @@ -794,7 +921,9 @@ let package = Package( exclude: platformTIFFExcludes, publicHeadersPath: "include", cxxSettings: [ + .define("FROM_TIF_JPEG_12", to: "1"), .define("HAVE_JPEGTURBO_DUAL_MODE_8_12", to: "1"), + .define("BITS_IN_JSAMPLE", to: "12") ], swiftSettings: [ .interoperabilityMode(.C), @@ -955,7 +1084,7 @@ let package = Package( .target( name: "OpenSubdiv", dependencies: [ - .target(name: "OneTBB"), + .target(name: "MetaTBB"), .target(name: "OpenMP"), .target(name: "GPUShaders"), ], @@ -1141,7 +1270,7 @@ let package = Package( name: "OpenVDB", dependencies: [ .target(name: "Boost"), - .target(name: "OneTBB"), + .target(name: "MetaTBB"), .target(name: "Blosc"), .target(name: "Python"), .target(name: "PyBind11"), diff --git a/Sources/LZMA2/check/crc32_tablegen.c b/Sources/LZMA2/check/crc32_tablegen.c index 44bd6680..4f596875 100644 --- a/Sources/LZMA2/check/crc32_tablegen.c +++ b/Sources/LZMA2/check/crc32_tablegen.c @@ -102,16 +102,16 @@ print_lz_table(void) } -int -main(void) -{ - init_crc32_table(); - -#ifdef LZ_HASH_TABLE - print_lz_table(); -#else - print_crc32_table(); -#endif - - return 0; -} +// int +// main(void) +// { +// init_crc32_table(); + +// #ifdef LZ_HASH_TABLE +// print_lz_table(); +// #else +// print_crc32_table(); +// #endif + +// return 0; +// } diff --git a/Sources/LZMA2/check/crc64_small.c b/Sources/LZMA2/check/crc64_small.c index 420f7cfb..3981e27e 100644 --- a/Sources/LZMA2/check/crc64_small.c +++ b/Sources/LZMA2/check/crc64_small.c @@ -40,19 +40,19 @@ crc64_init(void) } -extern LZMA_API(uint64_t) -lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) -{ -#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR - mythread_once(crc64_init); -#endif - - crc = ~crc; - - while (size != 0) { - crc = crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); - --size; - } - - return ~crc; -} +// extern LZMA_API(uint64_t) +// lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) +// { +// #ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR +// mythread_once(crc64_init); +// #endif + +// crc = ~crc; + +// while (size != 0) { +// crc = crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); +// --size; +// } + +// return ~crc; +// } diff --git a/Sources/LZMA2/check/crc64_tablegen.c b/Sources/LZMA2/check/crc64_tablegen.c index 40fcf498..54cf0203 100644 --- a/Sources/LZMA2/check/crc64_tablegen.c +++ b/Sources/LZMA2/check/crc64_tablegen.c @@ -79,10 +79,10 @@ print_crc64_table(void) } -int -main(void) -{ - init_crc64_table(); - print_crc64_table(); - return 0; -} +// int +// main(void) +// { +// init_crc64_table(); +// print_crc64_table(); +// return 0; +// } diff --git a/Sources/LZMA2/lzma/fastpos_tablegen.c b/Sources/LZMA2/lzma/fastpos_tablegen.c index d4484c82..70e64da5 100644 --- a/Sources/LZMA2/lzma/fastpos_tablegen.c +++ b/Sources/LZMA2/lzma/fastpos_tablegen.c @@ -16,40 +16,40 @@ #include "fastpos.h" -int -main(void) -{ - uint8_t fastpos[1 << FASTPOS_BITS]; +// int +// main(void) +// { +// uint8_t fastpos[1 << FASTPOS_BITS]; - const uint8_t fast_slots = 2 * FASTPOS_BITS; - uint32_t c = 2; +// const uint8_t fast_slots = 2 * FASTPOS_BITS; +// uint32_t c = 2; - fastpos[0] = 0; - fastpos[1] = 1; +// fastpos[0] = 0; +// fastpos[1] = 1; - for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) { - const uint32_t k = 1 << ((slot_fast >> 1) - 1); - for (uint32_t j = 0; j < k; ++j, ++c) - fastpos[c] = slot_fast; - } +// for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) { +// const uint32_t k = 1 << ((slot_fast >> 1) - 1); +// for (uint32_t j = 0; j < k; ++j, ++c) +// fastpos[c] = slot_fast; +// } - printf("/* This file has been automatically generated " - "by fastpos_tablegen.c. */\n\n" - "#include \"common.h\"\n" - "#include \"fastpos.h\"\n\n" - "const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {"); +// printf("/* This file has been automatically generated " +// "by fastpos_tablegen.c. */\n\n" +// "#include \"common.h\"\n" +// "#include \"fastpos.h\"\n\n" +// "const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {"); - for (size_t i = 0; i < (1 << FASTPOS_BITS); ++i) { - if (i % 16 == 0) - printf("\n\t"); +// for (size_t i = 0; i < (1 << FASTPOS_BITS); ++i) { +// if (i % 16 == 0) +// printf("\n\t"); - printf("%3u", (unsigned int)(fastpos[i])); +// printf("%3u", (unsigned int)(fastpos[i])); - if (i != (1 << FASTPOS_BITS) - 1) - printf(","); - } +// if (i != (1 << FASTPOS_BITS) - 1) +// printf(","); +// } - printf("\n};\n"); +// printf("\n};\n"); - return 0; -} +// return 0; +// } diff --git a/Sources/LZMA2/rangecoder/price_tablegen.c b/Sources/LZMA2/rangecoder/price_tablegen.c index bf08ce39..1b34c879 100644 --- a/Sources/LZMA2/rangecoder/price_tablegen.c +++ b/Sources/LZMA2/rangecoder/price_tablegen.c @@ -78,10 +78,10 @@ print_price_table(void) } -int -main(void) -{ - init_price_table(); - print_price_table(); - return 0; -} +// int +// main(void) +// { +// init_price_table(); +// print_price_table(); +// return 0; +// } diff --git a/Sources/LibPNG/arm/arm_init.c b/Sources/LibPNG/arm/arm_init.c new file mode 100644 index 00000000..ae753b5f --- /dev/null +++ b/Sources/LibPNG/arm/arm_init.c @@ -0,0 +1,139 @@ + +/* arm_init.c - NEON optimised filter functions + * + * Copyright (c) 2018-2022 Cosmin Truta + * Copyright (c) 2014,2016 Glenn Randers-Pehrson + * Written by Mans Rullgard, 2011. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* This module requires POSIX 1003.1 functions. */ +#define _POSIX_SOURCE 1 + +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +#if PNG_ARM_NEON_OPT > 0 || defined(WITH_ARM) +#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */ +/* WARNING: it is strongly recommended that you do not build libpng with + * run-time checks for CPU features if at all possible. In the case of the ARM + * NEON instructions there is no processor-specific way of detecting the + * presence of the required support, therefore run-time detection is extremely + * OS specific. + * + * You may set the macro PNG_ARM_NEON_FILE to the file name of file containing + * a fragment of C source code which defines the png_have_neon function. There + * are a number of implementations in contrib/arm-neon, but the only one that + * has partial support is contrib/arm-neon/linux.c - a generic Linux + * implementation which reads /proc/cpufino. + */ +#include /* for sig_atomic_t */ + +#ifndef PNG_ARM_NEON_FILE +# if defined(__aarch64__) || defined(_M_ARM64) + /* ARM Neon is expected to be unconditionally available on ARM64. */ +# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on ARM64" +# elif defined(__ARM_NEON__) || defined(__ARM_NEON) + /* ARM Neon is expected to be available on the target CPU architecture. */ +# error "PNG_ARM_NEON_CHECK_SUPPORTED must not be defined on this CPU arch" +# elif defined(__linux__) +# define PNG_ARM_NEON_FILE "contrib/arm-neon/linux.c" +# else +# error "No support for run-time ARM Neon checking; use compile-time options" +# endif +#endif + +static int png_have_neon(png_structp png_ptr); +#ifdef PNG_ARM_NEON_FILE +# include PNG_ARM_NEON_FILE +#endif +#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ + +#ifndef PNG_ALIGNED_MEMORY_SUPPORTED +# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED" +#endif + +void +png_init_filter_functions_neon(png_structp pp, unsigned int bpp) +{ + /* The switch statement is compiled in for ARM_NEON_API, the call to + * png_have_neon is compiled in for ARM_NEON_CHECK. If both are defined + * the check is only performed if the API has not set the NEON option on + * or off explicitly. In this case the check controls what happens. + * + * If the CHECK is not compiled in and the option is UNSET the behavior prior + * to 1.6.7 was to use the NEON code - this was a bug caused by having the + * wrong order of the 'ON' and 'default' cases. UNSET now defaults to OFF, + * as documented in png.h + */ + png_debug(1, "in png_init_filter_functions_neon"); +#ifdef PNG_ARM_NEON_API_SUPPORTED + switch ((pp->options >> PNG_ARM_NEON) & 3) + { + case PNG_OPTION_UNSET: + /* Allow the run-time check to execute if it has been enabled - + * thus both API and CHECK can be turned on. If it isn't supported + * this case will fall through to the 'default' below, which just + * returns. + */ +#endif /* PNG_ARM_NEON_API_SUPPORTED */ +#ifdef PNG_ARM_NEON_CHECK_SUPPORTED + { + static volatile sig_atomic_t no_neon = -1; /* not checked */ + + if (no_neon < 0) + no_neon = !png_have_neon(pp); + + if (no_neon) + return; + } +#ifdef PNG_ARM_NEON_API_SUPPORTED + break; +#endif +#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */ + +#ifdef PNG_ARM_NEON_API_SUPPORTED + default: /* OFF or INVALID */ + return; + + case PNG_OPTION_ON: + /* Option turned on */ + break; + } +#endif + + /* IMPORTANT: any new external functions used here must be declared using + * PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the + * 'prefix' option to configure works: + * + * ./configure --with-libpng-prefix=foobar_ + * + * Verify you have got this right by running the above command, doing a build + * and examining pngprefix.h; it must contain a #define for every external + * function you add. (Notice that this happens automatically for the + * initialization function.) + */ + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon; + + if (bpp == 3) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth3_neon; + } + + else if (bpp == 4) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth4_neon; + } +} +#endif /* PNG_ARM_NEON_OPT > 0 */ +#endif /* READ */ diff --git a/Sources/LibPNG/arm/filter_neon_intrinsics.c b/Sources/LibPNG/arm/filter_neon_intrinsics.c new file mode 100644 index 00000000..17a33eed --- /dev/null +++ b/Sources/LibPNG/arm/filter_neon_intrinsics.c @@ -0,0 +1,402 @@ + +/* filter_neon_intrinsics.c - NEON optimised filter functions + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2014,2016 Glenn Randers-Pehrson + * Written by James Yu , October 2013. + * Based on filter_neon.S, written by Mans Rullgard, 2011. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* This code requires -mfpu=neon on the command line: */ +#if PNG_ARM_NEON_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */ + +#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) +# include +#else +# include +#endif + +/* libpng row pointers are not necessarily aligned to any particular boundary, + * however this code will only work with appropriate alignment. arm/arm_init.c + * checks for this (and will not compile unless it is done). This code uses + * variants of png_aligncast to avoid compiler warnings. + */ +#define png_ptr(type,pointer) png_aligncast(type *,pointer) +#define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer) + +/* The following relies on a variable 'temp_pointer' being declared with type + * 'type'. This is written this way just to hide the GCC strict aliasing + * warning; note that the code is safe because there never is an alias between + * the input and output pointers. + * + * When compiling with MSVC ARM64, the png_ldr macro can't be passed directly + * to vst4_lane_u32, because of an internal compiler error inside MSVC. + * To avoid this compiler bug, we use a temporary variable (vdest_val) to store + * the result of png_ldr. + */ +#define png_ldr(type,pointer)\ + (temp_pointer = png_ptr(type,pointer), *temp_pointer) + +#if PNG_ARM_NEON_OPT > 0 + +void +png_read_filter_row_up_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + png_debug(1, "in png_read_filter_row_up_neon"); + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint8x16_t qrp, qpp; + + qrp = vld1q_u8(rp); + qpp = vld1q_u8(pp); + qrp = vaddq_u8(qrp, qpp); + vst1q_u8(rp, qrp); + } +} + +void +png_read_filter_row_sub3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp = vld1q_u8(rp); + uint8x8x2_t *vrpt = png_ptr(uint8x8x2_t, &vtmp); + uint8x8x2_t vrp = *vrpt; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + png_debug(1, "in png_read_filter_row_sub3_neon"); + + for (; rp < rp_stop;) + { + uint8x8_t vtmp1, vtmp2; + uint32x2_t *temp_pointer; + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); + vtmp2 = vext_u8(vrp.val[0], vrp.val[1], 6); + vdest.val[1] = vadd_u8(vdest.val[0], vtmp1); + + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + vdest.val[2] = vadd_u8(vdest.val[1], vtmp2); + vdest.val[3] = vadd_u8(vdest.val[2], vtmp1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t, &vtmp); + vrp = *vrpt; + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } + + PNG_UNUSED(prev_row) +} + +void +png_read_filter_row_sub4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + png_debug(1, "in png_read_filter_row_sub4_neon"); + + for (; rp < rp_stop; rp += 16) + { + uint32x2x4_t vtmp = vld4_u32(png_ptr(uint32_t,rp)); + uint8x8x4_t *vrpt = png_ptr(uint8x8x4_t,&vtmp); + uint8x8x4_t vrp = *vrpt; + uint32x2x4_t *temp_pointer; + uint32x2x4_t vdest_val; + + vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[0], vrp.val[1]); + vdest.val[2] = vadd_u8(vdest.val[1], vrp.val[2]); + vdest.val[3] = vadd_u8(vdest.val[2], vrp.val[3]); + + vdest_val = png_ldr(uint32x2x4_t, &vdest); + vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0); + } + + PNG_UNUSED(prev_row) +} + +void +png_read_filter_row_avg3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_const_bytep pp = prev_row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp; + uint8x8x2_t *vrpt; + uint8x8x2_t vrp; + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + vtmp = vld1q_u8(rp); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + png_debug(1, "in png_read_filter_row_avg3_neon"); + + for (; rp < rp_stop; pp += 12) + { + uint8x8_t vtmp1, vtmp2, vtmp3; + + uint8x8x2_t *vppt; + uint8x8x2_t vpp; + + uint32x2_t *temp_pointer; + + vtmp = vld1q_u8(pp); + vppt = png_ptr(uint8x8x2_t,&vtmp); + vpp = *vppt; + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); + vtmp3 = vext_u8(vrp.val[0], vrp.val[1], 6); + vdest.val[1] = vhadd_u8(vdest.val[0], vtmp2); + vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); + + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 6); + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + vdest.val[2] = vhadd_u8(vdest.val[1], vtmp2); + vdest.val[2] = vadd_u8(vdest.val[2], vtmp3); + + vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); + + vdest.val[3] = vhadd_u8(vdest.val[2], vtmp2); + vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } +} + +void +png_read_filter_row_avg4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + png_debug(1, "in png_read_filter_row_avg4_neon"); + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint32x2x4_t vtmp; + uint8x8x4_t *vrpt, *vppt; + uint8x8x4_t vrp, vpp; + uint32x2x4_t *temp_pointer; + uint32x2x4_t vdest_val; + + vtmp = vld4_u32(png_ptr(uint32_t,rp)); + vrpt = png_ptr(uint8x8x4_t,&vtmp); + vrp = *vrpt; + vtmp = vld4_u32(png_ptrc(uint32_t,pp)); + vppt = png_ptr(uint8x8x4_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + vdest.val[1] = vhadd_u8(vdest.val[0], vpp.val[1]); + vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); + vdest.val[2] = vhadd_u8(vdest.val[1], vpp.val[2]); + vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); + vdest.val[3] = vhadd_u8(vdest.val[2], vpp.val[3]); + vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); + + vdest_val = png_ldr(uint32x2x4_t, &vdest); + vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0); + } +} + +static uint8x8_t +paeth(uint8x8_t a, uint8x8_t b, uint8x8_t c) +{ + uint8x8_t d, e; + uint16x8_t p1, pa, pb, pc; + + p1 = vaddl_u8(a, b); /* a + b */ + pc = vaddl_u8(c, c); /* c * 2 */ + pa = vabdl_u8(b, c); /* pa */ + pb = vabdl_u8(a, c); /* pb */ + pc = vabdq_u16(p1, pc); /* pc */ + + p1 = vcleq_u16(pa, pb); /* pa <= pb */ + pa = vcleq_u16(pa, pc); /* pa <= pc */ + pb = vcleq_u16(pb, pc); /* pb <= pc */ + + p1 = vandq_u16(p1, pa); /* pa <= pb && pa <= pc */ + + d = vmovn_u16(pb); + e = vmovn_u16(p1); + + d = vbsl_u8(d, b, c); + e = vbsl_u8(e, a, d); + + return e; +} + +void +png_read_filter_row_paeth3_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_const_bytep pp = prev_row; + png_bytep rp_stop = row + row_info->rowbytes; + + uint8x16_t vtmp; + uint8x8x2_t *vrpt; + uint8x8x2_t vrp; + uint8x8_t vlast = vdup_n_u8(0); + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + vtmp = vld1q_u8(rp); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + png_debug(1, "in png_read_filter_row_paeth3_neon"); + + for (; rp < rp_stop; pp += 12) + { + uint8x8x2_t *vppt; + uint8x8x2_t vpp; + uint8x8_t vtmp1, vtmp2, vtmp3; + uint32x2_t *temp_pointer; + + vtmp = vld1q_u8(pp); + vppt = png_ptr(uint8x8x2_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3); + vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3); + vdest.val[1] = paeth(vdest.val[0], vtmp2, vpp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[1], vtmp1); + + vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6); + vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6); + vdest.val[2] = paeth(vdest.val[1], vtmp3, vtmp2); + vdest.val[2] = vadd_u8(vdest.val[2], vtmp1); + + vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1); + vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1); + + vtmp = vld1q_u8(rp + 12); + vrpt = png_ptr(uint8x8x2_t,&vtmp); + vrp = *vrpt; + + vdest.val[3] = paeth(vdest.val[2], vtmp2, vtmp3); + vdest.val[3] = vadd_u8(vdest.val[3], vtmp1); + + vlast = vtmp2; + + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0); + rp += 3; + vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0); + rp += 3; + } +} + +void +png_read_filter_row_paeth4_neon(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp = row; + png_bytep rp_stop = row + row_info->rowbytes; + png_const_bytep pp = prev_row; + + uint8x8_t vlast = vdup_n_u8(0); + uint8x8x4_t vdest; + vdest.val[3] = vdup_n_u8(0); + + png_debug(1, "in png_read_filter_row_paeth4_neon"); + + for (; rp < rp_stop; rp += 16, pp += 16) + { + uint32x2x4_t vtmp; + uint8x8x4_t *vrpt, *vppt; + uint8x8x4_t vrp, vpp; + uint32x2x4_t *temp_pointer; + uint32x2x4_t vdest_val; + + vtmp = vld4_u32(png_ptr(uint32_t,rp)); + vrpt = png_ptr(uint8x8x4_t,&vtmp); + vrp = *vrpt; + vtmp = vld4_u32(png_ptrc(uint32_t,pp)); + vppt = png_ptr(uint8x8x4_t,&vtmp); + vpp = *vppt; + + vdest.val[0] = paeth(vdest.val[3], vpp.val[0], vlast); + vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]); + vdest.val[1] = paeth(vdest.val[0], vpp.val[1], vpp.val[0]); + vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]); + vdest.val[2] = paeth(vdest.val[1], vpp.val[2], vpp.val[1]); + vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]); + vdest.val[3] = paeth(vdest.val[2], vpp.val[3], vpp.val[2]); + vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]); + + vlast = vpp.val[3]; + + vdest_val = png_ldr(uint32x2x4_t, &vdest); + vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0); + } +} + +#endif /* PNG_ARM_NEON_OPT > 0 */ +#endif /* PNG_ARM_NEON_IMPLEMENTATION == 1 (intrinsics) */ +#endif /* READ */ \ No newline at end of file diff --git a/Sources/LibPNG/arm/palette_neon_intrinsics.c b/Sources/LibPNG/arm/palette_neon_intrinsics.c new file mode 100644 index 00000000..07cf6008 --- /dev/null +++ b/Sources/LibPNG/arm/palette_neon_intrinsics.c @@ -0,0 +1,151 @@ + +/* palette_neon_intrinsics.c - NEON optimised palette expansion functions + * + * Copyright (c) 2018-2019 Cosmin Truta + * Copyright (c) 2017-2018 Arm Holdings. All rights reserved. + * Written by Richard Townsend , February 2017. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "../pngpriv.h" + +#if PNG_ARM_NEON_IMPLEMENTATION == 1 || defined(WITH_ARCH) + +#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) +# include +#else +# include +#endif + +/* Build an RGBA8 palette from the separate RGB and alpha palettes. */ +void +png_riffle_palette_neon(png_structrp png_ptr) +{ + png_const_colorp palette = png_ptr->palette; + png_bytep riffled_palette = png_ptr->riffled_palette; + png_const_bytep trans_alpha = png_ptr->trans_alpha; + int num_trans = png_ptr->num_trans; + int i; + + /* Initially black, opaque. */ + uint8x16x4_t w = {{ + vdupq_n_u8(0x00), + vdupq_n_u8(0x00), + vdupq_n_u8(0x00), + vdupq_n_u8(0xff), + }}; + + png_debug(1, "in png_riffle_palette_neon"); + + /* First, riffle the RGB colours into an RGBA8 palette. + * The alpha component is set to opaque for now. + */ + for (i = 0; i < 256; i += 16) + { + uint8x16x3_t v = vld3q_u8((png_const_bytep)(palette + i)); + w.val[0] = v.val[0]; + w.val[1] = v.val[1]; + w.val[2] = v.val[2]; + vst4q_u8(riffled_palette + (i << 2), w); + } + + /* Fix up the missing transparency values. */ + for (i = 0; i < num_trans; i++) + riffled_palette[(i << 2) + 3] = trans_alpha[i]; +} + +/* Expands a palettized row into RGBA8. */ +int +png_do_expand_palette_rgba8_neon(png_structrp png_ptr, png_row_infop row_info, + png_const_bytep row, png_bytepp ssp, png_bytepp ddp) +{ + png_uint_32 row_width = row_info->width; + const png_uint_32 *riffled_palette = + (const png_uint_32 *)png_ptr->riffled_palette; + const png_uint_32 pixels_per_chunk = 4; + png_uint_32 i; + + png_debug(1, "in png_do_expand_palette_rgba8_neon"); + + PNG_UNUSED(row) + if (row_width < pixels_per_chunk) + return 0; + + /* This function originally gets the last byte of the output row. + * The NEON part writes forward from a given position, so we have + * to seek this back by 4 pixels x 4 bytes. + */ + *ddp = *ddp - ((pixels_per_chunk * sizeof(png_uint_32)) - 1); + + for (i = 0; i < row_width; i += pixels_per_chunk) + { + uint32x4_t cur; + png_bytep sp = *ssp - i, dp = *ddp - (i << 2); + cur = vld1q_dup_u32 (riffled_palette + *(sp - 3)); + cur = vld1q_lane_u32(riffled_palette + *(sp - 2), cur, 1); + cur = vld1q_lane_u32(riffled_palette + *(sp - 1), cur, 2); + cur = vld1q_lane_u32(riffled_palette + *(sp - 0), cur, 3); + vst1q_u32((void *)dp, cur); + } + if (i != row_width) + { + /* Remove the amount that wasn't processed. */ + i -= pixels_per_chunk; + } + + /* Decrement output pointers. */ + *ssp = *ssp - i; + *ddp = *ddp - (i << 2); + return i; +} + +/* Expands a palettized row into RGB8. */ +int +png_do_expand_palette_rgb8_neon(png_structrp png_ptr, png_row_infop row_info, + png_const_bytep row, png_bytepp ssp, png_bytepp ddp) +{ + png_uint_32 row_width = row_info->width; + png_const_bytep palette = (png_const_bytep)png_ptr->palette; + const png_uint_32 pixels_per_chunk = 8; + png_uint_32 i; + + png_debug(1, "in png_do_expand_palette_rgb8_neon"); + + PNG_UNUSED(row) + if (row_width <= pixels_per_chunk) + return 0; + + /* Seeking this back by 8 pixels x 3 bytes. */ + *ddp = *ddp - ((pixels_per_chunk * sizeof(png_color)) - 1); + + for (i = 0; i < row_width; i += pixels_per_chunk) + { + uint8x8x3_t cur; + png_bytep sp = *ssp - i, dp = *ddp - ((i << 1) + i); + cur = vld3_dup_u8(palette + sizeof(png_color) * (*(sp - 7))); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 6)), cur, 1); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 5)), cur, 2); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 4)), cur, 3); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 3)), cur, 4); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 2)), cur, 5); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 1)), cur, 6); + cur = vld3_lane_u8(palette + sizeof(png_color) * (*(sp - 0)), cur, 7); + vst3_u8((void *)dp, cur); + } + + if (i != row_width) + { + /* Remove the amount that wasn't processed. */ + i -= pixels_per_chunk; + } + + /* Decrement output pointers. */ + *ssp = *ssp - i; + *ddp = *ddp - ((i << 1) + i); + return i; +} + +#endif /* PNG_ARM_NEON_IMPLEMENTATION */ \ No newline at end of file diff --git a/Sources/LibPNG/include/png.h b/Sources/LibPNG/include/png.h index cfc48410..5c656c09 100644 --- a/Sources/LibPNG/include/png.h +++ b/Sources/LibPNG/include/png.h @@ -3199,7 +3199,7 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, * selected at run time. */ #ifdef PNG_SET_OPTION_SUPPORTED -#ifdef PNG_ARM_NEON_API_SUPPORTED +#if defined(PNG_ARM_NEON_API_SUPPORTED) || defined(WITH_ARM) # define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ #endif #define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ @@ -3208,7 +3208,7 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, # define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */ #endif #define PNG_IGNORE_ADLER32 8 -#ifdef PNG_POWERPC_VSX_API_SUPPORTED +#if defined(PNG_POWERPC_VSX_API_SUPPORTED) || defined(WITH_POWERPC) # define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions supported */ #endif #define PNG_OPTION_NEXT 12 /* Next option - numbers must be even */ diff --git a/Sources/LibPNG/intel/filter_sse2_intrinsics.c b/Sources/LibPNG/intel/filter_sse2_intrinsics.c new file mode 100644 index 00000000..e62baf1e --- /dev/null +++ b/Sources/LibPNG/intel/filter_sse2_intrinsics.c @@ -0,0 +1,391 @@ + +/* filter_sse2_intrinsics.c - SSE2 optimized filter functions + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2016-2017 Glenn Randers-Pehrson + * Written by Mike Klein and Matt Sarett + * Derived from arm/filter_neon_intrinsics.c + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +#if PNG_INTEL_SSE_IMPLEMENTATION > 0 + +#include + +/* Functions in this file look at most 3 pixels (a,b,c) to predict the 4th (d). + * They're positioned like this: + * prev: c b + * row: a d + * The Sub filter predicts d=a, Avg d=(a+b)/2, and Paeth predicts d to be + * whichever of a, b, or c is closest to p=a+b-c. + */ + +static __m128i load4(const void* p) { + int tmp; + memcpy(&tmp, p, sizeof(tmp)); + return _mm_cvtsi32_si128(tmp); +} + +static void store4(void* p, __m128i v) { + int tmp = _mm_cvtsi128_si32(v); + memcpy(p, &tmp, sizeof(int)); +} + +static __m128i load3(const void* p) { + png_uint_32 tmp = 0; + memcpy(&tmp, p, 3); + return _mm_cvtsi32_si128(tmp); +} + +static void store3(void* p, __m128i v) { + int tmp = _mm_cvtsi128_si32(v); + memcpy(p, &tmp, 3); +} + +void png_read_filter_row_sub3_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* The Sub filter predicts each pixel as the previous pixel, a. + * There is no pixel to the left of the first pixel. It's encoded directly. + * That works with our main loop if we just say that left pixel was zero. + */ + size_t rb; + + __m128i a, d = _mm_setzero_si128(); + + png_debug(1, "in png_read_filter_row_sub3_sse2"); + + rb = row_info->rowbytes; + while (rb >= 4) { + a = d; d = load4(row); + d = _mm_add_epi8(d, a); + store3(row, d); + + row += 3; + rb -= 3; + } + if (rb > 0) { + a = d; d = load3(row); + d = _mm_add_epi8(d, a); + store3(row, d); + + row += 3; + rb -= 3; + } + PNG_UNUSED(prev) +} + +void png_read_filter_row_sub4_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* The Sub filter predicts each pixel as the previous pixel, a. + * There is no pixel to the left of the first pixel. It's encoded directly. + * That works with our main loop if we just say that left pixel was zero. + */ + size_t rb; + + __m128i a, d = _mm_setzero_si128(); + + png_debug(1, "in png_read_filter_row_sub4_sse2"); + + rb = row_info->rowbytes+4; + while (rb > 4) { + a = d; d = load4(row); + d = _mm_add_epi8(d, a); + store4(row, d); + + row += 4; + rb -= 4; + } + PNG_UNUSED(prev) +} + +void png_read_filter_row_avg3_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* The Avg filter predicts each pixel as the (truncated) average of a and b. + * There's no pixel to the left of the first pixel. Luckily, it's + * predicted to be half of the pixel above it. So again, this works + * perfectly with our loop if we make sure a starts at zero. + */ + + size_t rb; + + const __m128i zero = _mm_setzero_si128(); + + __m128i b; + __m128i a, d = zero; + + png_debug(1, "in png_read_filter_row_avg3_sse2"); + rb = row_info->rowbytes; + while (rb >= 4) { + __m128i avg; + b = load4(prev); + a = d; d = load4(row ); + + /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */ + avg = _mm_avg_epu8(a,b); + /* ...but we can fix it up by subtracting off 1 if it rounded up. */ + avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b), + _mm_set1_epi8(1))); + d = _mm_add_epi8(d, avg); + store3(row, d); + + prev += 3; + row += 3; + rb -= 3; + } + if (rb > 0) { + __m128i avg; + b = load3(prev); + a = d; d = load3(row ); + + /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */ + avg = _mm_avg_epu8(a,b); + /* ...but we can fix it up by subtracting off 1 if it rounded up. */ + avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b), + _mm_set1_epi8(1))); + + d = _mm_add_epi8(d, avg); + store3(row, d); + + prev += 3; + row += 3; + rb -= 3; + } +} + +void png_read_filter_row_avg4_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* The Avg filter predicts each pixel as the (truncated) average of a and b. + * There's no pixel to the left of the first pixel. Luckily, it's + * predicted to be half of the pixel above it. So again, this works + * perfectly with our loop if we make sure a starts at zero. + */ + size_t rb; + const __m128i zero = _mm_setzero_si128(); + __m128i b; + __m128i a, d = zero; + + png_debug(1, "in png_read_filter_row_avg4_sse2"); + + rb = row_info->rowbytes+4; + while (rb > 4) { + __m128i avg; + b = load4(prev); + a = d; d = load4(row ); + + /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */ + avg = _mm_avg_epu8(a,b); + /* ...but we can fix it up by subtracting off 1 if it rounded up. */ + avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a,b), + _mm_set1_epi8(1))); + + d = _mm_add_epi8(d, avg); + store4(row, d); + + prev += 4; + row += 4; + rb -= 4; + } +} + +/* Returns |x| for 16-bit lanes. */ +static __m128i abs_i16(__m128i x) { +#if PNG_INTEL_SSE_IMPLEMENTATION >= 2 + return _mm_abs_epi16(x); +#else + /* Read this all as, return x<0 ? -x : x. + * To negate two's complement, you flip all the bits then add 1. + */ + __m128i is_negative = _mm_cmplt_epi16(x, _mm_setzero_si128()); + + /* Flip negative lanes. */ + x = _mm_xor_si128(x, is_negative); + + /* +1 to negative lanes, else +0. */ + x = _mm_sub_epi16(x, is_negative); + return x; +#endif +} + +/* Bytewise c ? t : e. */ +static __m128i if_then_else(__m128i c, __m128i t, __m128i e) { +#if PNG_INTEL_SSE_IMPLEMENTATION >= 3 + return _mm_blendv_epi8(e,t,c); +#else + return _mm_or_si128(_mm_and_si128(c, t), _mm_andnot_si128(c, e)); +#endif +} + +void png_read_filter_row_paeth3_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* Paeth tries to predict pixel d using the pixel to the left of it, a, + * and two pixels from the previous row, b and c: + * prev: c b + * row: a d + * The Paeth function predicts d to be whichever of a, b, or c is nearest to + * p=a+b-c. + * + * The first pixel has no left context, and so uses an Up filter, p = b. + * This works naturally with our main loop's p = a+b-c if we force a and c + * to zero. + * Here we zero b and d, which become c and a respectively at the start of + * the loop. + */ + size_t rb; + const __m128i zero = _mm_setzero_si128(); + __m128i c, b = zero, + a, d = zero; + + png_debug(1, "in png_read_filter_row_paeth3_sse2"); + + rb = row_info->rowbytes; + while (rb >= 4) { + /* It's easiest to do this math (particularly, deal with pc) with 16-bit + * intermediates. + */ + __m128i pa,pb,pc,smallest,nearest; + c = b; b = _mm_unpacklo_epi8(load4(prev), zero); + a = d; d = _mm_unpacklo_epi8(load4(row ), zero); + + /* (p-a) == (a+b-c - a) == (b-c) */ + + pa = _mm_sub_epi16(b,c); + + /* (p-b) == (a+b-c - b) == (a-c) */ + pb = _mm_sub_epi16(a,c); + + /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */ + pc = _mm_add_epi16(pa,pb); + + pa = abs_i16(pa); /* |p-a| */ + pb = abs_i16(pb); /* |p-b| */ + pc = abs_i16(pc); /* |p-c| */ + + smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb)); + + /* Paeth breaks ties favoring a over b over c. */ + nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a, + if_then_else(_mm_cmpeq_epi16(smallest, pb), b, + c)); + + /* Note `_epi8`: we need addition to wrap modulo 255. */ + d = _mm_add_epi8(d, nearest); + store3(row, _mm_packus_epi16(d,d)); + + prev += 3; + row += 3; + rb -= 3; + } + if (rb > 0) { + /* It's easiest to do this math (particularly, deal with pc) with 16-bit + * intermediates. + */ + __m128i pa,pb,pc,smallest,nearest; + c = b; b = _mm_unpacklo_epi8(load3(prev), zero); + a = d; d = _mm_unpacklo_epi8(load3(row ), zero); + + /* (p-a) == (a+b-c - a) == (b-c) */ + pa = _mm_sub_epi16(b,c); + + /* (p-b) == (a+b-c - b) == (a-c) */ + pb = _mm_sub_epi16(a,c); + + /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */ + pc = _mm_add_epi16(pa,pb); + + pa = abs_i16(pa); /* |p-a| */ + pb = abs_i16(pb); /* |p-b| */ + pc = abs_i16(pc); /* |p-c| */ + + smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb)); + + /* Paeth breaks ties favoring a over b over c. */ + nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a, + if_then_else(_mm_cmpeq_epi16(smallest, pb), b, + c)); + + /* Note `_epi8`: we need addition to wrap modulo 255. */ + d = _mm_add_epi8(d, nearest); + store3(row, _mm_packus_epi16(d,d)); + + prev += 3; + row += 3; + rb -= 3; + } +} + +void png_read_filter_row_paeth4_sse2(png_row_infop row_info, png_bytep row, + png_const_bytep prev) +{ + /* Paeth tries to predict pixel d using the pixel to the left of it, a, + * and two pixels from the previous row, b and c: + * prev: c b + * row: a d + * The Paeth function predicts d to be whichever of a, b, or c is nearest to + * p=a+b-c. + * + * The first pixel has no left context, and so uses an Up filter, p = b. + * This works naturally with our main loop's p = a+b-c if we force a and c + * to zero. + * Here we zero b and d, which become c and a respectively at the start of + * the loop. + */ + size_t rb; + const __m128i zero = _mm_setzero_si128(); + __m128i pa,pb,pc,smallest,nearest; + __m128i c, b = zero, + a, d = zero; + + png_debug(1, "in png_read_filter_row_paeth4_sse2"); + + rb = row_info->rowbytes+4; + while (rb > 4) { + /* It's easiest to do this math (particularly, deal with pc) with 16-bit + * intermediates. + */ + c = b; b = _mm_unpacklo_epi8(load4(prev), zero); + a = d; d = _mm_unpacklo_epi8(load4(row ), zero); + + /* (p-a) == (a+b-c - a) == (b-c) */ + pa = _mm_sub_epi16(b,c); + + /* (p-b) == (a+b-c - b) == (a-c) */ + pb = _mm_sub_epi16(a,c); + + /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */ + pc = _mm_add_epi16(pa,pb); + + pa = abs_i16(pa); /* |p-a| */ + pb = abs_i16(pb); /* |p-b| */ + pc = abs_i16(pc); /* |p-c| */ + + smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb)); + + /* Paeth breaks ties favoring a over b over c. */ + nearest = if_then_else(_mm_cmpeq_epi16(smallest, pa), a, + if_then_else(_mm_cmpeq_epi16(smallest, pb), b, + c)); + + /* Note `_epi8`: we need addition to wrap modulo 255. */ + d = _mm_add_epi8(d, nearest); + store4(row, _mm_packus_epi16(d,d)); + + prev += 4; + row += 4; + rb -= 4; + } +} + +#endif /* PNG_INTEL_SSE_IMPLEMENTATION > 0 */ +#endif /* READ */ \ No newline at end of file diff --git a/Sources/LibPNG/intel/intel_init.c b/Sources/LibPNG/intel/intel_init.c new file mode 100644 index 00000000..7e3db35c --- /dev/null +++ b/Sources/LibPNG/intel/intel_init.c @@ -0,0 +1,52 @@ + +/* intel_init.c - SSE2 optimized filter functions + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2016-2017 Glenn Randers-Pehrson + * Written by Mike Klein and Matt Sarett, Google, Inc. + * Derived from arm/arm_init.c + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED +#if PNG_INTEL_SSE_IMPLEMENTATION > 0 + +void +png_init_filter_functions_sse2(png_structp pp, unsigned int bpp) +{ + /* The techniques used to implement each of these filters in SSE operate on + * one pixel at a time. + * So they generally speed up 3bpp images about 3x, 4bpp images about 4x. + * They can scale up to 6 and 8 bpp images and down to 2 bpp images, + * but they'd not likely have any benefit for 1bpp images. + * Most of these can be implemented using only MMX and 64-bit registers, + * but they end up a bit slower than using the equally-ubiquitous SSE2. + */ + png_debug(1, "in png_init_filter_functions_sse2"); + if (bpp == 3) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_sse2; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_sse2; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth3_sse2; + } + else if (bpp == 4) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_sse2; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_sse2; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth4_sse2; + } + + /* No need optimize PNG_FILTER_VALUE_UP. The compiler should + * autovectorize. + */ +} + +#endif /* PNG_INTEL_SSE_IMPLEMENTATION > 0 */ +#endif /* PNG_READ_SUPPORTED */ \ No newline at end of file diff --git a/Sources/LibPNG/pngpriv.h b/Sources/LibPNG/pngpriv.h index 7c19373f..c7de1bad 100644 --- a/Sources/LibPNG/pngpriv.h +++ b/Sources/LibPNG/pngpriv.h @@ -128,7 +128,7 @@ * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS. */ # if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ - defined(PNG_ALIGNED_MEMORY_SUPPORTED) + (defined(PNG_ALIGNED_MEMORY_SUPPORTED) || defined(WITH_ARM)) # define PNG_ARM_NEON_OPT 2 # else # define PNG_ARM_NEON_OPT 0 @@ -2089,7 +2089,7 @@ PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. */ -# if PNG_ARM_NEON_OPT > 0 +# if PNG_ARM_NEON_OPT > 0 || defined(WITH_NEON) PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif @@ -2099,7 +2099,7 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif -# if PNG_INTEL_SSE_IMPLEMENTATION > 0 +# if PNG_INTEL_SSE_IMPLEMENTATION > 0 || defined(WITH_INTEL) PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); # endif diff --git a/Sources/LibPNG/powerpc/filter_vsx_intrinsics.c b/Sources/LibPNG/powerpc/filter_vsx_intrinsics.c new file mode 100644 index 00000000..91f9520b --- /dev/null +++ b/Sources/LibPNG/powerpc/filter_vsx_intrinsics.c @@ -0,0 +1,768 @@ +/* filter_vsx_intrinsics.c - PowerPC optimised filter functions + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2017 Glenn Randers-Pehrson + * Written by Vadim Barkov, 2017. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +#include +#include +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +/* This code requires -maltivec and -mvsx on the command line: */ +#if PNG_POWERPC_VSX_IMPLEMENTATION == 1 /* intrinsics code from pngpriv.h */ + +#include + +#if PNG_POWERPC_VSX_OPT > 0 + +#ifndef __VSX__ +# error "This code requires VSX support (POWER7 and later). Please provide -mvsx compiler flag." +#endif + +#define vec_ld_unaligned(vec,data) vec = vec_vsx_ld(0,data) +#define vec_st_unaligned(vec,data) vec_vsx_st(vec,0,data) + + +/* Functions in this file look at most 3 pixels (a,b,c) to predict the 4th (d). + * They're positioned like this: + * prev: c b + * row: a d + * The Sub filter predicts d=a, Avg d=(a+b)/2, and Paeth predicts d to be + * whichever of a, b, or c is closest to p=a+b-c. + * ( this is taken from ../intel/filter_sse2_intrinsics.c ) + */ + +#define vsx_declare_common_vars(row_info,row,prev_row,offset) \ + png_byte i;\ + png_bytep rp = row + offset;\ + png_const_bytep pp = prev_row;\ + size_t unaligned_top = 16 - (((size_t)rp % 16));\ + size_t istop;\ + if(unaligned_top == 16)\ + unaligned_top = 0;\ + istop = row_info->rowbytes;\ + if((unaligned_top < istop))\ + istop -= unaligned_top;\ + else{\ + unaligned_top = istop;\ + istop = 0;\ + } + +void png_read_filter_row_up_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + vector unsigned char rp_vec; + vector unsigned char pp_vec; + vsx_declare_common_vars(row_info,row,prev_row,0) + + /* Altivec operations require 16-byte aligned data + * but input can be unaligned. So we calculate + * unaligned part as usual. + */ + for (i = 0; i < unaligned_top; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + /* Using SIMD while we can */ + while( istop >= 16 ) + { + rp_vec = vec_ld(0,rp); + vec_ld_unaligned(pp_vec,pp); + + rp_vec = vec_add(rp_vec,pp_vec); + + vec_st(rp_vec,0,rp); + + pp += 16; + rp += 16; + istop -= 16; + } + + if(istop > 0) + { + /* If byte count of row is not divisible by 16 + * we will process remaining part as usual + */ + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +} + +static const vector unsigned char VSX_LEFTSHIFTED1_4 = {16,16,16,16, 0, 1, 2, 3,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_LEFTSHIFTED2_4 = {16,16,16,16,16,16,16,16, 4, 5, 6, 7,16,16,16,16}; +static const vector unsigned char VSX_LEFTSHIFTED3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 8, 9,10,11}; + +static const vector unsigned char VSX_LEFTSHIFTED1_3 = {16,16,16, 0, 1, 2,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_LEFTSHIFTED2_3 = {16,16,16,16,16,16, 3, 4, 5,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_LEFTSHIFTED3_3 = {16,16,16,16,16,16,16,16,16, 6, 7, 8,16,16,16,16}; +static const vector unsigned char VSX_LEFTSHIFTED4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 9,10,11,16}; + +static const vector unsigned char VSX_NOT_SHIFTED1_4 = {16,16,16,16, 4, 5, 6, 7,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_NOT_SHIFTED2_4 = {16,16,16,16,16,16,16,16, 8, 9,10,11,16,16,16,16}; +static const vector unsigned char VSX_NOT_SHIFTED3_4 = {16,16,16,16,16,16,16,16,16,16,16,16,12,13,14,15}; + +static const vector unsigned char VSX_NOT_SHIFTED1_3 = {16,16,16, 3, 4, 5,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_NOT_SHIFTED2_3 = {16,16,16,16,16,16, 6, 7, 8,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_NOT_SHIFTED3_3 = {16,16,16,16,16,16,16,16,16, 9,10,11,16,16,16,16}; +static const vector unsigned char VSX_NOT_SHIFTED4_3 = {16,16,16,16,16,16,16,16,16,16,16,16,12,13,14,16}; + +static const vector unsigned char VSX_CHAR_ZERO = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +#ifdef __LITTLE_ENDIAN__ + +static const vector unsigned char VSX_CHAR_TO_SHORT1_4 = { 4,16, 5,16, 6,16, 7,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT2_4 = { 8,16, 9,16,10,16,11,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT3_4 = {12,16,13,16,14,16,15,16,16,16,16,16,16,16,16,16}; + +static const vector unsigned char VSX_SHORT_TO_CHAR1_4 = {16,16,16,16, 0, 2, 4, 6,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR2_4 = {16,16,16,16,16,16,16,16, 0, 2, 4, 6,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 0, 2, 4, 6}; + +static const vector unsigned char VSX_CHAR_TO_SHORT1_3 = { 3,16, 4,16, 5,16,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT2_3 = { 6,16, 7,16, 8,16,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT3_3 = { 9,16,10,16,11,16,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT4_3 = {12,16,13,16,14,16,16,16,16,16,16,16,16,16,16,16}; + +static const vector unsigned char VSX_SHORT_TO_CHAR1_3 = {16,16,16, 0, 2, 4,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR2_3 = {16,16,16,16,16,16, 0, 2, 4,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR3_3 = {16,16,16,16,16,16,16,16,16, 0, 2, 4,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 0, 2, 4,16}; + +#elif defined(__BIG_ENDIAN__) + +static const vector unsigned char VSX_CHAR_TO_SHORT1_4 = {16, 4,16, 5,16, 6,16, 7,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT2_4 = {16, 8,16, 9,16,10,16,11,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT3_4 = {16,12,16,13,16,14,16,15,16,16,16,16,16,16,16,16}; + +static const vector unsigned char VSX_SHORT_TO_CHAR1_4 = {16,16,16,16, 1, 3, 5, 7,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR2_4 = {16,16,16,16,16,16,16,16, 1, 3, 5, 7,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR3_4 = {16,16,16,16,16,16,16,16,16,16,16,16, 1, 3, 5, 7}; + +static const vector unsigned char VSX_CHAR_TO_SHORT1_3 = {16, 3,16, 4,16, 5,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT2_3 = {16, 6,16, 7,16, 8,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT3_3 = {16, 9,16,10,16,11,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_CHAR_TO_SHORT4_3 = {16,12,16,13,16,14,16,16,16,16,16,16,16,16,16,16}; + +static const vector unsigned char VSX_SHORT_TO_CHAR1_3 = {16,16,16, 1, 3, 5,16,16,16,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR2_3 = {16,16,16,16,16,16, 1, 3, 5,16,16,16,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR3_3 = {16,16,16,16,16,16,16,16,16, 1, 3, 5,16,16,16,16}; +static const vector unsigned char VSX_SHORT_TO_CHAR4_3 = {16,16,16,16,16,16,16,16,16,16,16,16, 1, 3, 5,16}; + +#endif + +#define vsx_char_to_short(vec,offset,bpp) (vector unsigned short)vec_perm((vec),VSX_CHAR_ZERO,VSX_CHAR_TO_SHORT##offset##_##bpp) +#define vsx_short_to_char(vec,offset,bpp) vec_perm(((vector unsigned char)(vec)),VSX_CHAR_ZERO,VSX_SHORT_TO_CHAR##offset##_##bpp) + +#ifdef PNG_USE_ABS +# define vsx_abs(number) abs(number) +#else +# define vsx_abs(number) (number > 0) ? (number) : -(number) +#endif + +void png_read_filter_row_sub4_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 4; + + vector unsigned char rp_vec; + vector unsigned char part_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + + PNG_UNUSED(pp) + + /* Altivec operations require 16-byte aligned data + * but input can be unaligned. So we calculate + * unaligned part as usual. + */ + for (i = 0; i < unaligned_top; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } + + /* Using SIMD while we can */ + while( istop >= 16 ) + { + for(i=0;i < bpp ; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } + rp -= bpp; + + rp_vec = vec_ld(0,rp); + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_4); + rp_vec = vec_add(rp_vec,part_vec); + + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_4); + rp_vec = vec_add(rp_vec,part_vec); + + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_4); + rp_vec = vec_add(rp_vec,part_vec); + + vec_st(rp_vec,0,rp); + + rp += 16; + istop -= 16; + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp - bpp))) & 0xff); + rp++; + } + +} + +void png_read_filter_row_sub3_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 3; + + vector unsigned char rp_vec; + vector unsigned char part_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + + PNG_UNUSED(pp) + + /* Altivec operations require 16-byte aligned data + * but input can be unaligned. So we calculate + * unaligned part as usual. + */ + for (i = 0; i < unaligned_top; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } + + /* Using SIMD while we can */ + while( istop >= 16 ) + { + for(i=0;i < bpp ; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } + rp -= bpp; + + rp_vec = vec_ld(0,rp); + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_3); + rp_vec = vec_add(rp_vec,part_vec); + + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_3); + rp_vec = vec_add(rp_vec,part_vec); + + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_3); + rp_vec = vec_add(rp_vec,part_vec); + + part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED4_3); + rp_vec = vec_add(rp_vec,part_vec); + + vec_st(rp_vec,0,rp); + rp += 15; + istop -= 16; + + /* Since 16 % bpp = 16 % 3 = 1, last element of array must + * be proceeded manually + */ + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +void png_read_filter_row_avg4_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 4; + + vector unsigned char rp_vec; + vector unsigned char pp_vec; + vector unsigned char pp_part_vec; + vector unsigned char rp_part_vec; + vector unsigned char avg_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + rp -= bpp; + if(istop >= bpp) + istop -= bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + /* Altivec operations require 16-byte aligned data + * but input can be unaligned. So we calculate + * unaligned part as usual. + */ + for (i = 0; i < unaligned_top; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } + + /* Using SIMD while we can */ + while( istop >= 16 ) + { + for(i=0;i < bpp ; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } + rp -= bpp; + pp -= bpp; + + vec_ld_unaligned(pp_vec,pp); + rp_vec = vec_ld(0,rp); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_4); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED1_4); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_4); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED2_4); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_4); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED3_4); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + vec_st(rp_vec,0,rp); + + rp += 16; + pp += 16; + istop -= 16; + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +void png_read_filter_row_avg3_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 3; + + vector unsigned char rp_vec; + vector unsigned char pp_vec; + vector unsigned char pp_part_vec; + vector unsigned char rp_part_vec; + vector unsigned char avg_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + rp -= bpp; + if(istop >= bpp) + istop -= bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + /* Altivec operations require 16-byte aligned data + * but input can be unaligned. So we calculate + * unaligned part as usual. + */ + for (i = 0; i < unaligned_top; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } + + /* Using SIMD while we can */ + while( istop >= 16 ) + { + for(i=0;i < bpp ; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } + rp -= bpp; + pp -= bpp; + + vec_ld_unaligned(pp_vec,pp); + rp_vec = vec_ld(0,rp); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED1_3); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED1_3); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED2_3); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED2_3); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED3_3); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED3_3); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + rp_part_vec = vec_perm(rp_vec,VSX_CHAR_ZERO,VSX_LEFTSHIFTED4_3); + pp_part_vec = vec_perm(pp_vec,VSX_CHAR_ZERO,VSX_NOT_SHIFTED4_3); + avg_vec = vec_avg(rp_part_vec,pp_part_vec); + avg_vec = vec_sub(avg_vec, vec_and(vec_xor(rp_part_vec,pp_part_vec),vec_splat_u8(1))); + rp_vec = vec_add(rp_vec,avg_vec); + + vec_st(rp_vec,0,rp); + + rp += 15; + pp += 15; + istop -= 16; + + /* Since 16 % bpp = 16 % 3 = 1, last element of array must + * be proceeded manually + */ + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + rp++; + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +/* Bytewise c ? t : e. */ +#define if_then_else(c,t,e) vec_sel(e,t,c) + +#define vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) {\ + c = *(pp - bpp);\ + a = *(rp - bpp);\ + b = *pp++;\ + p = b - c;\ + pc = a - c;\ + pa = vsx_abs(p);\ + pb = vsx_abs(pc);\ + pc = vsx_abs(p + pc);\ + if (pb < pa) pa = pb, a = b;\ + if (pc < pa) a = c;\ + a += *rp;\ + *rp++ = (png_byte)a;\ + } + +void png_read_filter_row_paeth4_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 4; + + int a, b, c, pa, pb, pc, p; + vector unsigned char rp_vec; + vector unsigned char pp_vec; + vector unsigned short a_vec,b_vec,c_vec,nearest_vec; + vector signed short pa_vec,pb_vec,pc_vec,smallest_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + rp -= bpp; + if(istop >= bpp) + istop -= bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + for(i = 0; i < bpp ; i++) + { + *rp = (png_byte)( *rp + *pp); + rp++; + pp++; + } + + for(i = 0; i < unaligned_top ; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } + + while( istop >= 16) + { + for(i = 0; i < bpp ; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } + + rp -= bpp; + pp -= bpp; + rp_vec = vec_ld(0,rp); + vec_ld_unaligned(pp_vec,pp); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_4),1,4); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED1_4),1,4); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_4),1,4); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,1,4))); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_4),2,4); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED2_4),2,4); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_4),2,4); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,2,4))); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_4),3,4); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED3_4),3,4); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_4),3,4); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,3,4))); + + vec_st(rp_vec,0,rp); + + rp += 16; + pp += 16; + istop -= 16; + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } +} + +void png_read_filter_row_paeth3_vsx(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_byte bpp = 3; + + int a, b, c, pa, pb, pc, p; + vector unsigned char rp_vec; + vector unsigned char pp_vec; + vector unsigned short a_vec,b_vec,c_vec,nearest_vec; + vector signed short pa_vec,pb_vec,pc_vec,smallest_vec; + + vsx_declare_common_vars(row_info,row,prev_row,bpp) + rp -= bpp; + if(istop >= bpp) + istop -= bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + for(i = 0; i < bpp ; i++) + { + *rp = (png_byte)( *rp + *pp); + rp++; + pp++; + } + + for(i = 0; i < unaligned_top ; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } + + while( istop >= 16) + { + for(i = 0; i < bpp ; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } + + rp -= bpp; + pp -= bpp; + rp_vec = vec_ld(0,rp); + vec_ld_unaligned(pp_vec,pp); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_3),1,3); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED1_3),1,3); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED1_3),1,3); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,1,3))); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_3),2,3); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED2_3),2,3); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED2_3),2,3); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,2,3))); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_3),3,3); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED3_3),3,3); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED3_3),3,3); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,3,3))); + + a_vec = vsx_char_to_short(vec_perm(rp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED4_3),4,3); + b_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_NOT_SHIFTED4_3),4,3); + c_vec = vsx_char_to_short(vec_perm(pp_vec , VSX_CHAR_ZERO , VSX_LEFTSHIFTED4_3),4,3); + pa_vec = (vector signed short) vec_sub(b_vec,c_vec); + pb_vec = (vector signed short) vec_sub(a_vec , c_vec); + pc_vec = vec_add(pa_vec,pb_vec); + pa_vec = vec_abs(pa_vec); + pb_vec = vec_abs(pb_vec); + pc_vec = vec_abs(pc_vec); + smallest_vec = vec_min(pc_vec, vec_min(pa_vec,pb_vec)); + nearest_vec = if_then_else( + vec_cmpeq(pa_vec,smallest_vec), + a_vec, + if_then_else( + vec_cmpeq(pb_vec,smallest_vec), + b_vec, + c_vec + ) + ); + rp_vec = vec_add(rp_vec,(vsx_short_to_char(nearest_vec,4,3))); + + vec_st(rp_vec,0,rp); + + rp += 15; + pp += 15; + istop -= 16; + + /* Since 16 % bpp = 16 % 3 = 1, last element of array must + * be proceeded manually + */ + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } + + if(istop > 0) + for (i = 0; i < istop % 16; i++) + { + vsx_paeth_process(rp,pp,a,b,c,pa,pb,pc,bpp) + } +} + +#endif /* PNG_POWERPC_VSX_OPT > 0 */ +#endif /* PNG_POWERPC_VSX_IMPLEMENTATION == 1 (intrinsics) */ +#endif /* READ */ \ No newline at end of file diff --git a/Sources/LibPNG/powerpc/powerpc_init.c b/Sources/LibPNG/powerpc/powerpc_init.c new file mode 100644 index 00000000..5f790eca --- /dev/null +++ b/Sources/LibPNG/powerpc/powerpc_init.c @@ -0,0 +1,126 @@ + +/* powerpc_init.c - POWERPC optimised filter functions + * + * Copyright (c) 2018 Cosmin Truta + * Copyright (c) 2017 Glenn Randers-Pehrson + * Written by Vadim Barkov, 2017. + * + * This code is released under the libpng license. + * For conditions of distribution and use, see the disclaimer + * and license in png.h + */ + +/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are + * called. + */ +#define _POSIX_SOURCE 1 + +#include +#include "../pngpriv.h" + +#ifdef PNG_READ_SUPPORTED + +#if PNG_POWERPC_VSX_OPT > 0 +#ifdef PNG_POWERPC_VSX_CHECK_SUPPORTED /* Do run-time checks */ +/* WARNING: it is strongly recommended that you do not build libpng with + * run-time checks for CPU features if at all possible. In the case of the PowerPC + * VSX instructions there is no processor-specific way of detecting the + * presence of the required support, therefore run-time detection is extremely + * OS specific. + * + * You may set the macro PNG_POWERPC_VSX_FILE to the file name of file containing + * a fragment of C source code which defines the png_have_vsx function. There + * are a number of implementations in contrib/powerpc-vsx, but the only one that + * has partial support is contrib/powerpc-vsx/linux.c - a generic Linux + * implementation which reads /proc/cpufino. + */ +#ifndef PNG_POWERPC_VSX_FILE +# ifdef __linux__ +# define PNG_POWERPC_VSX_FILE "contrib/powerpc-vsx/linux_aux.c" +# endif +#endif + +#ifdef PNG_POWERPC_VSX_FILE + +#include /* for sig_atomic_t */ +static int png_have_vsx(png_structp png_ptr); +#include PNG_POWERPC_VSX_FILE + +#else /* PNG_POWERPC_VSX_FILE */ +# error "PNG_POWERPC_VSX_FILE undefined: no support for run-time POWERPC VSX checks" +#endif /* PNG_POWERPC_VSX_FILE */ +#endif /* PNG_POWERPC_VSX_CHECK_SUPPORTED */ + +void +png_init_filter_functions_vsx(png_structp pp, unsigned int bpp) +{ + /* The switch statement is compiled in for POWERPC_VSX_API, the call to + * png_have_vsx is compiled in for POWERPC_VSX_CHECK. If both are defined + * the check is only performed if the API has not set the PowerPC option on + * or off explicitly. In this case the check controls what happens. + */ + +#ifdef PNG_POWERPC_VSX_API_SUPPORTED + switch ((pp->options >> PNG_POWERPC_VSX) & 3) + { + case PNG_OPTION_UNSET: + /* Allow the run-time check to execute if it has been enabled - + * thus both API and CHECK can be turned on. If it isn't supported + * this case will fall through to the 'default' below, which just + * returns. + */ +#endif /* PNG_POWERPC_VSX_API_SUPPORTED */ +#ifdef PNG_POWERPC_VSX_CHECK_SUPPORTED + { + static volatile sig_atomic_t no_vsx = -1; /* not checked */ + + if (no_vsx < 0) + no_vsx = !png_have_vsx(pp); + + if (no_vsx) + return; + } +#ifdef PNG_POWERPC_VSX_API_SUPPORTED + break; +#endif +#endif /* PNG_POWERPC_VSX_CHECK_SUPPORTED */ + +#ifdef PNG_POWERPC_VSX_API_SUPPORTED + default: /* OFF or INVALID */ + return; + + case PNG_OPTION_ON: + /* Option turned on */ + break; + } +#endif + + /* IMPORTANT: any new internal functions used here must be declared using + * PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the + * 'prefix' option to configure works: + * + * ./configure --with-libpng-prefix=foobar_ + * + * Verify you have got this right by running the above command, doing a build + * and examining pngprefix.h; it must contain a #define for every external + * function you add. (Notice that this happens automatically for the + * initialization function.) + */ + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_vsx; + + if (bpp == 3) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_vsx; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_vsx; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth3_vsx; + } + + else if (bpp == 4) + { + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_vsx; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_vsx; + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth4_vsx; + } +} +#endif /* PNG_POWERPC_VSX_OPT > 0 */ +#endif /* READ */ \ No newline at end of file diff --git a/Sources/MetaTBB/MetaTBB.swift b/Sources/MetaTBB/MetaTBB.swift new file mode 100644 index 00000000..463d793c --- /dev/null +++ b/Sources/MetaTBB/MetaTBB.swift @@ -0,0 +1,35 @@ +/* -------------------------------------------------------------- + * :: : M E T A V E R S E : :: + * -------------------------------------------------------------- + * This program is free software; you can redistribute it, and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Check out + * the GNU General Public License for more details. + * + * You should have received a copy for this software license, the + * GNU General Public License along with this program; or, if not + * write to the Free Software Foundation, Inc., to the address of + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) 2023 Wabi Foundation. All Rights Reserved. + * -------------------------------------------------------------- + * . x x x . o o o . x x x . : : : . o x o . : : : . + * -------------------------------------------------------------- */ + +/** + * # Metaversal Threading Building Blocks. + * + * Root of **OneTBB** (threading building blocks) + * dependency. */ +public class MetaTBB +{ + public static let shared = MetaTBB() + + public init() + {} +} diff --git a/Sources/OpenEXR/Imath/toFloat.cpp b/Sources/OpenEXR/Imath/toFloat.cpp index 20e750dc..243db974 100644 --- a/Sources/OpenEXR/Imath/toFloat.cpp +++ b/Sources/OpenEXR/Imath/toFloat.cpp @@ -97,34 +97,34 @@ halfToFloat (unsigned short y) // Main - prints the half-to-float lookup table //--------------------------------------------- -int -main() -{ - cout.precision (9); - cout.setf (ios_base::hex, ios_base::basefield); +// int +// main() +// { +// cout.precision (9); +// cout.setf (ios_base::hex, ios_base::basefield); - cout << "//\n" - "// This is an automatically generated file.\n" - "// Do not edit.\n" - "//\n\n"; +// cout << "//\n" +// "// This is an automatically generated file.\n" +// "// Do not edit.\n" +// "//\n\n"; - cout << "{\n "; +// cout << "{\n "; - const int iMax = (1 << 16); +// const int iMax = (1 << 16); - for (int i = 0; i < iMax; i++) - { - cout << "{0x" << setfill ('0') << setw (8) << halfToFloat (i) << "}, "; +// for (int i = 0; i < iMax; i++) +// { +// cout << "{0x" << setfill ('0') << setw (8) << halfToFloat (i) << "}, "; - if (i % 4 == 3) - { - cout << "\n"; +// if (i % 4 == 3) +// { +// cout << "\n"; - if (i < iMax - 1) - cout << " "; - } - } +// if (i < iMax - 1) +// cout << " "; +// } +// } - cout << "};\n"; - return 0; -} +// cout << "};\n"; +// return 0; +// } diff --git a/Sources/OpenEXR/OpenEXR/b44ExpLogTable.cpp b/Sources/OpenEXR/OpenEXR/b44ExpLogTable.cpp index eacb1611..7b9a6fa8 100644 --- a/Sources/OpenEXR/OpenEXR/b44ExpLogTable.cpp +++ b/Sources/OpenEXR/OpenEXR/b44ExpLogTable.cpp @@ -31,75 +31,75 @@ using namespace std; // Main - prints the half-to-float lookup table //--------------------------------------------- -int -main () -{ -#ifndef HAVE_IOS_BASE - cout.setf (ios::hex, ios::basefield); -#else - cout.setf (ios_base::hex, ios_base::basefield); -#endif - - cout << "//\n" - "// This is an automatically generated file.\n" - "// Do not edit.\n" - "//\n\n"; - - const int iMax = (1 << 16); - - cout << "const unsigned short expTable[] =\n" - "{\n" - " "; - - for (int i = 0; i < iMax; i++) - { - half h; - h.setBits (i); - - if (!h.isFinite ()) - h = 0; - else if (h >= 8 * log (HALF_MAX)) - h = HALF_MAX; - else - h = exp (h / 8); - - cout << "0x" << setfill ('0') << setw (4) << h.bits () << ", "; - - if (i % 8 == 7) - { - cout << "\n"; - - if (i < iMax - 1) cout << " "; - } - } - - cout << "};\n\n"; - - cout << "const unsigned short logTable[] =\n" - "{\n" - " "; - - for (int i = 0; i < iMax; i++) - { - half h; - h.setBits (i); - - if (!h.isFinite () || h < 0) - h = 0; - else - h = 8 * log (h); - - cout << "0x" << setfill ('0') << setw (4) << h.bits () << ", "; - - if (i % 8 == 7) - { - cout << "\n"; - - if (i < iMax - 1) cout << " "; - } - } - - cout << "};\n"; - - return 0; -} +// int +// main () +// { +// #ifndef HAVE_IOS_BASE +// cout.setf (ios::hex, ios::basefield); +// #else +// cout.setf (ios_base::hex, ios_base::basefield); +// #endif + +// cout << "//\n" +// "// This is an automatically generated file.\n" +// "// Do not edit.\n" +// "//\n\n"; + +// const int iMax = (1 << 16); + +// cout << "const unsigned short expTable[] =\n" +// "{\n" +// " "; + +// for (int i = 0; i < iMax; i++) +// { +// half h; +// h.setBits (i); + +// if (!h.isFinite ()) +// h = 0; +// else if (h >= 8 * log (HALF_MAX)) +// h = HALF_MAX; +// else +// h = exp (h / 8); + +// cout << "0x" << setfill ('0') << setw (4) << h.bits () << ", "; + +// if (i % 8 == 7) +// { +// cout << "\n"; + +// if (i < iMax - 1) cout << " "; +// } +// } + +// cout << "};\n\n"; + +// cout << "const unsigned short logTable[] =\n" +// "{\n" +// " "; + +// for (int i = 0; i < iMax; i++) +// { +// half h; +// h.setBits (i); + +// if (!h.isFinite () || h < 0) +// h = 0; +// else +// h = 8 * log (h); + +// cout << "0x" << setfill ('0') << setw (4) << h.bits () << ", "; + +// if (i % 8 == 7) +// { +// cout << "\n"; + +// if (i < iMax - 1) cout << " "; +// } +// } + +// cout << "};\n"; + +// return 0; +// } diff --git a/Sources/OpenEXR/OpenEXR/dwaLookups.cpp b/Sources/OpenEXR/OpenEXR/dwaLookups.cpp index 9f7f8108..2f281468 100644 --- a/Sources/OpenEXR/OpenEXR/dwaLookups.cpp +++ b/Sources/OpenEXR/OpenEXR/dwaLookups.cpp @@ -533,24 +533,24 @@ generateLutHeader () } } -int -main (int argc, char** argv) -{ - printf ("\n\n\n"); +// int +// main (int argc, char** argv) +// { +// printf ("\n\n\n"); - generateNoop (); +// generateNoop (); - printf ("\n\n\n"); +// printf ("\n\n\n"); - generateToLinear (); +// generateToLinear (); - printf ("\n\n\n"); +// printf ("\n\n\n"); - generateToNonlinear (); +// generateToNonlinear (); - printf ("\n\n\n"); +// printf ("\n\n\n"); - generateLutHeader (); +// generateLutHeader (); - return 0; -} +// return 0; +// } diff --git a/Sources/OpenImageIO/iconvert/iconvert.cpp b/Sources/OpenImageIO/iconvert/iconvert.cpp index 51f75a7e..f29382a4 100644 --- a/Sources/OpenImageIO/iconvert/iconvert.cpp +++ b/Sources/OpenImageIO/iconvert/iconvert.cpp @@ -504,28 +504,28 @@ convert_file(const std::string& in_filename, const std::string& out_filename) -int -main(int argc, char* argv[]) -{ - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - Filesystem::convert_native_arguments(argc, (const char**)argv); - getargs(argc, argv); - if (ap.aborted()) - return return_code; - - OIIO::attribute("threads", nthreads); - - bool ok = true; - - if (inplace) { - for (auto&& s : filenames) - ok &= convert_file(s, s); - } else { - ok = convert_file(filenames[0], filenames[1]); - } - shutdown(); - return ok ? EXIT_SUCCESS : EXIT_FAILURE; -} +// int +// main(int argc, char* argv[]) +// { +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// Filesystem::convert_native_arguments(argc, (const char**)argv); +// getargs(argc, argv); +// if (ap.aborted()) +// return return_code; + +// OIIO::attribute("threads", nthreads); + +// bool ok = true; + +// if (inplace) { +// for (auto&& s : filenames) +// ok &= convert_file(s, s); +// } else { +// ok = convert_file(filenames[0], filenames[1]); +// } +// shutdown(); +// return ok ? EXIT_SUCCESS : EXIT_FAILURE; +// } diff --git a/Sources/OpenImageIO/idiff/idiff.cpp b/Sources/OpenImageIO/idiff/idiff.cpp index c892b9d6..9756b482 100644 --- a/Sources/OpenImageIO/idiff/idiff.cpp +++ b/Sources/OpenImageIO/idiff/idiff.cpp @@ -170,235 +170,235 @@ print_subimage(ImageBuf& img0, int subimage, int miplevel) -int -main(int argc, char* argv[]) -{ - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - Filesystem::convert_native_arguments(argc, (const char**)argv); - ArgParse ap = getargs(argc, argv); - - std::vector filenames = ap["filename"].as_vec(); - if (filenames.size() != 2) { - print(stderr, "idiff: Must have two input filenames.\n"); - print(stderr, "> {}\n", Strutil::join(filenames, ", ")); - ap.usage(); - return EXIT_FAILURE; - } - bool verbose = ap["v"].get(); - bool quiet = ap["q"].get(); - bool compareall = ap["a"].get(); - bool outdiffonly = ap["od"].get(); - bool diffabs = ap["abs"].get(); - bool perceptual = ap["p"].get(); - std::string diffimage = ap["o"].get(); - float diffscale = ap["scale"].get(); - float failthresh = ap["fail"].get(); - float failrelative = ap["failrelative"].get(); - float failpercent = ap["failpercent"].get(); - float hardfail = ap["hardfail"].get(); - float warnthresh = ap["warn"].get(); - float warnrelative = ap["warnrelative"].get(); - float warnpercent = ap["warnpercent"].get(); - float hardwarn = ap["hardwarn"].get(); - int allowfailures = ap["allowfailures"].get(); - - if (!quiet) { - print("Comparing \"{}\" and \"{}\"\n", filenames[0], filenames[1]); - fflush(stdout); - } - - // Create a private ImageCache so we can customize its cache size - // and instruct it store everything internally as floats. - ImageCache* imagecache = ImageCache::create(true); - imagecache->attribute("forcefloat", 1); - if (sizeof(void*) == 4) // 32 bit or 64? - imagecache->attribute("max_memory_MB", 512.0); - else - imagecache->attribute("max_memory_MB", 2048.0); - imagecache->attribute("autotile", 256); - // force a full diff, even for files tagged with the same - // fingerprint, just in case some mistake has been made. - imagecache->attribute("deduplicate", 0); - - ImageBuf img0, img1; - if (!read_input(filenames[0], img0, imagecache) - || !read_input(filenames[1], img1, imagecache)) - return ErrFile; - // ImageSpec spec0 = img0.spec(); // stash it - - int ret = ErrOK; - for (int subimage = 0; subimage < img0.nsubimages(); ++subimage) { - if (subimage > 0 && !compareall) - break; - if (subimage >= img1.nsubimages()) - break; - - if (!read_input(filenames[0], img0, imagecache, subimage) - || !read_input(filenames[1], img1, imagecache, subimage)) { - print(stderr, "Failed to read subimage {}\n", subimage); - return ErrFile; - } - - if (img0.nmiplevels() != img1.nmiplevels()) { - if (!quiet) - print("Files do not match in their number of MIPmap levels\n"); - } - - for (int m = 0; m < img0.nmiplevels(); ++m) { - if (m > 0 && !compareall) - break; - if (m > 0 && img0.nmiplevels() != img1.nmiplevels()) { - print(stderr, - "Files do not match in their number of MIPmap levels\n"); - ret = ErrDifferentSize; - break; - } - - if (!read_input(filenames[0], img0, imagecache, subimage, m) - || !read_input(filenames[1], img1, imagecache, subimage, m)) - return ErrFile; - - if (img0.deep() != img1.deep()) { - print(stderr, - "One image contains deep data, the other does not\n"); - ret = ErrDifferentSize; - break; - } - - int npels = img0.spec().width * img0.spec().height - * img0.spec().depth; - if (npels == 0) - npels = 1; // Avoid divide by zero for 0x0 images - OIIO_ASSERT(img0.spec().format == TypeFloat); - - // Compare the two images. - // - auto cr = ImageBufAlgo::compare(img0, img1, failthresh, warnthresh, - failrelative, warnrelative); - - int yee_failures = 0; - if (perceptual && !img0.deep()) { - ImageBufAlgo::CompareResults cr; - yee_failures = ImageBufAlgo::compare_Yee(img0, img1, cr); - } - - if (cr.nfail <= imagesize_t(allowfailures)) { - // Pass if users set allowfailures and we are within that - // limit. - } else if (cr.nfail > (failpercent / 100.0 * npels) - || cr.maxerror > hardfail - || yee_failures > (failpercent / 100.0 * npels)) { - ret = ErrFail; - } else if (cr.nwarn > (warnpercent / 100.0 * npels) - || cr.maxerror > hardwarn) { - if (ret != ErrFail) - ret = ErrWarn; - } - - // Print the report - // - if (verbose || (ret != ErrOK && !quiet)) { - if (compareall) - print_subimage(img0, subimage, m); - print(" Mean error = "); - safe_double_print(cr.meanerror); - print(" RMS error = "); - safe_double_print(cr.rms_error); - print(" Peak SNR = "); - safe_double_print(cr.PSNR); - print(" Max error = {:g}", cr.maxerror); - if (cr.maxerror != 0) { - print(" @ ({}, {}", cr.maxx, cr.maxy); - if (img0.spec().depth > 1) - print(", {}", cr.maxz); - if (cr.maxc < (int)img0.spec().channelnames.size()) - print(", {})", img0.spec().channelnames[cr.maxc]); - else if (cr.maxc < (int)img1.spec().channelnames.size()) - print(", {})", img1.spec().channelnames[cr.maxc]); - else - print(", channel {})", cr.maxc); - if (!img0.deep()) { - print(" values are "); - for (int c = 0; c < img0.spec().nchannels; ++c) - print("{}{}", (c ? ", " : ""), - img0.getchannel(cr.maxx, cr.maxy, 0, c)); - ; - print(" vs "); - for (int c = 0; c < img1.spec().nchannels; ++c) - print("{}{}", (c ? ", " : ""), - img1.getchannel(cr.maxx, cr.maxy, 0, c)); - ; - } - } - print("\n"); -#if OIIO_MSVS_BEFORE_2015 - // When older Visual Studio is used, float values in - // scientific format are printed with three digit exponent. - // We change this behaviour to fit Linux way. - _set_output_format(_TWO_DIGIT_EXPONENT); -#endif - print(" {} pixels ({:1.3g}%) over {}\n", cr.nwarn, - (100.0 * cr.nwarn / npels), warnthresh); - print(" {} pixels ({:1.3g}%) over {}\n", cr.nfail, - (100.0 * cr.nfail / npels), failthresh); - if (perceptual) - print(" {} pixels ({:3g}%) failed the perceptual test\n", - yee_failures, (100.0 * yee_failures / npels)); - } - - // If the user requested that a difference image be output, - // do that. N.B. we only do this for the first subimage - // right now, because ImageBuf doesn't really know how to - // write subimages. - if (diffimage.size() && (cr.maxerror != 0 || !outdiffonly)) { - ImageBuf diff; - if (diffabs) - ImageBufAlgo::absdiff(diff, img0, img1); - else - ImageBufAlgo::sub(diff, img0, img1); - if (diffscale != 1.0f) - ImageBufAlgo::mul(diff, diff, diffscale); - diff.write(diffimage); - - // Clear diff image name so we only save the first - // non-matching subimage. - diffimage = ""; - } - } - } - - if (compareall && img0.nsubimages() != img1.nsubimages()) { - if (!quiet) - print(stderr, - "Images had differing numbers of subimages ({} vs {})\n", - img0.nsubimages(), img1.nsubimages()); - ret = ErrFail; - } - if (!compareall && (img0.nsubimages() > 1 || img1.nsubimages() > 1)) { - if (!quiet) - print( - "Only compared the first subimage (of {} and {}, respectively)\n", - img0.nsubimages(), img1.nsubimages()); - } - - if (ret == ErrOK) { - if (!quiet) - print("PASS\n"); - } else if (ret == ErrWarn) { - if (!quiet) - print("WARNING\n"); - } else if (ret) { - if (quiet) - print(stderr, "FAILURE\n"); - else - print("FAILURE\n"); - } - - imagecache->invalidate_all(true); - ImageCache::destroy(imagecache); - shutdown(); - return ret; -} +// int +// main(int argc, char* argv[]) +// { +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// Filesystem::convert_native_arguments(argc, (const char**)argv); +// ArgParse ap = getargs(argc, argv); + +// std::vector filenames = ap["filename"].as_vec(); +// if (filenames.size() != 2) { +// print(stderr, "idiff: Must have two input filenames.\n"); +// print(stderr, "> {}\n", Strutil::join(filenames, ", ")); +// ap.usage(); +// return EXIT_FAILURE; +// } +// bool verbose = ap["v"].get(); +// bool quiet = ap["q"].get(); +// bool compareall = ap["a"].get(); +// bool outdiffonly = ap["od"].get(); +// bool diffabs = ap["abs"].get(); +// bool perceptual = ap["p"].get(); +// std::string diffimage = ap["o"].get(); +// float diffscale = ap["scale"].get(); +// float failthresh = ap["fail"].get(); +// float failrelative = ap["failrelative"].get(); +// float failpercent = ap["failpercent"].get(); +// float hardfail = ap["hardfail"].get(); +// float warnthresh = ap["warn"].get(); +// float warnrelative = ap["warnrelative"].get(); +// float warnpercent = ap["warnpercent"].get(); +// float hardwarn = ap["hardwarn"].get(); +// int allowfailures = ap["allowfailures"].get(); + +// if (!quiet) { +// print("Comparing \"{}\" and \"{}\"\n", filenames[0], filenames[1]); +// fflush(stdout); +// } + +// // Create a private ImageCache so we can customize its cache size +// // and instruct it store everything internally as floats. +// ImageCache* imagecache = ImageCache::create(true); +// imagecache->attribute("forcefloat", 1); +// if (sizeof(void*) == 4) // 32 bit or 64? +// imagecache->attribute("max_memory_MB", 512.0); +// else +// imagecache->attribute("max_memory_MB", 2048.0); +// imagecache->attribute("autotile", 256); +// // force a full diff, even for files tagged with the same +// // fingerprint, just in case some mistake has been made. +// imagecache->attribute("deduplicate", 0); + +// ImageBuf img0, img1; +// if (!read_input(filenames[0], img0, imagecache) +// || !read_input(filenames[1], img1, imagecache)) +// return ErrFile; +// // ImageSpec spec0 = img0.spec(); // stash it + +// int ret = ErrOK; +// for (int subimage = 0; subimage < img0.nsubimages(); ++subimage) { +// if (subimage > 0 && !compareall) +// break; +// if (subimage >= img1.nsubimages()) +// break; + +// if (!read_input(filenames[0], img0, imagecache, subimage) +// || !read_input(filenames[1], img1, imagecache, subimage)) { +// print(stderr, "Failed to read subimage {}\n", subimage); +// return ErrFile; +// } + +// if (img0.nmiplevels() != img1.nmiplevels()) { +// if (!quiet) +// print("Files do not match in their number of MIPmap levels\n"); +// } + +// for (int m = 0; m < img0.nmiplevels(); ++m) { +// if (m > 0 && !compareall) +// break; +// if (m > 0 && img0.nmiplevels() != img1.nmiplevels()) { +// print(stderr, +// "Files do not match in their number of MIPmap levels\n"); +// ret = ErrDifferentSize; +// break; +// } + +// if (!read_input(filenames[0], img0, imagecache, subimage, m) +// || !read_input(filenames[1], img1, imagecache, subimage, m)) +// return ErrFile; + +// if (img0.deep() != img1.deep()) { +// print(stderr, +// "One image contains deep data, the other does not\n"); +// ret = ErrDifferentSize; +// break; +// } + +// int npels = img0.spec().width * img0.spec().height +// * img0.spec().depth; +// if (npels == 0) +// npels = 1; // Avoid divide by zero for 0x0 images +// OIIO_ASSERT(img0.spec().format == TypeFloat); + +// // Compare the two images. +// // +// auto cr = ImageBufAlgo::compare(img0, img1, failthresh, warnthresh, +// failrelative, warnrelative); + +// int yee_failures = 0; +// if (perceptual && !img0.deep()) { +// ImageBufAlgo::CompareResults cr; +// yee_failures = ImageBufAlgo::compare_Yee(img0, img1, cr); +// } + +// if (cr.nfail <= imagesize_t(allowfailures)) { +// // Pass if users set allowfailures and we are within that +// // limit. +// } else if (cr.nfail > (failpercent / 100.0 * npels) +// || cr.maxerror > hardfail +// || yee_failures > (failpercent / 100.0 * npels)) { +// ret = ErrFail; +// } else if (cr.nwarn > (warnpercent / 100.0 * npels) +// || cr.maxerror > hardwarn) { +// if (ret != ErrFail) +// ret = ErrWarn; +// } + +// // Print the report +// // +// if (verbose || (ret != ErrOK && !quiet)) { +// if (compareall) +// print_subimage(img0, subimage, m); +// print(" Mean error = "); +// safe_double_print(cr.meanerror); +// print(" RMS error = "); +// safe_double_print(cr.rms_error); +// print(" Peak SNR = "); +// safe_double_print(cr.PSNR); +// print(" Max error = {:g}", cr.maxerror); +// if (cr.maxerror != 0) { +// print(" @ ({}, {}", cr.maxx, cr.maxy); +// if (img0.spec().depth > 1) +// print(", {}", cr.maxz); +// if (cr.maxc < (int)img0.spec().channelnames.size()) +// print(", {})", img0.spec().channelnames[cr.maxc]); +// else if (cr.maxc < (int)img1.spec().channelnames.size()) +// print(", {})", img1.spec().channelnames[cr.maxc]); +// else +// print(", channel {})", cr.maxc); +// if (!img0.deep()) { +// print(" values are "); +// for (int c = 0; c < img0.spec().nchannels; ++c) +// print("{}{}", (c ? ", " : ""), +// img0.getchannel(cr.maxx, cr.maxy, 0, c)); +// ; +// print(" vs "); +// for (int c = 0; c < img1.spec().nchannels; ++c) +// print("{}{}", (c ? ", " : ""), +// img1.getchannel(cr.maxx, cr.maxy, 0, c)); +// ; +// } +// } +// print("\n"); +// #if OIIO_MSVS_BEFORE_2015 +// // When older Visual Studio is used, float values in +// // scientific format are printed with three digit exponent. +// // We change this behaviour to fit Linux way. +// _set_output_format(_TWO_DIGIT_EXPONENT); +// #endif +// print(" {} pixels ({:1.3g}%) over {}\n", cr.nwarn, +// (100.0 * cr.nwarn / npels), warnthresh); +// print(" {} pixels ({:1.3g}%) over {}\n", cr.nfail, +// (100.0 * cr.nfail / npels), failthresh); +// if (perceptual) +// print(" {} pixels ({:3g}%) failed the perceptual test\n", +// yee_failures, (100.0 * yee_failures / npels)); +// } + +// // If the user requested that a difference image be output, +// // do that. N.B. we only do this for the first subimage +// // right now, because ImageBuf doesn't really know how to +// // write subimages. +// if (diffimage.size() && (cr.maxerror != 0 || !outdiffonly)) { +// ImageBuf diff; +// if (diffabs) +// ImageBufAlgo::absdiff(diff, img0, img1); +// else +// ImageBufAlgo::sub(diff, img0, img1); +// if (diffscale != 1.0f) +// ImageBufAlgo::mul(diff, diff, diffscale); +// diff.write(diffimage); + +// // Clear diff image name so we only save the first +// // non-matching subimage. +// diffimage = ""; +// } +// } +// } + +// if (compareall && img0.nsubimages() != img1.nsubimages()) { +// if (!quiet) +// print(stderr, +// "Images had differing numbers of subimages ({} vs {})\n", +// img0.nsubimages(), img1.nsubimages()); +// ret = ErrFail; +// } +// if (!compareall && (img0.nsubimages() > 1 || img1.nsubimages() > 1)) { +// if (!quiet) +// print( +// "Only compared the first subimage (of {} and {}, respectively)\n", +// img0.nsubimages(), img1.nsubimages()); +// } + +// if (ret == ErrOK) { +// if (!quiet) +// print("PASS\n"); +// } else if (ret == ErrWarn) { +// if (!quiet) +// print("WARNING\n"); +// } else if (ret) { +// if (quiet) +// print(stderr, "FAILURE\n"); +// else +// print("FAILURE\n"); +// } + +// imagecache->invalidate_all(true); +// ImageCache::destroy(imagecache); +// shutdown(); +// return ret; +// } diff --git a/Sources/OpenImageIO/iff.imageio/iffinput.cpp b/Sources/OpenImageIO/iff.imageio/iffinput.cpp deleted file mode 100644 index d0b8aee0..00000000 --- a/Sources/OpenImageIO/iff.imageio/iffinput.cpp +++ /dev/null @@ -1,773 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO -#include "iff_pvt.h" - -#include - -OIIO_PLUGIN_NAMESPACE_BEGIN - -using namespace iff_pvt; - -class IffInput final : public ImageInput { -public: - IffInput() { init(); } - ~IffInput() override { close(); } - const char* format_name(void) const override { return "iff"; } - int supports(string_view feature) const override - { - return feature == "ioproxy"; - } - bool open(const std::string& name, ImageSpec& spec) override; - bool open(const std::string& name, ImageSpec& newspec, - const ImageSpec& config) override; - bool close(void) override; - bool read_native_scanline(int subimage, int miplevel, int y, int z, - void* data) override; - bool read_native_tile(int subimage, int miplevel, int x, int y, int z, - void* data) override; - -private: - std::string m_filename; - iff_pvt::IffFileHeader m_iff_header; - std::vector m_buf; - - uint32_t m_tbmp_start; - - // init to initialize state - void init(void) - { - ioproxy_clear(); - m_filename.clear(); - m_buf.clear(); - } - - // Reads information about IFF file. If errors are encountereed, - // read_header wil. issue error messages and return false. - bool read_header(); - - // helper to read an image - bool readimg(void); - - // helper to uncompress a rle channel - size_t uncompress_rle_channel(const uint8_t* in, uint8_t* out, int size); - - /// Helper: read buf[0..nitems-1], swap endianness if necessary - template bool read(T* buf, size_t nitems = 1) - { - if (!ioread(buf, sizeof(T), nitems)) - return false; - if (littleendian() - && (is_same::value || is_same::value - || is_same::value || is_same::value)) { - swap_endian(buf, nitems); - } - return true; - } - - bool read_str(std::string& val, uint32_t len, uint32_t round = 4) - { - const uint32_t big = 1024; - char strbuf[big]; - len = std::min(len, big); - bool ok = ioread(strbuf, len); - val.assign(strbuf, len); - ok &= ioseek(len % round, SEEK_CUR); - return ok; - } - - bool read_type_len(std::string& type, uint32_t& len) - { - return read_str(type, 4) && read(&len); - } - - bool read_meta_string(std::string& name, std::string& val) - { - uint32_t len = 0; - return read_type_len(name, len) && read_str(val, len); - } - - // Read a 4-byte type code (no endian swap), and if that succeeds (beware - // of EOF or other errors), then also read a 32 bit size (subject to - // endian swap). - bool read_typesize(uint8_t type[4], uint32_t& size) - { - return ioread(type, 1, 4) && read(&size); - } -}; - - - -// Obligatory material to make this a recognizable imageio plugin -OIIO_PLUGIN_EXPORTS_BEGIN - -OIIO_EXPORT int iff_imageio_version = OIIO_PLUGIN_VERSION; - -OIIO_EXPORT const char* -iff_imageio_library_version() -{ - return nullptr; -} - -OIIO_EXPORT ImageInput* -iff_input_imageio_create() -{ - return new IffInput; -} - -OIIO_EXPORT const char* iff_input_extensions[] = { "iff", "z", nullptr }; - -OIIO_PLUGIN_EXPORTS_END - - - -bool -IffInput::open(const std::string& name, ImageSpec& newspec, - const ImageSpec& config) -{ - // Check 'config' for any special requests - ioproxy_retrieve_from_config(config); - return open(name, newspec); -} - - - -bool -IffInput::open(const std::string& name, ImageSpec& spec) -{ - // Autodesk Maya documentation: - // "Maya Image File Format - IFF - // - // Maya supports images in the Interchange File Format (IFF). - // IFF is a generic structured file access mechanism, and is not only - // limited to images. - // - // The openimageio IFF implementation deals specifically with Maya IFF - // images with it's data blocks structured as follows: - // - // Header: - // FOR4 CIMG - // TBHD flags, width, height, compression ... - // AUTH attribute ... - // DATE attribute ... - // FOR4 TBMP - // Tiles: - // RGBA tile pixels - // RGBA tile pixels - // RGBA tile pixels - // ... - - // saving 'name' for later use - m_filename = name; - - if (!ioproxy_use_or_open(name)) - return false; - ioseek(0); - - // we read header of the file that we think is IFF file - if (!read_header()) { - close(); - return false; - } - - // image specification - m_spec = ImageSpec(m_iff_header.width, m_iff_header.height, - m_iff_header.pixel_channels, - m_iff_header.pixel_bits == 8 ? TypeDesc::UINT8 - : TypeDesc::UINT16); - // set x, y - m_spec.x = m_iff_header.x; - m_spec.y = m_iff_header.y; - - // set full width, height - m_spec.full_width = m_iff_header.width; - m_spec.full_height = m_iff_header.height; - - // tiles - if (m_iff_header.tile_width > 0 && m_iff_header.tile_height > 0) { - m_spec.tile_width = m_iff_header.tile_width; - m_spec.tile_height = m_iff_header.tile_height; - // only 1 subimage for IFF - m_spec.tile_depth = 1; - } else { - errorfmt("\"{}\": wrong tile size", m_filename); - close(); - return false; - } - - // attributes - - // compression - if (m_iff_header.compression == iff_pvt::RLE) { - m_spec.attribute("compression", "rle"); - } - - // author - if (m_iff_header.author.size()) { - m_spec.attribute("Artist", m_iff_header.author); - } - - // date - if (m_iff_header.date.size()) { - m_spec.attribute("DateTime", m_iff_header.date); - } - - // file pointer is set to the beginning of tbmp data - // we save this position - it will be helpful in read_native_tile - m_tbmp_start = m_iff_header.tbmp_start; - - spec = m_spec; - return true; -} - - - -bool -IffInput::read_header() -{ - uint8_t type[4]; - uint32_t size; - uint32_t chunksize; - uint32_t tbhdsize; - uint32_t flags; - uint16_t bytes; - uint16_t prnum; - uint16_t prden; - - // read FOR4 CIMG. - for (;;) { - // get type and length - if (!read_typesize(type, size)) - return false; - - chunksize = align_size(size, 4); - - if (type[0] == 'F' && type[1] == 'O' && type[2] == 'R' - && type[3] == '4') { - // get type - if (!ioread(&type, 1, sizeof(type))) - return false; - - // check if CIMG - if (type[0] == 'C' && type[1] == 'I' && type[2] == 'M' - && type[3] == 'G') { - // read TBHD. - for (;;) { - if (!read_typesize(type, size)) - return false; - - chunksize = align_size(size, 4); - - if (type[0] == 'T' && type[1] == 'B' && type[2] == 'H' - && type[3] == 'D') { - tbhdsize = size; - - // test if table header size is correct - if (tbhdsize != 24 && tbhdsize != 32) { - errorfmt("Bad table ehader size {}", tbhdsize); - return false; // bad table header - } - - // get width and height - if (!read(&m_iff_header.width) - || !read(&m_iff_header.height) || !read(&prnum) - || !read(&prden) || !read(&flags) || !read(&bytes) - || !read(&m_iff_header.tiles) - || !read(&m_iff_header.compression)) { - return false; - } - - // get xy - if (tbhdsize == 32) { - if (!read(&m_iff_header.x) - || !read(&m_iff_header.y)) { - return false; - } - } else { - m_iff_header.x = 0; - m_iff_header.y = 0; - } - - // tiles - if (m_iff_header.tiles == 0) { - errorfmt("non-tiles are not supported"); - return false; - } - - // 0 no compression - // 1 RLE compression - // 2 QRL (not supported) - // 3 QR4 (not supported) - if (m_iff_header.compression > 1) { - errorfmt("only RLE compression is supported"); - return false; - } - - // test format. - if (flags & RGBA) { - // test if black is set - OIIO_DASSERT(!(flags & BLACK)); - - // test for RGB channels. - if (flags & RGB) - m_iff_header.pixel_channels = 3; - - // test for alpha channel - if (flags & ALPHA) - m_iff_header.pixel_channels++; - - // test pixel bits - m_iff_header.pixel_bits = bytes ? 16 : 8; - } - - // Z format. - else if (flags & ZBUFFER) { - m_iff_header.pixel_channels = 1; - m_iff_header.pixel_bits = 32; // 32bit - // NOTE: Z_F32 support - not supported - OIIO_DASSERT(bytes == 0); - } - - // read AUTH, DATE or FOR4 - - for (;;) { - // get type - if (!read_typesize(type, size)) - return false; - - chunksize = align_size(size, 4); - - if (type[0] == 'A' && type[1] == 'U' - && type[2] == 'T' && type[3] == 'H') { - std::vector str(chunksize); - if (!ioread(&str[0], 1, chunksize)) - return false; - m_iff_header.author = std::string(&str[0], - size); - } else if (type[0] == 'D' && type[1] == 'A' - && type[2] == 'T' && type[3] == 'E') { - std::vector str(chunksize); - if (!ioread(&str[0], 1, chunksize)) - return false; - m_iff_header.date = std::string(&str[0], size); - } else if (type[0] == 'F' && type[1] == 'O' - && type[2] == 'R' && type[3] == '4') { - if (!ioread(&type, 1, sizeof(type))) - return false; - - // check if CIMG - if (type[0] == 'T' && type[1] == 'B' - && type[2] == 'M' && type[3] == 'P') { - // tbmp position for later user in in - // read_native_tile - - m_iff_header.tbmp_start = iotell(); - - // read first RGBA block to detect tile size. - - for (unsigned int t = 0; - t < m_iff_header.tiles; t++) { - if (!read_typesize(type, size)) - return false; - chunksize = align_size(size, 4); - - // check if RGBA - if (type[0] == 'R' && type[1] == 'G' - && type[2] == 'B' - && type[3] == 'A') { - // get tile coordinates. - uint16_t xmin, xmax, ymin, ymax; - if (!read(&xmin) || !read(&ymin) - || !read(&xmax) || !read(&ymax)) - return false; - - // check tile - if (xmin > xmax || ymin > ymax - || xmax >= m_iff_header.width - || ymax >= m_iff_header.height) - return false; - - // set tile width and height - m_iff_header.tile_width - = xmax - xmin + 1; - m_iff_header.tile_height - = ymax - ymin + 1; - - // done, return - return true; - } - - // skip to the next block. - if (!ioseek(chunksize, SEEK_CUR)) - return false; - } - } else { - // skip to the next block. - if (!ioseek(chunksize, SEEK_CUR)) - return false; - } - } else { - // skip to the next block. - if (!ioseek(chunksize, SEEK_CUR)) - return false; - } - } - // TBHD done, break - break; - } - - // skip to the next block. - if (!ioseek(chunksize, SEEK_CUR)) - return false; - } - } - } - // skip to the next block. - if (!ioseek(chunksize, SEEK_CUR)) - return false; - } - errorfmt("unknown error reading header"); - return false; -} - - - -bool -IffInput::read_native_scanline(int /*subimage*/, int /*miplevel*/, int /*y*/, - int /*z*/, void* /*data*/) -{ - // scanline not used for Maya IFF, uses tiles instead. - return false; -} - - - -bool -IffInput::read_native_tile(int subimage, int miplevel, int x, int y, int /*z*/, - void* data) -{ - lock_guard lock(*this); - if (!seek_subimage(subimage, miplevel)) - return false; - - if (m_buf.empty()) - readimg(); - - // tile size - int w = m_spec.width; - int tw = std::min(x + m_spec.tile_width, m_spec.width) - x; - int th = std::min(y + m_spec.tile_height, m_spec.height) - y; - - // tile data - int oy = 0; - for (int iy = y; iy < y + th; iy++) { - // in - uint8_t* in_p = &m_buf[0] + (iy * w + x) * m_spec.pixel_bytes(); - // out - uint8_t* out_p = (uint8_t*)data - + (oy * m_spec.tile_width) * m_spec.pixel_bytes(); - // copy - memcpy(out_p, in_p, tw * m_spec.pixel_bytes()); - oy++; - } - - return true; -} - - - -bool inline IffInput::close(void) -{ - init(); - return true; -} - - - -bool -IffInput::readimg() -{ - uint8_t type[4]; - uint32_t size; - uint32_t chunksize; - - // seek pos - // set position tile may be called randomly - ioseek(m_tbmp_start); - - // resize buffer - m_buf.resize(m_spec.image_bytes()); - - for (unsigned int t = 0; t < m_iff_header.tiles;) { - // get type and length - if (!ioread(&type, 1, sizeof(type)) || !read(&size)) - return false; - - chunksize = align_size(size, 4); - - // check if RGBA - if (type[0] == 'R' && type[1] == 'G' && type[2] == 'B' - && type[3] == 'A') { - // get tile coordinates. - uint16_t xmin, xmax, ymin, ymax; - if (!read(&xmin) || !read(&ymin) || !read(&xmax) || !read(&ymax)) - return false; - - // get tile width/height - uint32_t tw = xmax - xmin + 1; - uint32_t th = ymax - ymin + 1; - - // get image size - // skip coordinates, uint16_t (2) * 4 = 8 - uint32_t image_size = chunksize - 8; - - // check tile - if (xmin > xmax || ymin > ymax || xmax >= m_spec.width - || ymax >= m_spec.height || !tw || !th) { - return false; - } - - // tile compress - bool tile_compress = false; - - // if tile compression fails to be less than image data stored - // uncompressed the tile is written uncompressed - - // set channels - uint8_t channels = m_iff_header.pixel_channels; - - // set tile size - uint32_t tile_size = tw * th * channels * m_spec.channel_bytes() - + 8; - - // test if compressed - // we use the non aligned size - if (tile_size > size) { - tile_compress = true; - } - - // handle 8-bit data. - if (m_iff_header.pixel_bits == 8) { - std::vector scratch; - - // set bytes. - scratch.resize(image_size); - - if (!ioread(scratch.data(), 1, scratch.size())) - return false; - - // set tile data - uint8_t* p = static_cast(&scratch[0]); - - // tile compress. - if (tile_compress) { - // map BGR(A) to RGB(A) - for (int c = (channels * m_spec.channel_bytes()) - 1; - c >= 0; --c) { - std::vector in(tw * th); - uint8_t* in_p = &in[0]; - - // uncompress and increment - p += uncompress_rle_channel(p, in_p, tw * th); - - // set tile - for (uint16_t py = ymin; py <= ymax; py++) { - uint8_t* out_dy = static_cast(&m_buf[0]) - + (py * m_spec.width) - * m_spec.pixel_bytes(); - - for (uint16_t px = xmin; px <= xmax; px++) { - uint8_t* out_p - = out_dy + px * m_spec.pixel_bytes() + c; - *out_p++ = *in_p++; - } - } - } - } else { - int sy = 0; - for (uint16_t py = ymin; py <= ymax; py++) { - uint8_t* out_dy = static_cast(&m_buf[0]) - + (py * m_spec.width + xmin) - * m_spec.pixel_bytes(); - - // set tile - int sx = 0; - for (uint16_t px = xmin; px <= xmax; px++) { - uint8_t* in_p - = p + (sy * tw + sx) * m_spec.pixel_bytes(); - - // map BGR(A) to RGB(A) - for (int c = channels - 1; c >= 0; --c) { - uint8_t* out_p = in_p - + (c * m_spec.channel_bytes()); - *out_dy++ = *out_p; - } - sx++; - } - sy++; - } - } - } - // handle 16-bit data. - else if (m_iff_header.pixel_bits == 16) { - std::vector scratch; - - // set bytes. - scratch.resize(image_size); - - if (!ioread(scratch.data(), 1, scratch.size())) - return false; - - // set tile data - uint8_t* p = static_cast(&scratch[0]); - - if (tile_compress) { - // set map - std::vector map; - if (littleendian()) { - int rgb16[] = { 0, 2, 4, 1, 3, 5 }; - int rgba16[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; - if (m_iff_header.pixel_channels == 3) { - map = std::vector(rgb16, &rgb16[6]); - } else { - map = std::vector(rgba16, &rgba16[8]); - } - - } else { - int rgb16[] = { 1, 3, 5, 0, 2, 4 }; - int rgba16[] = { 1, 3, 5, 7, 0, 2, 4, 6 }; - if (m_iff_header.pixel_channels == 3) { - map = std::vector(rgb16, &rgb16[6]); - } else { - map = std::vector(rgba16, &rgba16[8]); - } - } - - // map BGR(A)BGR(A) to RRGGBB(AA) - for (int c = (channels * m_spec.channel_bytes()) - 1; - c >= 0; --c) { - int mc = map[c]; - - std::vector in(tw * th); - uint8_t* in_p = &in[0]; - - // uncompress and increment - p += uncompress_rle_channel(p, in_p, tw * th); - - // set tile - for (uint16_t py = ymin; py <= ymax; py++) { - uint8_t* out_dy = static_cast(&m_buf[0]) - + (py * m_spec.width) - * m_spec.pixel_bytes(); - - for (uint16_t px = xmin; px <= xmax; px++) { - uint8_t* out_p - = out_dy + px * m_spec.pixel_bytes() + mc; - *out_p++ = *in_p++; - } - } - } - } else { - int sy = 0; - for (uint16_t py = ymin; py <= ymax; py++) { - uint8_t* out_dy = static_cast(&m_buf[0]) - + (py * m_spec.width + xmin) - * m_spec.pixel_bytes(); - - // set scanline, make copy easier - std::vector scanline(tw - * m_spec.pixel_bytes()); - uint16_t* sl_p = &scanline[0]; - - // set tile - int sx = 0; - for (uint16_t px = xmin; px <= xmax; px++) { - uint8_t* in_p - = p + (sy * tw + sx) * m_spec.pixel_bytes(); - - // map BGR(A) to RGB(A) - for (int c = channels - 1; c >= 0; --c) { - uint16_t pixel; - uint8_t* out_p = in_p - + (c * m_spec.channel_bytes()); - memcpy(&pixel, out_p, 2); - // swap endianness - if (littleendian()) { - swap_endian(&pixel); - } - *sl_p++ = pixel; - } - sx++; - } - // copy data - memcpy(out_dy, &scanline[0], tw * m_spec.pixel_bytes()); - sy++; - } - } - - } else { - errorfmt("\"{}\": unsupported number of bits per pixel for tile", - m_filename); - return false; - } - - // tile - t++; - - } else { - // skip to the next block - if (!ioseek(chunksize)) - return false; - } - } - - // flip buffer to make read_native_tile easier, - // from tga.imageio: - - int bytespp = m_spec.pixel_bytes(); - - std::vector flip(m_spec.width * bytespp); - unsigned char *src, *dst, *tmp = &flip[0]; - for (int y = 0; y < m_spec.height / 2; y++) { - src = &m_buf[(m_spec.height - y - 1) * m_spec.width * bytespp]; - dst = &m_buf[y * m_spec.width * bytespp]; - - memcpy(tmp, src, m_spec.width * bytespp); - memcpy(src, dst, m_spec.width * bytespp); - memcpy(dst, tmp, m_spec.width * bytespp); - } - - return true; -} - - - -size_t -IffInput::uncompress_rle_channel(const uint8_t* in, uint8_t* out, int size) -{ - const uint8_t* const _in = in; - const uint8_t* const end = out + size; - - while (out < end) { - // information. - const uint8_t count = (*in & 0x7f) + 1; - const bool run = (*in & 0x80) ? true : false; - ++in; - - // find runs - if (!run) { - // verbatim - for (int i = 0; i < count; i++) - *out++ = *in++; - } else { - // duplicate - const uint8_t p = *in++; - for (int i = 0; i < count; i++) - *out++ = p; - } - } - const size_t r = in - _in; - return r; -} - -OIIO_PLUGIN_NAMESPACE_END diff --git a/Sources/OpenImageIO/iff.imageio/iffoutput.cpp b/Sources/OpenImageIO/iff.imageio/iffoutput.cpp deleted file mode 100644 index 5cf4b6a2..00000000 --- a/Sources/OpenImageIO/iff.imageio/iffoutput.cpp +++ /dev/null @@ -1,730 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include "iff_pvt.h" - -OIIO_PLUGIN_NAMESPACE_BEGIN - -using namespace iff_pvt; - - -class IffOutput final : public ImageOutput { -public: - IffOutput() { init(); } - ~IffOutput() override - { - try { - close(); - } catch (...) { - } - } - const char* format_name(void) const override { return "iff"; } - int supports(string_view feature) const override; - bool open(const std::string& name, const ImageSpec& spec, - OpenMode mode) override; - bool close(void) override; - bool write_scanline(int y, int z, TypeDesc format, const void* data, - stride_t xstride) override; - bool write_tile(int x, int y, int z, TypeDesc format, const void* data, - stride_t xstride, stride_t ystride, - stride_t zstride) override; - -private: - std::string m_filename; - iff_pvt::IffFileHeader m_iff_header; - std::vector m_buf; - unsigned int m_dither; - std::vector scratch; - - void init(void) - { - ioproxy_clear(); - m_filename.clear(); - } - - // writes information about iff file to give file - bool write_header(iff_pvt::IffFileHeader& header); - - /// Helper: write buf[0..nitems-1], swap endianness if necessary - template bool write(const T* buf, size_t nitems = 1) - { - if (littleendian() - && (is_same::value || is_same::value - || is_same::value || is_same::value)) { - T* newbuf = OIIO_ALLOCA(T, nitems); - memcpy(newbuf, buf, nitems * sizeof(T)); - swap_endian(newbuf, nitems); - buf = newbuf; - } - return iowrite(buf, sizeof(T), nitems); - } - - bool write_short(uint16_t val) { return write(&val); } - bool write_int(uint32_t val) { return write(&val); } - - bool write_str(string_view val, size_t round = 4) - { - bool ok = iowrite(val.data(), val.size()); - if (size_t extra = round_to_multiple(val.size(), round) - val.size()) { - static const uint8_t pad[4] = { 0, 0, 0, 0 }; - ok &= iowrite(pad, extra); - } - return ok; - } - - bool write_meta_string(string_view name, string_view val, - bool write_if_empty = false) - { - if (val.empty() && !write_if_empty) - return true; - return write_str(name) && write_int(uint32_t(val.size())) - && (val.size() == 0 || write_str(val)); - } - - // helper to compress verbatim - void compress_verbatim(const uint8_t*& in, uint8_t*& out, int size); - - // helper to compress duplicate - void compress_duplicate(const uint8_t*& in, uint8_t*& out, int size); - - // helper to compress a rle channel - size_t compress_rle_channel(const uint8_t* in, uint8_t* out, int size); -}; - - - -// Obligatory material to make this a recognizable imageio plugin -OIIO_PLUGIN_EXPORTS_BEGIN - -OIIO_EXPORT ImageOutput* -iff_output_imageio_create() -{ - return new IffOutput; -} - -OIIO_EXPORT const char* iff_output_extensions[] = { "iff", "z", nullptr }; - -OIIO_PLUGIN_EXPORTS_END - - - -int -IffOutput::supports(string_view feature) const -{ - return (feature == "tiles" || feature == "alpha" || feature == "nchannels" - || feature == "ioproxy" || feature == "origin"); -} - - - -bool -IffOutput::open(const std::string& name, const ImageSpec& spec, OpenMode mode) -{ - // Autodesk Maya documentation: - // "Maya Image File Format - IFF - // - // Maya supports images in the Interchange File Format (IFF). - // IFF is a generic structured file access mechanism, and is not only - // limited to images. - // - // The openimageio IFF implementation deals specifically with Maya IFF - // images with it's data blocks structured as follows: - // - // Header: - // FOR4 CIMG - // TBHD flags, width, height, compression ... - // AUTH attribute ... - // DATE attribute ... - // FOR4 TBMP - // Tiles: - // RGBA tile pixels - // RGBA tile pixels - // RGBA tile pixels - // ... - - // saving 'name' and 'spec' for later use - m_filename = name; - - if (!check_open(mode, spec, { 0, 8192, 0, 8192, 0, 1, 0, 4 })) - return false; - // Maya docs say 8k is the limit - - // tiles always - m_spec.tile_width = tile_width(); - m_spec.tile_height = tile_height(); - m_spec.tile_depth = 1; - - // This implementation only supports writing RGB and RGBA images as IFF - if (m_spec.nchannels < 3 || m_spec.nchannels > 4) { - errorfmt("Cannot write IFF file with {} channels", m_spec.nchannels); - return false; - } - - uint64_t xtiles = tile_width_size(m_spec.width); - uint64_t ytiles = tile_height_size(m_spec.height); - if (xtiles * ytiles >= (1 << 16)) { // The format can't store it! - errorfmt( - "Too high a resolution ({}x{}), exceeds maximum of 64k tiles in the image\n", - m_spec.width, m_spec.height); - return false; - } - - ioproxy_retrieve_from_config(m_spec); - if (!ioproxy_use_or_open(name)) - return false; - - // IFF image files only supports UINT8 and UINT16. If something - // else was requested, revert to the one most likely to be readable - // by any IFF reader: UINT8 - if (m_spec.format != TypeDesc::UINT8 && m_spec.format != TypeDesc::UINT16) - m_spec.set_format(TypeDesc::UINT8); - - m_dither = (m_spec.format == TypeDesc::UINT8) - ? m_spec.get_int_attribute("oiio:dither", 0) - : 0; - - // check if the client wants the image to be run length encoded - // currently only RGB RLE compression is supported, we default to RLE - // as Maya does not handle non-compressed IFF's very well. - m_iff_header.compression - = (m_spec.get_string_attribute("compression") == "none") ? NONE : RLE; - - // we write the header of the file - m_iff_header.x = m_spec.x; - m_iff_header.y = m_spec.y; - m_iff_header.width = m_spec.width; - m_iff_header.height = m_spec.height; - m_iff_header.tiles = xtiles * ytiles; - m_iff_header.pixel_bits = m_spec.format == TypeDesc::UINT8 ? 8 : 16; - m_iff_header.pixel_channels = m_spec.nchannels; - m_iff_header.author = m_spec.get_string_attribute("Artist"); - m_iff_header.date = m_spec.get_string_attribute("DateTime"); - - if (!write_header(m_iff_header)) { - errorfmt("\"{}\": could not write iff header", m_filename); - close(); - return false; - } - - m_buf.resize(m_spec.image_bytes()); - - return true; -} - - - -bool -IffOutput::write_header(IffFileHeader& header) -{ - // write 'FOR4' type, with 0 length for now (to reserve it) - if (!(write_str("FOR4") && write_int(0))) - return false; - - // write 'CIMG' type - if (!write_str("CIMG")) - return false; - - // write 'TBHD' type - if (!write_str("TBHD")) - return false; - - // 'TBHD' length, 32 bytes - if (!write_int(32)) - return false; - - if (!write_int(header.width) || !write_int(header.height)) - return false; - - // write prnum and prden (pixel aspect ratio? -- FIXME) - if (!write_short(1) || !write_short(1)) //NOSONAR - return false; - - // write flags and channels - if (!write_int(header.pixel_channels == 3 ? RGB : RGBA) - || !write_short(header.pixel_bits == 8 ? 0 : 1) - || !write_short(header.tiles)) - return false; - - // write compression - // 0 no compression - // 1 RLE compression - // 2 QRL (not supported) - // 3 QR4 (not supported) - if (!write_int(header.compression)) - return false; - - // write x and y - if (!write_int(header.x) || !write_int(header.y)) - return false; - - // Write metadata - write_meta_string("AUTH", header.author); - write_meta_string("DATE", header.date); - - // for4 position for later user in close - header.for4_start = iotell(); - - // write 'FOR4' type, with 0 length to reserve it for now - if (!write_str("FOR4") || !write_int(0)) - return false; - - // write 'TBMP' type - if (!write_str("TBMP")) - return false; - - return true; -} - - - -bool -IffOutput::write_scanline(int y, int z, TypeDesc format, const void* data, - stride_t xstride) -{ - if (!ioproxy_opened()) { - errorfmt("write_scanline called but file is not open."); - return false; - } - - // scanline not used for Maya IFF, uses tiles instead. - // Emulate by copying the scanline to the buffer we're accumulating. - std::vector scratch; - data = to_native_scanline(format, data, xstride, scratch, m_dither, y, z); - size_t scanlinesize = spec().scanline_bytes(true); - size_t offset = scanlinesize * (y - spec().y) - + scanlinesize * spec().height * (z - spec().z); - memcpy(&m_buf[offset], data, scanlinesize); - return false; -} - - - -bool -IffOutput::write_tile(int x, int y, int z, TypeDesc format, const void* data, - stride_t xstride, stride_t ystride, stride_t zstride) -{ - if (!ioproxy_opened()) { - errorfmt("write_tile called but file is not open."); - return false; - } - - // auto stride - m_spec.auto_stride(xstride, ystride, zstride, format, spec().nchannels, - spec().tile_width, spec().tile_height); - - // native tile - data = to_native_tile(format, data, xstride, ystride, zstride, scratch, - m_dither, x, y, z); - - x -= m_spec.x; // Account for offset, so x,y are file relative, not - y -= m_spec.y; // image relative - - // tile size - int w = m_spec.width; - int tw = std::min(x + m_spec.tile_width, m_spec.width) - x; - int th = std::min(y + m_spec.tile_height, m_spec.height) - y; - - // tile data - int iy = 0; - for (int oy = y; oy < y + th; oy++) { - // in - uint8_t* in_p = (uint8_t*)data - + (iy * m_spec.tile_width) * m_spec.pixel_bytes(); - // out - uint8_t* out_p = &m_buf[0] + (oy * w + x) * m_spec.pixel_bytes(); - // copy - memcpy(out_p, in_p, tw * m_spec.pixel_bytes()); - iy++; - } - - return true; -} - - - -inline bool -IffOutput::close(void) -{ - if (ioproxy_opened() && m_buf.size()) { - // flip buffer to make write tile easier, - // from tga.imageio: - - int bytespp = m_spec.pixel_bytes(); - - std::vector flip(m_spec.width * bytespp); - unsigned char *src, *dst, *tmp = &flip[0]; - for (int y = 0; y < m_spec.height / 2; y++) { - src = &m_buf[(m_spec.height - y - 1) * m_spec.width * bytespp]; - dst = &m_buf[y * m_spec.width * bytespp]; - - memcpy(tmp, src, m_spec.width * bytespp); - memcpy(src, dst, m_spec.width * bytespp); - memcpy(dst, tmp, m_spec.width * bytespp); - } - - // write y-tiles - for (uint32_t ty = 0; ty < tile_height_size(m_spec.height); ty++) { - // write x-tiles - for (uint32_t tx = 0; tx < tile_width_size(m_spec.width); tx++) { - // channels - uint8_t channels = m_iff_header.pixel_channels; - - // set tile coordinates - uint32_t xmin = tx * tile_width(); - uint32_t xmax - = std::min(xmin + tile_width(), uint32_t(m_spec.width)) - 1; - uint32_t ymin = ty * tile_height(); - uint32_t ymax = std::min(ymin + tile_height(), - uint32_t(m_spec.height)) - - 1; - - // set width and height - uint32_t tw = xmax - xmin + 1; - uint32_t th = ymax - ymin + 1; - - // write 'RGBA' type - if (!iowritefmt("RGBA")) - return false; - - // length. - uint32_t length = tw * th * m_spec.pixel_bytes(); - - // tile length. - uint32_t tile_length = length; - - // align. - length = align_size(length, 4); - - // append xmin, xmax, ymin and ymax. - length += 8; - - // tile compression. - bool tile_compress = (m_iff_header.compression == RLE); - - // set bytes. - std::vector scratch; - scratch.resize(tile_length); - - uint8_t* out_p = static_cast(&scratch[0]); - - // handle 8-bit data - if (m_spec.format == TypeDesc::UINT8) { - if (tile_compress) { - uint32_t index = 0, size = 0; - std::vector tmp; - - // set bytes. - tmp.resize(tile_length * 2); - - // map: RGB(A) to BGRA - for (int c = (channels * m_spec.channel_bytes()) - 1; - c >= 0; --c) { - std::vector in(tw * th); - uint8_t* in_p = &in[0]; - - // set tile - for (uint32_t py = ymin; py <= ymax; py++) { - const uint8_t* in_dy - = &m_buf[0] + py * m_spec.scanline_bytes(); - - for (uint32_t px = xmin; px <= xmax; px++) { - // get pixel - uint8_t pixel; - const uint8_t* in_dx - = in_dy + px * m_spec.pixel_bytes() + c; - memcpy(&pixel, in_dx, 1); - // set pixel - *in_p++ = pixel; - } - } - - // compress rle channel - size = compress_rle_channel(&in[0], &tmp[0] + index, - tw * th); - index += size; - } - - // if size exceeds tile length write uncompressed - - if (index < tile_length) { - memcpy(&scratch[0], &tmp[0], index); - - // set tile length - tile_length = index; - - // append xmin, xmax, ymin and ymax - length = index + 8; - - // set length - uint32_t align = align_size(length, 4); - if (align > length) { - if (scratch.size() < index + align - length) - scratch.resize(index + align - length); - out_p = &scratch[0] + index; - // Pad. - for (uint32_t i = 0; i < align - length; i++) { - *out_p++ = '\0'; - tile_length++; - } - } - } else { - tile_compress = false; - } - } - if (!tile_compress) { - for (uint32_t py = ymin; py <= ymax; py++) { - const uint8_t* in_dy = &m_buf[0] - + (py * m_spec.width) - * m_spec.pixel_bytes(); - - for (uint32_t px = xmin; px <= xmax; px++) { - // Map: RGB(A)8 RGBA to BGRA - for (int c = channels - 1; c >= 0; --c) { - // get pixel - uint8_t pixel; - const uint8_t* in_dx - = in_dy + px * m_spec.pixel_bytes() - + c * m_spec.channel_bytes(); - memcpy(&pixel, in_dx, 1); - // set pixel - *out_p++ = pixel; - } - } - } - } - } - // handle 16-bit data - else if (m_spec.format == TypeDesc::UINT16) { - if (tile_compress) { - uint32_t index = 0, size = 0; - std::vector tmp; - - // set bytes. - tmp.resize(tile_length * 2); - - // set map - std::vector map; - if (littleendian()) { - int rgb16[] = { 0, 2, 4, 1, 3, 5 }; - int rgba16[] = { 0, 2, 4, 7, 1, 3, 5, 6 }; - if (m_iff_header.pixel_channels == 3) { - map = std::vector(rgb16, &rgb16[6]); - } else { - map = std::vector(rgba16, &rgba16[8]); - } - - } else { - int rgb16[] = { 1, 3, 5, 0, 2, 4 }; - int rgba16[] = { 1, 3, 5, 7, 0, 2, 4, 6 }; - if (m_iff_header.pixel_channels == 3) { - map = std::vector(rgb16, &rgb16[6]); - } else { - map = std::vector(rgba16, &rgba16[8]); - } - } - - // map: RRGGBB(AA) to BGR(A)BGR(A) - for (int c = (channels * m_spec.channel_bytes()) - 1; - c >= 0; --c) { - int mc = map[c]; - - std::vector in(tw * th); - uint8_t* in_p = &in[0]; - - // set tile - for (uint32_t py = ymin; py <= ymax; py++) { - const uint8_t* in_dy - = &m_buf[0] + py * m_spec.scanline_bytes(); - - for (uint32_t px = xmin; px <= xmax; px++) { - // get pixel - uint8_t pixel; - const uint8_t* in_dx - = in_dy + px * m_spec.pixel_bytes() - + mc; - memcpy(&pixel, in_dx, 1); - // set pixel. - *in_p++ = pixel; - } - } - - // compress rle channel - size = compress_rle_channel(&in[0], &tmp[0] + index, - tw * th); - index += size; - } - - // if size exceeds tile length write uncompressed - - if (index < tile_length) { - memcpy(&scratch[0], &tmp[0], index); - - // set tile length - tile_length = index; - - // append xmin, xmax, ymin and ymax - length = index + 8; - - // set length - uint32_t align = align_size(length, 4); - if (align > length) { - if (scratch.size() < index + align - length) - scratch.resize(index + align - length); - out_p = &scratch[0] + index; - // Pad. - for (uint32_t i = 0; i < align - length; i++) { - *out_p++ = '\0'; - tile_length++; - } - } - } else { - tile_compress = false; - } - } - - if (!tile_compress) { - for (uint32_t py = ymin; py <= ymax; py++) { - const uint8_t* in_dy = &m_buf[0] - + (py * m_spec.width) - * m_spec.pixel_bytes(); - - for (uint32_t px = xmin; px <= xmax; px++) { - // map: RGB(A) to BGRA - for (int c = channels - 1; c >= 0; --c) { - uint16_t pixel; - const uint8_t* in_dx - = in_dy + px * m_spec.pixel_bytes() - + c * m_spec.channel_bytes(); - memcpy(&pixel, in_dx, 2); - if (littleendian()) - swap_endian(&pixel); - // set pixel - *out_p++ = pixel & 0xff; - *out_p++ = pixel >> 8; - } - } - } - } - } - - // write 'RGBA' length - if (!write(&length)) - return false; - - // write xmin, xmax, ymin and ymax - if (!write_short(xmin) || !write_short(ymin) - || !write_short(xmax) || !write_short(ymax)) - return false; - - // write tile - if (!iowrite(scratch.data(), tile_length)) - return false; - } - } - - // set sizes - uint32_t pos(iotell()); - - uint32_t p0 = pos - 8; - uint32_t p1 = p0 - m_iff_header.for4_start; - - // set pos - ioseek(4); - - // write FOR4 CIMG - if (!write(&p0)) - return false; - - // set pos - ioseek(m_iff_header.for4_start + 4); - - // write FOR4 TBMP - if (!write(&p1)) - return false; - - m_buf.resize(0); - m_buf.shrink_to_fit(); - } - - init(); - return true; -} - - - -void -IffOutput::compress_verbatim(const uint8_t*& in, uint8_t*& out, int size) -{ - int count = 1; - unsigned char byte = 0; - - // two in a row or count - for (; count < size; ++count) { - if (in[count - 1] == in[count]) { - if (byte == in[count - 1]) { - count -= 2; - break; - } - } - byte = in[count - 1]; - } - - // copy - *out++ = count - 1; - memcpy(out, in, count); - - out += count; - in += count; -} - - - -void -IffOutput::compress_duplicate(const uint8_t*& in, uint8_t*& out, int size) -{ - int count = 1; - for (; count < size; ++count) { - if (in[count - 1] != in[count]) - break; - } - - const bool run = count > 1; - const int length = run ? 1 : count; - - // copy - *out++ = ((count - 1) & 0x7f) | (run << 7); - *out = *in; - - out += length; - in += count; -} - - - -size_t -IffOutput::compress_rle_channel(const uint8_t* in, uint8_t* out, int size) -{ - const uint8_t* const _out = out; - const uint8_t* const end = in + size; - - while (in < end) { - // find runs - const int max = std::min(0x7f + 1, static_cast(end - in)); - if (max > 0) { - if (in < (end - 1) && in[0] == in[1]) { - // compress duplicate - compress_duplicate(in, out, max); - } else { - // compress verbatim - compress_verbatim(in, out, max); - } - } - } - const size_t r = out - _out; - return r; -} - - - -OIIO_PLUGIN_NAMESPACE_END diff --git a/Sources/OpenImageIO/igrep/igrep.cpp b/Sources/OpenImageIO/igrep/igrep.cpp index 4dddda89..82a835d6 100644 --- a/Sources/OpenImageIO/igrep/igrep.cpp +++ b/Sources/OpenImageIO/igrep/igrep.cpp @@ -134,64 +134,64 @@ parse_files(int argc, const char* argv[]) -int -main(int argc, const char* argv[]) -{ - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - Filesystem::convert_native_arguments(argc, argv); - // clang-format off - ArgParse ap; - ap.intro("igrep -- search images for matching metadata\n" - OIIO_INTRO_STRING) - .usage("igrep [options] pattern filename...") - .add_version(OIIO_VERSION_STRING); - ap.arg("filename") - .hidden() - .action(parse_files); - ap.arg("-i") - .help("Ignore upper/lower case distinctions"); - ap.arg("-v", &invert_match) - .help("Invert match (select non-matching files)"); - ap.arg("-E") - .help( "Pattern is an extended regular expression"); - ap.arg("-f", &file_match) - .help("Match against file name as well as metadata"); - ap.arg("-l", &list_files) - .help("List the matching files (no detail)"); - ap.arg("-r", &recursive) - .help("Recurse into directories"); - ap.arg("-d", &print_dirs) - .help("Print directories (when recursive)"); - ap.arg("-a", &all_subimages) - .help("Search all subimages of each file"); - - // clang-format on - ap.parse(argc, argv); - if (pattern.empty() || filenames.empty()) { - std::cerr << ap.geterror() << std::endl; - ap.usage(); - return help ? EXIT_SUCCESS : EXIT_FAILURE; - } - - auto flag = std::regex_constants::grep; - if (ap["E"].get()) - flag = std::regex_constants::extended; - if (ap["i"].get()) - flag |= std::regex_constants::icase; - - bool ok = true; - - try { - std::regex re(pattern, flag); - for (auto&& s : filenames) - grep_file(s, re); - } catch (const std::regex_error& e) { - std::cerr << "igrep: " << e.what() << "\n"; - ok = false; - } - shutdown(); - return ok ? EXIT_SUCCESS : EXIT_FAILURE; -} +// int +// main(int argc, const char* argv[]) +// { +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// Filesystem::convert_native_arguments(argc, argv); +// // clang-format off +// ArgParse ap; +// ap.intro("igrep -- search images for matching metadata\n" +// OIIO_INTRO_STRING) +// .usage("igrep [options] pattern filename...") +// .add_version(OIIO_VERSION_STRING); +// ap.arg("filename") +// .hidden() +// .action(parse_files); +// ap.arg("-i") +// .help("Ignore upper/lower case distinctions"); +// ap.arg("-v", &invert_match) +// .help("Invert match (select non-matching files)"); +// ap.arg("-E") +// .help( "Pattern is an extended regular expression"); +// ap.arg("-f", &file_match) +// .help("Match against file name as well as metadata"); +// ap.arg("-l", &list_files) +// .help("List the matching files (no detail)"); +// ap.arg("-r", &recursive) +// .help("Recurse into directories"); +// ap.arg("-d", &print_dirs) +// .help("Print directories (when recursive)"); +// ap.arg("-a", &all_subimages) +// .help("Search all subimages of each file"); + +// // clang-format on +// ap.parse(argc, argv); +// if (pattern.empty() || filenames.empty()) { +// std::cerr << ap.geterror() << std::endl; +// ap.usage(); +// return help ? EXIT_SUCCESS : EXIT_FAILURE; +// } + +// auto flag = std::regex_constants::grep; +// if (ap["E"].get()) +// flag = std::regex_constants::extended; +// if (ap["i"].get()) +// flag |= std::regex_constants::icase; + +// bool ok = true; + +// try { +// std::regex re(pattern, flag); +// for (auto&& s : filenames) +// grep_file(s, re); +// } catch (const std::regex_error& e) { +// std::cerr << "igrep: " << e.what() << "\n"; +// ok = false; +// } +// shutdown(); +// return ok ? EXIT_SUCCESS : EXIT_FAILURE; +// } diff --git a/Sources/OpenImageIO/iinfo/iinfo.cpp b/Sources/OpenImageIO/iinfo/iinfo.cpp index 86295e3c..61ce5483 100644 --- a/Sources/OpenImageIO/iinfo/iinfo.cpp +++ b/Sources/OpenImageIO/iinfo/iinfo.cpp @@ -419,74 +419,74 @@ print_info(const std::string& filename, size_t namefieldlength, -int -main(int argc, const char* argv[]) -{ - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - Filesystem::convert_native_arguments(argc, (const char**)argv); - ArgParse ap; - // clang-format off - ap.intro("iinfo -- print information about images\n" OIIO_INTRO_STRING) - .usage("iinfo [options] filename...") - .add_version(OIIO_VERSION_STRING); - ap.arg("filename") - .hidden() - .action([&](cspan argv){ filenames.emplace_back(argv[0]); }); - ap.arg("-v", &verbose) - .help("Verbose output"); - ap.arg("-m %s:NAMES", &metamatch) - .help("Metadata names to print (default: all)"); - ap.arg("-f", &filenameprefix) - .help("Prefix each line with the filename"); - ap.arg("-s", &sum) - .help("Sum the image sizes"); - ap.arg("-a", &subimages) - .help("Print info about all subimages") - .action(ArgParse::store_true()); - ap.arg("--hash", &compute_sha1) - .help("Print SHA-1 hash of pixel values") - .action(ArgParse::store_true()); - ap.arg("--stats", &compute_stats) - .help("Print image pixel statistics (data window)"); - // clang-format on - if (ap.parse(argc, argv) < 0 || filenames.empty()) { - std::cerr << ap.geterror() << std::endl; - ap.print_help(); - return help ? EXIT_SUCCESS : EXIT_FAILURE; - } - - if (!metamatch.empty()) { - field_re.assign(metamatch, std::regex_constants::extended - | std::regex_constants::icase); - } - - // Find the longest filename - size_t longestname = 0; - for (auto&& s : filenames) - longestname = std::max(longestname, s.length()); - longestname = std::min(longestname, (size_t)40); - - int returncode = EXIT_SUCCESS; - long long totalsize = 0; - for (auto&& s : filenames) { - auto in = ImageInput::open(s); - if (!in) { - std::string err = geterror(); - print(std::cerr, "iinfo ERROR: \"{}\" : {}\n", s, - err.size() ? err : std::string("Could not open file.")); - returncode = EXIT_FAILURE; - continue; - } - ImageSpec spec = in->spec(); - print_info(s, longestname, in.get(), spec, verbose, sum, totalsize); - } - - if (sum) - print("Total size: {}\n", Strutil::memformat(totalsize)); - - shutdown(); - return returncode; -} +// int +// main(int argc, const char* argv[]) +// { +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// Filesystem::convert_native_arguments(argc, (const char**)argv); +// ArgParse ap; +// // clang-format off +// ap.intro("iinfo -- print information about images\n" OIIO_INTRO_STRING) +// .usage("iinfo [options] filename...") +// .add_version(OIIO_VERSION_STRING); +// ap.arg("filename") +// .hidden() +// .action([&](cspan argv){ filenames.emplace_back(argv[0]); }); +// ap.arg("-v", &verbose) +// .help("Verbose output"); +// ap.arg("-m %s:NAMES", &metamatch) +// .help("Metadata names to print (default: all)"); +// ap.arg("-f", &filenameprefix) +// .help("Prefix each line with the filename"); +// ap.arg("-s", &sum) +// .help("Sum the image sizes"); +// ap.arg("-a", &subimages) +// .help("Print info about all subimages") +// .action(ArgParse::store_true()); +// ap.arg("--hash", &compute_sha1) +// .help("Print SHA-1 hash of pixel values") +// .action(ArgParse::store_true()); +// ap.arg("--stats", &compute_stats) +// .help("Print image pixel statistics (data window)"); +// // clang-format on +// if (ap.parse(argc, argv) < 0 || filenames.empty()) { +// std::cerr << ap.geterror() << std::endl; +// ap.print_help(); +// return help ? EXIT_SUCCESS : EXIT_FAILURE; +// } + +// if (!metamatch.empty()) { +// field_re.assign(metamatch, std::regex_constants::extended +// | std::regex_constants::icase); +// } + +// // Find the longest filename +// size_t longestname = 0; +// for (auto&& s : filenames) +// longestname = std::max(longestname, s.length()); +// longestname = std::min(longestname, (size_t)40); + +// int returncode = EXIT_SUCCESS; +// long long totalsize = 0; +// for (auto&& s : filenames) { +// auto in = ImageInput::open(s); +// if (!in) { +// std::string err = geterror(); +// print(std::cerr, "iinfo ERROR: \"{}\" : {}\n", s, +// err.size() ? err : std::string("Could not open file.")); +// returncode = EXIT_FAILURE; +// continue; +// } +// ImageSpec spec = in->spec(); +// print_info(s, longestname, in.get(), spec, verbose, sum, totalsize); +// } + +// if (sum) +// print("Total size: {}\n", Strutil::memformat(totalsize)); + +// shutdown(); +// return returncode; +// } diff --git a/Sources/OpenImageIO/include/OpenImageIO/detail/fmt/fmt.cc b/Sources/OpenImageIO/include/OpenImageIO/detail/fmt/fmt.cc index b8808129..d8665c23 100644 --- a/Sources/OpenImageIO/include/OpenImageIO/detail/fmt/fmt.cc +++ b/Sources/OpenImageIO/include/OpenImageIO/detail/fmt/fmt.cc @@ -102,5 +102,5 @@ extern "C++" { //module : private; #endif -#include "format.cc" -#include "os.cc" +//#include "format.cc" +//#include "os.cc" diff --git a/Sources/OpenImageIO/libOpenImageIO/color_test.cpp b/Sources/OpenImageIO/libOpenImageIO/color_test.cpp deleted file mode 100644 index aff34a23..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/color_test.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace OIIO; -using namespace simd; - - -// Aid for things that are too short to benchmark accurately -#define REP10(x) x, x, x, x, x, x, x, x, x, x - -static int iterations = 1000000; -static int ntrials = 5; -static bool verbose = false; - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("color_test\n" OIIO_INTRO_STRING) - .usage("color_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--iters %d", &iterations) - .help(Strutil::fmt::format("Number of iterations (default: {})", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -static void -test_sRGB_conversion() -{ - Benchmarker bench; - - OIIO_CHECK_EQUAL_THRESH(linear_to_sRGB(0.0f), 0.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(linear_to_sRGB(1.0f), 1.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(linear_to_sRGB(0.5f), 0.735356983052449f, 1.0e-6); - - OIIO_CHECK_EQUAL_THRESH(sRGB_to_linear(0.0f), 0.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(sRGB_to_linear(1.0f), 1.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(sRGB_to_linear(0.5f), 0.214041140482232f, 1.0e-6); - - // Check the SIMD versions, too - OIIO_CHECK_SIMD_EQUAL_THRESH(linear_to_sRGB(vfloat4(0.0f)), vfloat4(0.0f), - 1.0e-5); - OIIO_CHECK_SIMD_EQUAL_THRESH(linear_to_sRGB(vfloat4(1.0f)), vfloat4(1.0f), - 1.0e-5); - OIIO_CHECK_SIMD_EQUAL_THRESH(linear_to_sRGB(vfloat4(0.5f)), - vfloat4(0.735356983052449f), 1.0e-5); - - OIIO_CHECK_SIMD_EQUAL_THRESH(sRGB_to_linear(vfloat4(0.0f)), vfloat4(0.0f), - 1.0e-5); - OIIO_CHECK_SIMD_EQUAL_THRESH(sRGB_to_linear(vfloat4(1.0f)), vfloat4(1.0f), - 1.0e-5); - OIIO_CHECK_SIMD_EQUAL_THRESH(sRGB_to_linear(vfloat4(0.5f)), - vfloat4(0.214041140482232f), 1.0e-5); - - float fval = 0.5f; - clobber(fval); - vfloat4 vfval(fval); - clobber(vfval); - bench("sRGB_to_linear", - [&]() { return DoNotOptimize(sRGB_to_linear(fval)); }); - bench("linear_to_sRGB", - [&]() { return DoNotOptimize(sRGB_to_linear(fval)); }); - bench.work(4); - bench("sRGB_to_linear simd", - [&]() { return DoNotOptimize(sRGB_to_linear(vfval)); }); - bench("linear_to_sRGB simd", - [&]() { return DoNotOptimize(sRGB_to_linear(vfval)); }); -} - - - -static void -test_Rec709_conversion() -{ - Benchmarker bench; - - OIIO_CHECK_EQUAL_THRESH(linear_to_Rec709(0.0f), 0.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(linear_to_Rec709(1.0f), 1.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(linear_to_Rec709(0.5f), 0.705515089922121f, 1.0e-6); - - OIIO_CHECK_EQUAL_THRESH(Rec709_to_linear(0.0f), 0.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(Rec709_to_linear(1.0f), 1.0f, 1.0e-6); - OIIO_CHECK_EQUAL_THRESH(Rec709_to_linear(0.5f), 0.259589400506286f, 1.0e-6); - - float fval = 0.5f; - clobber(fval); - bench("Rec709_to_linear", - [&]() { return DoNotOptimize(Rec709_to_linear(fval)); }); - bench("linear_to_Rec709", - [&]() { return DoNotOptimize(Rec709_to_linear(fval)); }); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - test_sRGB_conversion(); - test_Rec709_conversion(); - - return unit_test_failures != 0; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/compute_test.cpp b/Sources/OpenImageIO/libOpenImageIO/compute_test.cpp deleted file mode 100644 index 2b7358af..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/compute_test.cpp +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -// -// Task: take "images" A and B, and compute R = A*A + B. -// -// Do this a whole bunch of different ways and benchmark. -// - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - -static int iterations = 0; -static int numthreads = Sysutil::hardware_concurrency(); -static int ntrials = 5; -static bool verbose = false; -static bool wedge = false; -static bool allgpus = false; - -static spin_mutex print_mutex; // make the prints not clobber each other - -static int xres = 1920, yres = 1080, channels = 3; -static int npixels = xres * yres; -static int size = npixels * channels; -static ImageBuf imgA, imgB, imgR; - - - -static void test_arrays(ROI) -{ - const float* a = (const float*)imgA.localpixels(); - OIIO_DASSERT(a); - const float* b = (const float*)imgB.localpixels(); - OIIO_DASSERT(b); - float* r = (float*)imgR.localpixels(); - OIIO_DASSERT(r); - for (int x = 0; x < size; ++x) - r[x] = a[x] * a[x] + b[x]; -} - - - -static void -test_arrays_like_image(ROI roi) -{ - const float* a = (const float*)imgA.localpixels(); - OIIO_DASSERT(a); - const float* b = (const float*)imgB.localpixels(); - OIIO_DASSERT(b); - float* r = (float*)imgR.localpixels(); - OIIO_DASSERT(r); - int nchannels = imgA.nchannels(); - for (int y = roi.ybegin; y < roi.yend; ++y) { - for (int x = roi.xbegin; x < roi.xend; ++x) { - int i = (y * xres + x) * nchannels; - for (int c = 0; c < nchannels; ++c) - r[i + c] = a[i + c] * a[i + c] + b[i + c]; - } - } -} - - - -static void test_arrays_simd4(ROI) -{ - const float* a = (const float*)imgA.localpixels(); - OIIO_DASSERT(a); - const float* b = (const float*)imgB.localpixels(); - OIIO_DASSERT(b); - float* r = (float*)imgR.localpixels(); - OIIO_DASSERT(r); - int x, end4 = size - (size & 3); - for (x = 0; x < end4; x += 4, a += 4, b += 4, r += 4) { - simd::vfloat4 a_simd(a), b_simd(b); - *(simd::vfloat4*)r = a_simd * a_simd + b_simd; - } - for (; x < size; ++x, ++a, ++b, ++r) { - *r = a[0] * a[0] + b[0]; - } -} - - - -static void -test_arrays_like_image_simd(ROI roi) -{ - const float* a = (const float*)imgA.localpixels(); - OIIO_DASSERT(a); - const float* b = (const float*)imgB.localpixels(); - OIIO_DASSERT(b); - float* r = (float*)imgR.localpixels(); - OIIO_DASSERT(r); - int nchannels = imgA.nchannels(); - for (int y = roi.ybegin; y < roi.yend; ++y) { - for (int x = roi.xbegin; x < roi.xend; ++x) { - int i = (y * xres + x) * nchannels; - simd::vfloat4 a_simd, b_simd, r_simd; - a_simd.load(a + i, 3); - b_simd.load(b + i, 3); - r_simd = a_simd * a_simd + b_simd; - r_simd.store(r + i, 3); - } - } -} - - - -static void -test_IBA(ROI roi, int threads) -{ - ImageBufAlgo::mad(imgR, imgA, imgA, imgB, roi, threads); -} - - - -void -test_compute() -{ - Benchmarker bench; - bench.iterations(iterations); - bench.trials(ntrials); - bench.work(xres * yres * channels); - bench.units(Benchmarker::Unit::ms); - - ROI roi(0, xres, 0, yres, 0, 1, 0, channels); - - ImageBufAlgo::zero(imgR); - bench("1D array loop", test_arrays, roi); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - // imgR.write ("ref.exr"); - - ImageBufAlgo::zero(imgR); - bench("iterated as image", test_arrays_like_image, roi); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("iterated as image, threaded", - [&]() { ImageBufAlgo::parallel_image(roi, test_arrays_like_image); }); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("1D array loop, SIMD", test_arrays_simd4, roi); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("iterated as image, SIMD", test_arrays_like_image_simd, roi); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("iterated as image, SIMD, threaded", [&]() { - ImageBufAlgo::parallel_image(roi, test_arrays_like_image_simd); - }); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("IBA::mad 1 thread", test_IBA, roi, 1); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); - - ImageBufAlgo::zero(imgR); - bench("IBA::mad threaded", test_IBA, roi, numthreads); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 0), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 1), 0.25, - 0.001); - OIIO_CHECK_EQUAL_THRESH(imgR.getchannel(xres / 2, yres / 2, 0, 2), 0.50, - 0.001); -} - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("compute_test\n" OIIO_INTRO_STRING) - .usage("compute_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--allgpus", &allgpus) - .help("Run OpenCL tests on all devices, not just default"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - // Initialize - imgA.reset(ImageSpec(xres, yres, channels, TypeDesc::FLOAT)); - imgB.reset(ImageSpec(xres, yres, channels, TypeDesc::FLOAT)); - imgR.reset(ImageSpec(xres, yres, channels, TypeDesc::FLOAT)); - float red[3] = { 1, 0, 0 }; - float green[3] = { 0, 1, 0 }; - float blue[3] = { 0, 0, 1 }; - float black[3] = { 0, 0, 0 }; - ImageBufAlgo::fill(imgA, red, green, red, green); - ImageBufAlgo::fill(imgB, blue, blue, black, black); - // imgA.write ("A.exr"); - // imgB.write ("B.exr"); - - test_compute(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imagebuf_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imagebuf_test.cpp deleted file mode 100644 index 69bdcdef..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imagebuf_test.cpp +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include -#include -#include -#include - -#include - -using namespace OIIO; - - - -inline int -test_wrap(wrap_impl wrap, int coord, int origin, int width) -{ - wrap(coord, origin, width); - return coord; -} - - -void -test_wrapmodes() -{ - const int ori = 0; - const int w = 4; - static int val[] = { -7, -6, -5, -4, -3, -2, -1, 0, 1, - 2, 3, 4, 5, 6, 7, 8, 9, -10 }, - cla[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3 }, - per[] = { 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1 }, - mir[] = { 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2, 1, 0, 0, 1 }; - - for (int i = 0; val[i] > -10; ++i) { - OIIO_CHECK_EQUAL(test_wrap(wrap_clamp, val[i], ori, w), cla[i]); - OIIO_CHECK_EQUAL(test_wrap(wrap_periodic, val[i], ori, w), per[i]); - OIIO_CHECK_EQUAL(test_wrap(wrap_periodic_pow2, val[i], ori, w), per[i]); - OIIO_CHECK_EQUAL(test_wrap(wrap_mirror, val[i], ori, w), mir[i]); - } -} - - - -void -test_is_imageio_format_name() -{ - OIIO_CHECK_EQUAL(is_imageio_format_name(""), false); - OIIO_CHECK_EQUAL(is_imageio_format_name("openexr"), true); - OIIO_CHECK_EQUAL(is_imageio_format_name("OpEnExR"), true); - OIIO_CHECK_EQUAL(is_imageio_format_name("tiff"), true); - OIIO_CHECK_EQUAL(is_imageio_format_name("tiffx"), false); - OIIO_CHECK_EQUAL(is_imageio_format_name("blort"), false); -} - - - -// Test iterators -template -void -iterator_read_test() -{ - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 3; - static float buf[HEIGHT][WIDTH][CHANNELS] - = { { { 0, 0, 0 }, { 1, 0, 1 }, { 2, 0, 2 }, { 3, 0, 3 } }, - { { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 3, 1, 7 } }, - { { 0, 2, 8 }, { 1, 2, 9 }, { 2, 2, 10 }, { 3, 2, 11 } }, - { { 0, 3, 12 }, { 1, 3, 13 }, { 2, 3, 14 }, { 3, 3, 15 } } }; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec, buf); - - ITERATOR p(A); - OIIO_CHECK_EQUAL(p[0], 0.0f); - OIIO_CHECK_EQUAL(p[1], 0.0f); - OIIO_CHECK_EQUAL(p[2], 0.0f); - - // Explicit position - p.pos(2, 1); - OIIO_CHECK_EQUAL(p.x(), 2); - OIIO_CHECK_EQUAL(p.y(), 1); - OIIO_CHECK_EQUAL(p[0], 2.0f); - OIIO_CHECK_EQUAL(p[1], 1.0f); - OIIO_CHECK_EQUAL(p[2], 6.0f); - - // Iterate a few times - ++p; - OIIO_CHECK_EQUAL(p.x(), 3); - OIIO_CHECK_EQUAL(p.y(), 1); - OIIO_CHECK_EQUAL(p[0], 3.0f); - OIIO_CHECK_EQUAL(p[1], 1.0f); - OIIO_CHECK_EQUAL(p[2], 7.0f); - ++p; - OIIO_CHECK_EQUAL(p.x(), 0); - OIIO_CHECK_EQUAL(p.y(), 2); - OIIO_CHECK_EQUAL(p[0], 0.0f); - OIIO_CHECK_EQUAL(p[1], 2.0f); - OIIO_CHECK_EQUAL(p[2], 8.0f); - - std::cout << "iterator_read_test result:"; - int i = 0; - for (ITERATOR p(A); !p.done(); ++p, ++i) { - if ((i % 4) == 0) - std::cout << "\n "; - std::cout << " " << p[0] << ' ' << p[1] << ' ' << p[2]; - } - std::cout << "\n"; -} - - - -// Test iterators -template -void -iterator_wrap_test(ImageBuf::WrapMode wrap, std::string wrapname) -{ - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 3; - static float buf[HEIGHT][WIDTH][CHANNELS] - = { { { 0, 0, 0 }, { 1, 0, 1 }, { 2, 0, 2 }, { 3, 0, 3 } }, - { { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 3, 1, 7 } }, - { { 0, 2, 8 }, { 1, 2, 9 }, { 2, 2, 10 }, { 3, 2, 11 } }, - { { 0, 3, 12 }, { 1, 3, 13 }, { 2, 3, 14 }, { 3, 3, 15 } } }; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec, buf); - - std::cout << "iterator_wrap_test " << wrapname << ":"; - int i = 0; - int noutside = 0; - for (ITERATOR p(A, ROI(-2, WIDTH + 2, -2, HEIGHT + 2), wrap); !p.done(); - ++p, ++i) { - if ((i % 8) == 0) - std::cout << "\n "; - std::cout << " " << p[0] << ' ' << p[1] << ' ' << p[2]; - // Check wraps - if (!p.exists()) { - ++noutside; - if (wrap == ImageBuf::WrapBlack) { - OIIO_CHECK_EQUAL(p[0], 0.0f); - OIIO_CHECK_EQUAL(p[1], 0.0f); - OIIO_CHECK_EQUAL(p[2], 0.0f); - } else if (wrap == ImageBuf::WrapClamp) { - ITERATOR q = p; - q.pos(clamp(p.x(), 0, WIDTH - 1), clamp(p.y(), 0, HEIGHT - 1)); - OIIO_CHECK_EQUAL(p[0], q[0]); - OIIO_CHECK_EQUAL(p[1], q[1]); - OIIO_CHECK_EQUAL(p[2], q[2]); - } else if (wrap == ImageBuf::WrapPeriodic) { - ITERATOR q = p; - q.pos(p.x() % WIDTH, p.y() % HEIGHT); - OIIO_CHECK_EQUAL(p[0], q[0]); - OIIO_CHECK_EQUAL(p[1], q[1]); - OIIO_CHECK_EQUAL(p[2], q[2]); - } else if (wrap == ImageBuf::WrapMirror) { - ITERATOR q = p; - int x = p.x(), y = p.y(); - wrap_mirror(x, 0, WIDTH); - wrap_mirror(y, 0, HEIGHT); - q.pos(x, y); - OIIO_CHECK_EQUAL(p[0], q[0]); - OIIO_CHECK_EQUAL(p[1], q[1]); - OIIO_CHECK_EQUAL(p[2], q[2]); - } - } - } - std::cout << "\n"; - OIIO_CHECK_EQUAL(noutside, 48); // Should be 48 wrapped pixels -} - - - -// Tests ImageBuf construction from application buffer -void -ImageBuf_test_appbuffer() -{ - const int WIDTH = 8; - const int HEIGHT = 8; - const int CHANNELS = 3; - // clang-format off - float buf[HEIGHT][WIDTH][CHANNELS] = { - { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }, - { {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0} }, - { {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0} }, - { {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0} }, - { {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0} }, - { {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0} }, - { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {1,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }, - { {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} } - }; - // clang-format on - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec, buf); - - // Make sure A now points to the buffer - OIIO_CHECK_EQUAL((void*)A.pixeladdr(0, 0, 0), (void*)buf); - - // write it - A.write("A_imagebuf_test.tif"); - - // Read it back and make sure it matches the original - ImageBuf B("A_imagebuf_test.tif"); - for (int y = 0; y < HEIGHT; ++y) - for (int x = 0; x < WIDTH; ++x) - for (int c = 0; c < WIDTH; ++c) - OIIO_CHECK_EQUAL(A.getchannel(x, y, 0, c), - B.getchannel(x, y, 0, c)); - - // Make sure we can write to the buffer - float pix[CHANNELS] = { 0.0, 42.0, 0 }; - A.setpixel(3, 2, 0, pix); - OIIO_CHECK_EQUAL(buf[2][3][1], 42.0); - - // Make sure we can copy-construct the ImageBuf and it points to the - // same application buffer. - ImageBuf C(A); - OIIO_CHECK_EQUAL((void*)A.pixeladdr(0, 0, 0), (void*)C.pixeladdr(0, 0, 0)); - - // Test that channel and pixel strides work - OIIO_CHECK_EQUAL((float*)A.pixeladdr(0, 0, 0, 1), - (float*)A.pixeladdr(0, 0, 0) + 1); - OIIO_CHECK_EQUAL(A.pixel_stride(), (stride_t)sizeof(float) * CHANNELS); -} - - - -void -ImageBuf_test_appbuffer_strided() -{ - Strutil::print("Testing strided app buffers\n"); - - // Make a 16x16 x 3chan float buffer, fill with zero - const int res = 16, nchans = 3; - float mem[res][res][nchans]; - memset(mem, 0, res * res * nchans * sizeof(float)); - - // Wrap the whole buffer, fill with green - ImageBuf wrapped(ImageSpec(res, res, nchans, TypeFloat), mem); - const float green[nchans] = { 0.0f, 1.0f, 0.0f }; - ImageBufAlgo::fill(wrapped, green); - float color[nchans] = { -1, -1, -1 }; - OIIO_CHECK_ASSERT(ImageBufAlgo::isConstantColor(wrapped, 0.0f, color) - && color[0] == 0.0f && color[1] == 1.0f - && color[2] == 0.0f); - - // Do a strided wrap in the interior: a 3x3 image with extra spacing - // between pixels and rows, and fill it with red. - ImageBuf strided(ImageSpec(3, 3, nchans, TypeFloat), &mem[4][4][0], - 2 * nchans * sizeof(float) /* every other pixel */, - 2 * res * nchans * sizeof(float) /* ever other line */); - const float red[nchans] = { 1.0f, 0.0f, 0.0f }; - ImageBufAlgo::fill(strided, red); - - // The strided IB ought to look all-red - OIIO_CHECK_ASSERT(ImageBufAlgo::isConstantColor(strided, 0.0f, color) - && color[0] == 1.0f && color[1] == 0.0f - && color[2] == 0.0f); - - // The wrapped IB ought NOT to look like one color - OIIO_CHECK_ASSERT(!ImageBufAlgo::isConstantColor(wrapped, 0.0f, color)); - - // Write both to disk and make sure they are what we think they are - { - strided.write("stridedfill.tif", TypeUInt8); - ImageBuf test("stridedfill.tif"); // read it back - float color[nchans] = { -1, -1, -1 }; - OIIO_CHECK_ASSERT(ImageBufAlgo::isConstantColor(test, 0.0f, color) - && color[0] == 1.0f && color[1] == 0.0f - && color[2] == 0.0f); - } - { - wrapped.write("wrappedfill.tif", TypeUInt8); - ImageBuf test("wrappedfill.tif"); // read it back - // Slightly tricky test because of the strides - for (int y = 0; y < res; ++y) { - for (int x = 0; x < res; ++x) { - float pixel[nchans]; - test.getpixel(x, y, pixel); - if ((x == 4 || x == 6 || x == 8) - && (y == 4 || y == 6 || y == 8)) { - OIIO_CHECK_ASSERT(cspan(pixel) == cspan(red)); - } else { - OIIO_CHECK_ASSERT(cspan(pixel) - == cspan(green)); - } - } - } - } -} - - - -void -test_open_with_config() -{ - // N.B. This function must run after ImageBuf_test_appbuffer, which - // writes "A.tif". - ImageCache* ic = ImageCache::create(false); - ImageSpec config; - config.attribute("oiio:DebugOpenConfig!", 1); - ImageBuf A("A_imagebuf_test.tif", 0, 0, ic, &config); - OIIO_CHECK_EQUAL(A.spec().get_int_attribute("oiio:DebugOpenConfig!", 0), - 42); - // Clear A because it would be unwise to let the ImageBuf outlive the - // custom ImageCache we passed it to use. - A.clear(); - ic->destroy(ic); -} - - - -void -test_empty_iterator() -{ - // Ensure that ImageBuf iterators over empty ROIs immediately appear - // done - ImageBuf A(ImageSpec(64, 64, 3, TypeDesc::FLOAT)); - ROI roi(10, 10, 20, 40, 0, 1); - for (ImageBuf::Iterator p(A, roi); !p.done(); ++p) { - std::cout << "p is " << p.x() << ' ' << p.y() << ' ' << p.z() << "\n"; - OIIO_CHECK_ASSERT(0 && "should never execute this loop body"); - } -} - - - -void -print(const ImageBuf& A) -{ - OIIO_DASSERT(A.spec().format == TypeDesc::FLOAT); - for (ImageBuf::ConstIterator p(A); !p.done(); ++p) { - std::cout << " @" << p.x() << ',' << p.y() << "=("; - for (int c = 0; c < A.nchannels(); ++c) - std::cout << (c ? "," : "") << p[c]; - std::cout << ')' << (p.x() == A.xmax() ? "\n" : ""); - } - std::cout << "\n"; -} - - - -void -test_set_get_pixels() -{ - std::cout << "\nTesting set_pixels, get_pixels:\n"; - const int nchans = 3; - ImageBuf A(ImageSpec(4, 4, nchans, TypeDesc::FLOAT)); - ImageBufAlgo::zero(A); - std::cout << " Cleared:\n"; - print(A); - float newdata[2 * 2 * nchans] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; - A.set_pixels(ROI(1, 3, 1, 3), TypeDesc::FLOAT, newdata); - std::cout << " After set:\n"; - print(A); - float retrieved[2 * 2 * nchans] = { 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; - A.get_pixels(ROI(1, 3, 1, 3, 0, 1), TypeDesc::FLOAT, retrieved); - OIIO_CHECK_ASSERT(0 == memcmp(retrieved, newdata, 2 * 2 * nchans)); -} - - - -void -time_get_pixels() -{ - std::cout << "\nTesting set_pixels, get_pixels:\n"; - Benchmarker bench; - const int nchans = 4; - const int xres = 2000, yres = 1000; - ImageBuf A(ImageSpec(xres, yres, nchans, TypeDesc::FLOAT)); - ImageBufAlgo::zero(A); - - // bench.work (size_t(xres*yres*nchans)); - std::unique_ptr fbuf(new float[xres * yres * nchans]); - bench("get_pixels 1Mpelx4 float[4]->float[4] ", - [&]() { A.get_pixels(A.roi(), TypeFloat, fbuf.get()); }); - bench("get_pixels 1Mpelx4 float[4]->float[3] ", [&]() { - ROI roi3 = A.roi(); - roi3.chend = 3; - A.get_pixels(roi3, TypeFloat, fbuf.get()); - }); - - std::unique_ptr ucbuf(new uint8_t[xres * yres * nchans]); - bench("get_pixels 1Mpelx4 float[4]->uint8[4] ", - [&]() { A.get_pixels(A.roi(), TypeUInt8, ucbuf.get()); }); - - std::unique_ptr usbuf(new uint16_t[xres * yres * nchans]); - bench("get_pixels 1Mpelx4 float[4]->uint16[4] ", - [&]() { A.get_pixels(A.roi(), TypeUInt8, usbuf.get()); }); -} - - - -void -test_read_channel_subset() -{ - std::cout << "\nTesting reading a channel subset\n"; - - // FIrst, write a test image with 6 channels - static float color6[] = { 0.6f, 0.5f, 0.4f, 0.3f, 0.2f, 0.1f }; - ImageBuf A(ImageSpec(2, 2, 6, TypeDesc::FLOAT)); - ImageBufAlgo::fill(A, color6); - A.write("sixchans.tif"); - std::cout << " Start with image:\n"; - print(A); - - // Now read it back using the "channel range" option. - ImageBuf B("sixchans.tif"); - B.read(0 /*subimage*/, 0 /*mip*/, 2 /*chbegin*/, 5 /*chend*/, - true /*force*/, TypeDesc::FLOAT); - std::cout << " After reading channels [2,5), we have:\n"; - print(B); - OIIO_CHECK_EQUAL(B.nativespec().nchannels, 6); - OIIO_CHECK_EQUAL(B.spec().nchannels, 3); - OIIO_CHECK_EQUAL(B.spec().format, TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(B.spec().channelnames[0], "B"); - OIIO_CHECK_EQUAL(B.spec().channelnames[1], "A"); - OIIO_CHECK_EQUAL(B.spec().channelnames[2], "channel4"); - for (ImageBuf::ConstIterator p(B); !p.done(); ++p) { - OIIO_CHECK_EQUAL(p[0], 0.4f); - OIIO_CHECK_EQUAL(p[1], 0.3f); - OIIO_CHECK_EQUAL(p[2], 0.2f); - } -} - - - -void -test_roi() -{ - std::cout << "Testing ROI functions for ImageSpec and ImageBuf\n"; - ROI datawin(10, 640, 20, 480, 0, 1, 0, 3); - ROI displaywin(0, 512, 30, 100, 0, 1, 0, 3); - ROI initroi(0, 256, 0, 300, 0, 1, 0, 3); - - // Test roi set and retrieve on an ImageSpec - ImageSpec spec(256, 300, 3); - OIIO_CHECK_EQUAL(spec.roi(), initroi); - OIIO_CHECK_EQUAL(spec.roi_full(), initroi); - spec.set_roi(datawin); - spec.set_roi_full(displaywin); - OIIO_CHECK_EQUAL(spec.roi(), datawin); - OIIO_CHECK_EQUAL(spec.roi_full(), displaywin); - - // Test roi set and retrieve on an ImageSBuf - ImageBuf buf((ImageSpec(datawin))); - OIIO_CHECK_EQUAL(buf.roi(), datawin); - OIIO_CHECK_EQUAL(buf.roi_full(), datawin); - buf.set_roi_full(displaywin); - OIIO_CHECK_EQUAL(buf.roi(), datawin); - OIIO_CHECK_EQUAL(buf.roi_full(), displaywin); - - OIIO_CHECK_ASSERT(buf.contains_roi(datawin)); - OIIO_CHECK_ASSERT(buf.contains_roi(ROI(100, 110, 100, 110, 0, 1, 0, 2))); - OIIO_CHECK_ASSERT( - !buf.contains_roi(ROI(0, 640, 0, 480, 0, 1, 0, 3))); // outside xy - OIIO_CHECK_ASSERT( - !buf.contains_roi(ROI(10, 640, 20, 480, 1, 2, 0, 3))); // outside z - OIIO_CHECK_ASSERT( - !buf.contains_roi(ROI(10, 640, 20, 480, 0, 1, 0, 4))); // outside ch -} - - - -// Test what happens when we read, replace the image on disk, then read -// again. -void -test_write_over() -{ - // Write two images - { - ImageBuf img(ImageSpec(16, 16, 3, TypeUInt8)); - ImageBufAlgo::fill(img, { 0.0f, 1.0f, 0.0f }); - img.write("tmp-green.tif"); - Sysutil::usleep(1000000); // make sure times are different - ImageBufAlgo::fill(img, { 1.0f, 0.0f, 0.0f }); - img.write("tmp-red.tif"); - } - - // Read the image - float pixel[3]; - ImageBuf A("tmp-green.tif"); - A.getpixel(4, 4, pixel); - OIIO_CHECK_ASSERT(pixel[0] == 0 && pixel[1] == 1 && pixel[2] == 0); - A.reset(); // make sure A isn't held open, we're about to remove it - - // Replace the green image with red, under the nose of the ImageBuf. - Filesystem::remove("tmp-green.tif"); - Filesystem::copy("tmp-red.tif", "tmp-green.tif"); - - // Read the image again -- different ImageBuf. - // We expect it to have the new color, not have the underlying - // ImageCache misremember the old color! - ImageBuf B("tmp-green.tif"); - B.getpixel(4, 4, pixel); - OIIO_CHECK_ASSERT(pixel[0] == 1 && pixel[1] == 0 && pixel[2] == 0); - B.reset(); // make sure B isn't held open, we're about to remove it - - Filesystem::remove("tmp-green.tif"); -} - - - -static void -test_uncaught_error() -{ - ImageBuf buf; - buf.error("Boo!"); - // buf exists scope and is destroyed without anybody retrieving the error. -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - // Some miscellaneous things that aren't strictly ImageBuf, but this is - // as good a place to verify them as any. - test_wrapmodes(); - test_is_imageio_format_name(); - test_roi(); - - // Lots of tests related to ImageBuf::Iterator - test_empty_iterator(); - iterator_read_test>(); - iterator_read_test>(); - - iterator_wrap_test>(ImageBuf::WrapBlack, - "black"); - iterator_wrap_test>(ImageBuf::WrapClamp, - "clamp"); - iterator_wrap_test>(ImageBuf::WrapPeriodic, - "periodic"); - iterator_wrap_test>(ImageBuf::WrapMirror, - "mirror"); - - ImageBuf_test_appbuffer(); - ImageBuf_test_appbuffer_strided(); - test_open_with_config(); - test_read_channel_subset(); - - test_set_get_pixels(); - time_get_pixels(); - - test_write_over(); - - test_uncaught_error(); - - Filesystem::remove("A_imagebuf_test.tif"); - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imagebufalgo_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imagebufalgo_test.cpp deleted file mode 100644 index b7629887..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imagebufalgo_test.cpp +++ /dev/null @@ -1,1203 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include - -#include - -#if USE_OPENCV -// Suppress gcc 11 / C++20 errors about opencv 4 headers -# if OIIO_GNUC_VERSION >= 110000 && OIIO_CPLUSPLUS_VERSION >= 20 -# pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion" -# endif -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - - -static int iterations = 1; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; -static int threadcounts[] = { 1, 2, 4, 8, 12, 16, 20, - 24, 28, 32, 64, 128, 1024, 1 << 30 }; - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("imagebufalgo_test\n" OIIO_INTRO_STRING) - .usage("imagebufalgo_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -void -test_type_merge() -{ - std::cout << "test type_merge\n"; - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::UINT8, TypeDesc::UINT8), - TypeDesc::UINT8); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::UINT8, TypeDesc::FLOAT), - TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::FLOAT, TypeDesc::UINT8), - TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::UINT8, TypeDesc::UINT16), - TypeDesc::UINT16); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::UINT16, TypeDesc::FLOAT), - TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::HALF, TypeDesc::FLOAT), - TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::HALF, TypeDesc::UINT8), - TypeDesc::HALF); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::HALF, TypeDesc::UNKNOWN), - TypeDesc::HALF); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::FLOAT, - TypeDesc::UNKNOWN), - TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(TypeDesc::basetype_merge(TypeDesc::UINT8, - TypeDesc::UNKNOWN), - TypeDesc::UINT8); -} - - - -// Helper: make an IB filled with a constant value, with a spec that -// describes the image shape. -static ImageBuf -filled_image(cspan value, const ImageSpec& spec) -{ - ImageBuf buf(spec); - ImageBufAlgo::fill(buf, value); - return buf; -} - -// Helper: make an IB filled with a constant value, with given resolution and -// data type (defaulting to 4x4 float), with number of channels determined by -// the size of the value array). -static ImageBuf -filled_image(cspan value, int width = 4, int height = 4, - TypeDesc dtype = TypeDesc::FLOAT) -{ - ImageSpec spec(width, height, std::ssize(value), dtype); - return filled_image(value, spec); -} - -// Helper: make a 4x4 IB filled with a constant value, with given data type -// (defaulting to float), with number of channels determined by the size of -// the value array). -inline ImageBuf -filled_image(cspan value, TypeDesc dtype) -{ - return filled_image(value, 4, 4, dtype); -} - - - -// Test ImageBuf::zero and ImageBuf::fill -void -test_zero_fill() -{ - std::cout << "test zero_fill\n"; - const int WIDTH = 8; - const int HEIGHT = 6; - const int CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - spec.alpha_channel = 3; - - // Create a buffer -- pixels should be undefined - ImageBuf A(spec); - - // Set a pixel to an odd value, make sure it takes - const float arbitrary1[CHANNELS] = { 0.2f, 0.3f, 0.4f, 0.5f }; - A.setpixel(1, 1, arbitrary1); - float pixel[CHANNELS]; // test pixel - A.getpixel(1, 1, pixel); - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], arbitrary1[c]); - - // Zero out and test that it worked - ImageBufAlgo::zero(A); - for (int j = 0; j < HEIGHT; ++j) { - for (int i = 0; i < WIDTH; ++i) { - float pixel[CHANNELS]; - A.getpixel(i, j, pixel); - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], 0.0f); - } - } - - // Test fill of whole image - const float arbitrary2[CHANNELS] = { 0.6f, 0.7f, 0.3f, 0.9f }; - ImageBufAlgo::fill(A, arbitrary2); - for (int j = 0; j < HEIGHT; ++j) { - for (int i = 0; i < WIDTH; ++i) { - float pixel[CHANNELS]; - A.getpixel(i, j, pixel); - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], arbitrary2[c]); - } - } - - // Test fill of partial image - const float arbitrary3[CHANNELS] = { 0.42f, 0.43f, 0.44f, 0.45f }; - { - const int xbegin = 3, xend = 5, ybegin = 0, yend = 4; - ImageBufAlgo::fill(A, arbitrary3, ROI(xbegin, xend, ybegin, yend)); - for (int j = 0; j < HEIGHT; ++j) { - for (int i = 0; i < WIDTH; ++i) { - float pixel[CHANNELS]; - A.getpixel(i, j, pixel); - if (j >= ybegin && j < yend && i >= xbegin && i < xend) { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], arbitrary3[c]); - } else { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], arbitrary2[c]); - } - } - } - } - - // Timing - Benchmarker bench; - ImageBuf buf_rgba_float(ImageSpec(1000, 1000, 4, TypeFloat)); - ImageBuf buf_rgba_uint8(ImageSpec(1000, 1000, 4, TypeUInt8)); - ImageBuf buf_rgba_half(ImageSpec(1000, 1000, 4, TypeHalf)); - ImageBuf buf_rgba_uint16(ImageSpec(1000, 1000, 4, TypeDesc::UINT16)); - float vals[] = { 0, 0, 0, 0 }; - bench(" IBA::fill float[4] ", - [&]() { ImageBufAlgo::fill(buf_rgba_float, vals); }); - bench(" IBA::fill uint8[4] ", - [&]() { ImageBufAlgo::fill(buf_rgba_uint8, vals); }); - bench(" IBA::fill uint16[4] ", - [&]() { ImageBufAlgo::fill(buf_rgba_uint16, vals); }); - bench(" IBA::fill half[4] ", - [&]() { ImageBufAlgo::fill(buf_rgba_half, vals); }); -} - - - -// Test ImageBuf::copy -void -test_copy() -{ - std::cout << "test copy\n"; - - // Make image A red, image B green, copy part of B to A and check result - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - // copy region we'll work with - ROI roi(2, 4, 1, 3); - ImageBuf A(spec), B(spec); - float red[4] = { 1, 0, 0, 1 }; - float green[4] = { 0, 0, 0.5, 0.5 }; - ImageBufAlgo::fill(A, red); - ImageBufAlgo::fill(B, green); - ImageBufAlgo::copy(A, B, TypeUnknown, roi); - for (ImageBuf::ConstIterator r(A); !r.done(); ++r) { - if (roi.contains(r.x(), r.y())) { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], green[c]); - } else { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], red[c]); - } - } - - // Test copying into a blank image - A.clear(); - ImageBufAlgo::copy(A, B, TypeUnknown, roi); - for (ImageBuf::ConstIterator r(A); !r.done(); ++r) { - if (roi.contains(r.x(), r.y())) { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], green[c]); - } else { - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(r[c], 0.0f); - } - } - - // Timing - Benchmarker bench; - ImageSpec spec_rgba_float(1000, 1000, 4, TypeFloat); - ImageSpec spec_rgba_uint8(1000, 1000, 4, TypeUInt8); - ImageSpec spec_rgba_half(1000, 1000, 4, TypeHalf); - ImageSpec spec_rgba_int16(1000, 1000, 4, TypeDesc::INT16); - ImageBuf buf_rgba_uint8(spec_rgba_uint8); - ImageBuf buf_rgba_float(spec_rgba_float); - ImageBuf buf_rgba_float2(spec_rgba_float); - ImageBuf buf_rgba_half(spec_rgba_half); - ImageBuf buf_rgba_half2(spec_rgba_half); - ImageBuf empty; - bench(" IBA::copy float[4] -> float[4] ", - [&]() { ImageBufAlgo::copy(buf_rgba_float, buf_rgba_float2); }); - bench(" IBA::copy float[4] -> empty ", [&]() { - empty.clear(); - ImageBufAlgo::copy(empty, buf_rgba_float2); - }); - bench(" IBA::copy float[4] -> uint8[4] ", - [&]() { ImageBufAlgo::copy(buf_rgba_uint8, buf_rgba_float2); }); - bench(" IBA::copy half[4] -> half[4] ", - [&]() { ImageBufAlgo::copy(buf_rgba_half, buf_rgba_half2); }); - bench(" IBA::copy half[4] -> empty ", [&]() { - empty.clear(); - ImageBufAlgo::copy(empty, buf_rgba_half2); - }); -} - - - -// Test ImageBuf::crop -void -test_crop() -{ - std::cout << "test crop\n"; - int WIDTH = 8, HEIGHT = 6, CHANNELS = 4; - // Crop region we'll work with - int xbegin = 3, xend = 5, ybegin = 0, yend = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - spec.alpha_channel = 3; - ImageBuf A, B; - A.reset(spec); - B.reset(spec); - float arbitrary1[4]; - arbitrary1[0] = 0.2f; - arbitrary1[1] = 0.3f; - arbitrary1[2] = 0.4f; - arbitrary1[3] = 0.5f; - ImageBufAlgo::fill(A, arbitrary1); - - // Test CUT crop - ImageBufAlgo::crop(B, A, ROI(xbegin, xend, ybegin, yend)); - - // Should have changed the data window (origin and width/height) - OIIO_CHECK_EQUAL(B.spec().x, xbegin); - OIIO_CHECK_EQUAL(B.spec().width, xend - xbegin); - OIIO_CHECK_EQUAL(B.spec().y, ybegin); - OIIO_CHECK_EQUAL(B.spec().height, yend - ybegin); - float* pixel = OIIO_ALLOCA(float, CHANNELS); - for (int j = 0; j < B.spec().height; ++j) { - for (int i = 0; i < B.spec().width; ++i) { - B.getpixel(i + B.xbegin(), j + B.ybegin(), pixel); - // Inside the crop region should match what it always was - for (int c = 0; c < CHANNELS; ++c) - OIIO_CHECK_EQUAL(pixel[c], arbitrary1[c]); - } - } -} - - - -void -test_paste() -{ - std::cout << "test paste\n"; - // Create the source image, make it a color gradient - ImageSpec Aspec(4, 4, 3, TypeDesc::FLOAT); - ImageBuf A(Aspec); - for (ImageBuf::Iterator it(A); !it.done(); ++it) { - it[0] = float(it.x()) / float(Aspec.width - 1); - it[1] = float(it.y()) / float(Aspec.height - 1); - it[2] = 0.1f; - } - - // Create destination image -- fill with grey - ImageSpec Bspec(8, 8, 3, TypeDesc::FLOAT); - ImageBuf B(Bspec); - float gray[3] = { 0.1f, 0.1f, 0.1f }; - ImageBufAlgo::fill(B, gray); - - // Paste a few pixels from A into B -- include offsets - ImageBufAlgo::paste(B, 2, 2, 0, 1 /* chan offset */, - ImageBufAlgo::cut(A, ROI(1, 4, 1, 4))); - - // Spot check - float a[3], b[3]; - B.getpixel(1, 1, 0, b); - OIIO_CHECK_EQUAL(b[0], gray[0]); - OIIO_CHECK_EQUAL(b[1], gray[1]); - OIIO_CHECK_EQUAL(b[2], gray[2]); - - B.getpixel(2, 2, 0, b); - A.getpixel(1, 1, 0, a); - OIIO_CHECK_EQUAL(b[0], gray[0]); - OIIO_CHECK_EQUAL(b[1], a[0]); - OIIO_CHECK_EQUAL(b[2], a[1]); - - B.getpixel(3, 4, 0, b); - A.getpixel(2, 3, 0, a); - OIIO_CHECK_EQUAL(b[0], gray[0]); - OIIO_CHECK_EQUAL(b[1], a[0]); - OIIO_CHECK_EQUAL(b[2], a[1]); -} - - - -void -test_channel_append() -{ - std::cout << "test channel_append\n"; - ImageSpec spec(2, 2, 1, TypeDesc::FLOAT); - ImageBuf A(spec); - ImageBuf B(spec); - float Acolor = 0.1, Bcolor = 0.2; - ImageBufAlgo::fill(A, &Acolor); - ImageBufAlgo::fill(B, &Bcolor); - - ImageBuf R = ImageBufAlgo::channel_append(A, B); - OIIO_CHECK_EQUAL(R.spec().width, spec.width); - OIIO_CHECK_EQUAL(R.spec().height, spec.height); - OIIO_CHECK_EQUAL(R.nchannels(), 2); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) { - OIIO_CHECK_EQUAL(r[0], Acolor); - OIIO_CHECK_EQUAL(r[1], Bcolor); - } -} - - - -// Tests ImageBufAlgo::add -void -test_add() -{ - std::cout << "test add\n"; - - // Create buffers - const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; - const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBuf A = filled_image(Aval); - ImageBuf B = filled_image(Bval); - - // Test addition of images - ImageBuf R = ImageBufAlgo::add(A, B); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) - for (int c = 0, nc = R.nchannels(); c < nc; ++c) - OIIO_CHECK_EQUAL(r[c], Aval[c] + Bval[c]); - - // Test addition of image and constant color - ImageBuf D = ImageBufAlgo::add(A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Tests ImageBufAlgo::sub -void -test_sub() -{ - std::cout << "test sub\n"; - - // Create buffers - const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; - const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBuf A = filled_image(Aval); - ImageBuf B = filled_image(Bval); - - // Test subtraction of images - ImageBuf R = ImageBufAlgo::sub(A, B); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) - for (int c = 0, nc = R.nchannels(); c < nc; ++c) - OIIO_CHECK_EQUAL(r[c], Aval[c] - Bval[c]); - - // Test subtraction of image and constant color - ImageBuf D = ImageBufAlgo::sub(A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Tests ImageBufAlgo::mul -void -test_mul() -{ - std::cout << "test mul\n"; - - // Create buffers - // Create buffers - const float Aval[] = { 0.1f, 0.2f, 0.3f, 0.4f }; - const float Bval[] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBuf A = filled_image(Aval); - ImageBuf B = filled_image(Bval); - - // Test multiplication of images - ImageBuf R = ImageBufAlgo::mul(A, B); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) - for (int c = 0, nc = R.nchannels(); c < nc; ++c) - OIIO_CHECK_EQUAL(r[c], Aval[c] * Bval[c]); - - // Test multiplication of image and constant color - ImageBuf D = ImageBufAlgo::mul(A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Tests ImageBufAlgo::mad -void -test_mad() -{ - std::cout << "test mad\n"; - const int WIDTH = 4, HEIGHT = 4, CHANNELS = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - - // Create buffers - ImageBuf A(spec); - const float Aval[CHANNELS] = { 0.1f, 0.2f, 0.3f, 0.4f }; - ImageBufAlgo::fill(A, Aval); - ImageBuf B(spec); - const float Bval[CHANNELS] = { 1, 2, 3, 4 }; - ImageBufAlgo::fill(B, Bval); - ImageBuf C(spec); - const float Cval[CHANNELS] = { 0.01f, 0.02f, 0.03f, 0.04f }; - ImageBufAlgo::fill(C, Cval); - - // Test multiplication of images - ImageBuf R(spec); - ImageBufAlgo::mad(R, A, B, C); - for (int j = 0; j < spec.height; ++j) - for (int i = 0; i < spec.width; ++i) - for (int c = 0; c < spec.nchannels; ++c) - OIIO_CHECK_EQUAL(R.getchannel(i, j, 0, c), - Aval[c] * Bval[c] + Cval[c]); - - // Test multiplication of image and constant color - ImageBuf D(spec); - ImageBufAlgo::mad(D, A, Bval, Cval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Tests ImageBufAlgo::min -void -test_min() -{ - std::cout << "test min\n"; - - // Create buffers - const float Aval[] = { 0.1f, 0.02f, 0.3f, 0.04f }; - const float Bval[] = { 0.01f, 0.2f, 0.03f, 0.4f }; - ImageBuf A = filled_image(Aval); - ImageBuf B = filled_image(Bval); - - // Test min of images - ImageBuf R = ImageBufAlgo::min(A, B); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) - for (int c = 0, nc = R.nchannels(); c < nc; ++c) - OIIO_CHECK_EQUAL(r[c], std::min(Aval[c], Bval[c])); - - // Test min of image and constant color - ImageBuf D = ImageBufAlgo::min(A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Tests ImageBufAlgo::max -void -test_max() -{ - std::cout << "test max\n"; - - // Create buffers - const float Aval[] = { 0.1f, 0.02f, 0.3f, 0.04f }; - const float Bval[] = { 0.01f, 0.2f, 0.03f, 0.4f }; - ImageBuf A = filled_image(Aval); - ImageBuf B = filled_image(Bval); - - // Test max of images - ImageBuf R = ImageBufAlgo::max(A, B); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) - for (int c = 0, nc = R.nchannels(); c < nc; ++c) - OIIO_CHECK_EQUAL(r[c], std::max(Aval[c], Bval[c])); - - // Test max of image and constant color - ImageBuf D = ImageBufAlgo::max(A, Bval); - auto comp = ImageBufAlgo::compare(R, D, 1e-6f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -} - - - -// Test ImageBuf::over -void -test_over(TypeDesc dtype = TypeFloat) -{ - std::cout << "test over " << dtype << "\n"; - - ROI roi(2, 4, 1, 3); // region with fg - - // Create buffers - const float BGval[] = { 0.5f, 0.0f, 0.0f, 0.5f }; - ImageBuf BG = filled_image(BGval, dtype); - - ImageBuf FG = filled_image({ 0.0f, 0.0f, 0.0f, 0.0f }, dtype); - const float FGval[] = { 0.0f, 0.5f, 0.0f, 0.5f }; - ImageBufAlgo::fill(FG, FGval, roi); - - // value it should be where composited - const float comp_val[] = { 0.25f, 0.5f, 0.0f, 0.75f }; - - // Test over - ImageBuf R = ImageBufAlgo::over(FG, BG); - int nc = R.nchannels(); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) { - if (roi.contains(r.x(), r.y())) - for (int c = 0; c < nc; ++c) - OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), comp_val[c]); - else - for (int c = 0; c < nc; ++c) - OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), BGval[c]); - } - - // Timing - Benchmarker bench; - ImageSpec onekfloat(1000, 1000, 4, TypeFloat); - BG = filled_image(BGval, 1000, 1000); - FG = filled_image({ 0.0f, 0.0f, 0.0f, 0.0f }, 1000, 1000); - ImageBufAlgo::fill(FG, FGval, ROI(250, 750, 100, 900)); - R.reset(onekfloat); - bench(" IBA::over ", [&]() { ImageBufAlgo::over(R, FG, BG); }); -} - - - -// Test ImageBuf::zover -void -test_zover() -{ - std::cout << "test zover\n"; - - ImageSpec spec(4, 4, 5, TypeFloat); - spec.channelnames.assign({ "R", "G", "B", "A", "Z" }); - spec.z_channel = 4; - - ROI roi(2, 4, 1, 3); // region with fg - - // Create buffers - const float Aval[] = { 0.5f, 0.5, 0.5, 1.0f, 10.0f }; // z == 10 - ImageBuf A = filled_image(Aval, spec); - - ImageBuf B = filled_image({ 0.0f, 0.0f, 0.0f, 1.0f, 15.0f }, spec); - const float Bval[] = { 1.0f, 1.0f, 1.0f, 1.0f, 5.0f }; - ImageBufAlgo::fill(B, Bval, roi); - - // Test zover - ImageBuf R = ImageBufAlgo::zover(A, B, true); - int nc = R.nchannels(); - for (ImageBuf::ConstIterator r(R); !r.done(); ++r) { - if (roi.contains(r.x(), r.y())) - for (int c = 0; c < nc; ++c) - OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), Bval[c]); - else - for (int c = 0; c < nc; ++c) - OIIO_CHECK_EQUAL(R.getchannel(r.x(), r.y(), 0, c), Aval[c]); - } -} - - - -// Tests ImageBufAlgo::compare -void -test_compare() -{ - std::cout << "test compare\n"; - // Construct two identical 50% grey images - const int WIDTH = 10, HEIGHT = 10, CHANNELS = 3; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec); - ImageBuf B(spec); - const float grey[CHANNELS] = { 0.5f, 0.5f, 0.5f }; - ImageBufAlgo::fill(A, grey); - ImageBufAlgo::fill(B, grey); - - // Introduce some minor differences - const int NDIFFS = 10; - ImageBuf::Iterator a(A); - for (int i = 0; i < NDIFFS && a.valid(); ++i, ++a) { - for (int c = 0; c < CHANNELS; ++c) - a[c] = a[c] + 0.01f * i; - } - // We expect the differences to be { 0, 0.01, 0.02, 0.03, 0.04, 0.05, - // 0.06, 0.07, 0.08, 0.09, 0, 0, ...}. - const float failthresh = 0.05; - const float warnthresh = 0.025; - auto comp = ImageBufAlgo::compare(A, B, failthresh, warnthresh); - // We expect 5 pixels to exceed the fail threshold, 7 pixels to - // exceed the warn threshold, the maximum difference to be 0.09, - // and the maximally different pixel to be (9,0). - // The total error should be 3 chans * sum{0.01,...,0.09} / (pixels*chans) - // = 3 * 0.45 / (100*3) = 0.0045 - std::cout << "Testing comparison: " << comp.nfail << " failed, " - << comp.nwarn << " warned, max diff = " << comp.maxerror << " @ (" - << comp.maxx << ',' << comp.maxy << ")\n"; - std::cout << " mean err " << comp.meanerror << ", RMS err " - << comp.rms_error << ", PSNR = " << comp.PSNR << "\n"; - OIIO_CHECK_EQUAL(comp.nfail, 5); - OIIO_CHECK_EQUAL(comp.nwarn, 7); - OIIO_CHECK_EQUAL_THRESH(comp.maxerror, 0.09f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxx, 9); - OIIO_CHECK_EQUAL(comp.maxy, 0); - OIIO_CHECK_EQUAL_THRESH(comp.meanerror, 0.0045f, 1.0e-8f); - - // Relative comparison: warn at 5% of the difference, fail at 10% of the - // difference. In row 0, we have: - // A: 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 0.50 - // B: 0.50 0.51 0.52 0.53 0.54 0.55 0.56 0.57 0.58 0.59 - // mean: 0.50 0.505 0.51 0.515 0.52 0.525 0.53 0.535 0.54 0.545 - // diff: 0.0 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 - // fail? x x x x - // warn? x x x x x x x - comp = ImageBufAlgo::compare(A, B, 0.0f, 0.0f, 0.1f, 0.05f); - // We expect 4 pixels to exceed the fail threshold, 7 pixels to - // exceed the warn threshold, the maximum difference to be 0.09, - // and the maximally different pixel to be (9,0). - // The total error should be 3 chans * sum{0.01,...,0.09} / (pixels*chans) - // = 3 * 0.45 / (100*3) = 0.0045 - std::cout << "Testing relative comparison: " << comp.nfail << " failed, " - << comp.nwarn << " warned, max diff = " << comp.maxerror << " @ (" - << comp.maxx << ',' << comp.maxy << ")\n"; - std::cout << " mean err " << comp.meanerror << ", RMS err " - << comp.rms_error << ", PSNR = " << comp.PSNR << "\n"; - OIIO_CHECK_EQUAL(comp.nfail, 4); - OIIO_CHECK_EQUAL(comp.nwarn, 7); - OIIO_CHECK_EQUAL_THRESH(comp.maxerror, 0.09f, 1e-6f); - OIIO_CHECK_EQUAL(comp.maxx, 9); - OIIO_CHECK_EQUAL(comp.maxy, 0); - OIIO_CHECK_EQUAL_THRESH(comp.meanerror, 0.0045f, 1.0e-8f); -} - - - -// Tests ImageBufAlgo::isConstantColor -void -test_isConstantColor() -{ - std::cout << "test isConstantColor\n"; - const int WIDTH = 10, HEIGHT = 10, CHANNELS = 3; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec); - const float col[CHANNELS] = { 0.25, 0.5, 0.75 }; - ImageBufAlgo::fill(A, col); - - float thecolor[CHANNELS] = { 0, 0, 0 }; - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A), true); - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A, thecolor), true); - OIIO_CHECK_EQUAL(col[0], thecolor[0]); - OIIO_CHECK_EQUAL(col[1], thecolor[1]); - OIIO_CHECK_EQUAL(col[2], thecolor[2]); - - // Now introduce a difference - const float another[CHANNELS] = { 0.25f, 0.51f, 0.75f }; - A.setpixel(2, 2, 0, another, 3); - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A), false); - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A, thecolor), false); - // But not with lower threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A, 0.015f), true); - - // Make sure ROI works - ROI roi(0, WIDTH, 0, 2, 0, 1, 0, CHANNELS); // should match for this ROI - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantColor(A, 0.0f, {}, roi), true); -} - - - -// Tests ImageBufAlgo::isConstantChannel -void -test_isConstantChannel() -{ - std::cout << "test isConstantChannel\n"; - const int WIDTH = 10, HEIGHT = 10, CHANNELS = 3; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec); - const float col[CHANNELS] = { 0.25f, 0.5f, 0.75f }; - ImageBufAlgo::fill(A, col); - - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantChannel(A, 1, 0.5f), true); - - // Now introduce a difference - const float another[CHANNELS] = { 0.25f, 0.51f, 0.75f }; - A.setpixel(2, 2, 0, another, 3); - // It should still pass if within the threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantChannel(A, 1, 0.5f, 0.015f), true); - // But not with lower threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantChannel(A, 1, 0.5f, 0.005), false); - // And certainly not with zero threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantChannel(A, 1, 0.5f), false); - - // Make sure ROI works - ROI roi(0, WIDTH, 0, 2, 0, 1, 0, CHANNELS); // should match for this ROI - OIIO_CHECK_EQUAL(ImageBufAlgo::isConstantChannel(A, 1, 0.5f, roi = roi), - true); -} - - - -// Tests ImageBufAlgo::isMonochrome -void -test_isMonochrome() -{ - std::cout << "test isMonochrome\n"; - const int WIDTH = 10, HEIGHT = 10, CHANNELS = 3; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec); - const float col[CHANNELS] = { 0.25f, 0.25f, 0.25f }; - ImageBufAlgo::fill(A, col); - - OIIO_CHECK_EQUAL(ImageBufAlgo::isMonochrome(A), true); - - // Now introduce a tiny difference - const float another[CHANNELS] = { 0.25f, 0.25f, 0.26f }; - A.setpixel(2, 2, 0, another, 3); - // It should still pass if within the threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isMonochrome(A, 0.015f), true); - // But not with lower threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isMonochrome(A, 0.005f), false); - // And certainly not with zero threshold - OIIO_CHECK_EQUAL(ImageBufAlgo::isMonochrome(A), false); - - - // Make sure ROI works - ROI roi(0, WIDTH, 0, 2, 0, 1, 0, CHANNELS); // should match for this ROI - OIIO_CHECK_EQUAL(ImageBufAlgo::isMonochrome(A, roi), true); -} - - - -// Tests ImageBufAlgo::computePixelStats() -void -test_computePixelStats() -{ - std::cout << "test computePixelStats\n"; - ImageBuf img(ImageSpec(2, 2, 3, TypeDesc::FLOAT)); - float black[3] = { 0, 0, 0 }, white[3] = { 1, 1, 1 }; - img.setpixel(0, 0, black); - img.setpixel(1, 0, white); - img.setpixel(0, 1, black); - img.setpixel(1, 1, white); - auto stats = ImageBufAlgo::computePixelStats(img); - for (int c = 0; c < 3; ++c) { - OIIO_CHECK_EQUAL(stats.min[c], 0.0f); - OIIO_CHECK_EQUAL(stats.max[c], 1.0f); - OIIO_CHECK_EQUAL(stats.avg[c], 0.5f); - OIIO_CHECK_EQUAL(stats.stddev[c], 0.5f); - OIIO_CHECK_EQUAL(stats.nancount[c], 0); - OIIO_CHECK_EQUAL(stats.infcount[c], 0); - OIIO_CHECK_EQUAL(stats.finitecount[c], 4); - } -} - - - -// Tests histogram computation. -void -histogram_computation_test() -{ - const int INPUT_WIDTH = 64; - const int INPUT_HEIGHT = 64; - const int INPUT_CHANNEL = 0; - - const int HISTOGRAM_BINS = 256; - - const int SPIKE1 = 51; // 0.2f in range 0->1 maps to 51 in range 0->255 - const int SPIKE2 = 128; // 0.5f in range 0->1 maps to 128 in range 0->255 - const int SPIKE3 = 204; // 0.8f in range 0->1 maps to 204 in range 0->255 - - const int SPIKE1_COUNT = INPUT_WIDTH * 8; - const int SPIKE2_COUNT = INPUT_WIDTH * 16; - const int SPIKE3_COUNT = INPUT_WIDTH * 40; - - // Create input image with three regions with different pixel values. - ImageSpec spec(INPUT_WIDTH, INPUT_HEIGHT, 1, TypeDesc::FLOAT); - ImageBuf A(spec); - - float value[] = { 0.2f }; - ImageBufAlgo::fill(A, value, ROI(0, INPUT_WIDTH, 0, 8)); - - value[0] = 0.5f; - ImageBufAlgo::fill(A, value, ROI(0, INPUT_WIDTH, 8, 24)); - - value[0] = 0.8f; - ImageBufAlgo::fill(A, value, ROI(0, INPUT_WIDTH, 24, 64)); - - // Compute A's histogram. - std::vector hist = ImageBufAlgo::histogram(A, INPUT_CHANNEL, - HISTOGRAM_BINS); - - // Does the histogram size equal the number of bins? - OIIO_CHECK_EQUAL(hist.size(), (imagesize_t)HISTOGRAM_BINS); - - // Are the histogram values as expected? - OIIO_CHECK_EQUAL(hist[SPIKE1], (imagesize_t)SPIKE1_COUNT); - OIIO_CHECK_EQUAL(hist[SPIKE2], (imagesize_t)SPIKE2_COUNT); - OIIO_CHECK_EQUAL(hist[SPIKE3], (imagesize_t)SPIKE3_COUNT); - for (int i = 0; i < HISTOGRAM_BINS; i++) - if (i != SPIKE1 && i != SPIKE2 && i != SPIKE3) - OIIO_CHECK_EQUAL(hist[i], 0); -} - - - -// Test ability to do a maketx directly from an ImageBuf -void -test_maketx_from_imagebuf() -{ - std::cout << "test make_texture from ImageBuf\n"; - // Make a checkerboard - const int WIDTH = 16, HEIGHT = 16, CHANNELS = 3; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - ImageBuf A(spec); - float pink[] = { 0.5f, 0.3f, 0.3f }, green[] = { 0.1f, 0.5f, 0.1f }; - ImageBufAlgo::checker(A, 4, 4, 4, pink, green); - - // Write it - const char* pgname = "oiio-pgcheck.tx"; - remove(pgname); // Remove it first - ImageSpec configspec; - ImageBufAlgo::make_texture(ImageBufAlgo::MakeTxTexture, A, pgname, - configspec); - - // Read it back and compare it - ImageBuf B(pgname); - B.read(); - auto comparison = ImageBufAlgo::compare(A, B, 0, 0); - OIIO_CHECK_EQUAL(comparison.nwarn, 0); - OIIO_CHECK_EQUAL(comparison.nfail, 0); - remove(pgname); // clean up -} - - - -// Test various IBAprep features -void -test_IBAprep() -{ - std::cout << "test IBAprep\n"; - using namespace ImageBufAlgo; - ImageBuf rgb(ImageSpec(256, 256, 3)); // Basic RGB uint8 image - ImageBuf rgba(ImageSpec(256, 256, 4)); // Basic RGBA uint8 image - -#define CHECK(...) \ - { \ - ImageBuf dst; \ - ROI roi; \ - OIIO_CHECK_ASSERT(IBAprep(__VA_ARGS__)); \ - } -#define CHECK0(...) \ - { \ - ImageBuf dst; \ - ROI roi; \ - OIIO_CHECK_ASSERT(!IBAprep(__VA_ARGS__)); \ - } - - // Test REQUIRE_ALPHA - CHECK(roi, &dst, &rgba, IBAprep_REQUIRE_ALPHA); - CHECK0(roi, &dst, &rgb, IBAprep_REQUIRE_ALPHA); - - // Test REQUIRE_Z - ImageSpec rgbaz_spec(256, 256, 5); - rgbaz_spec.channelnames[4] = std::string("Z"); - rgbaz_spec.z_channel = 4; - ImageBuf rgbaz(rgbaz_spec); - CHECK(roi, &dst, &rgbaz, IBAprep_REQUIRE_Z); - CHECK0(roi, &dst, &rgb, IBAprep_REQUIRE_Z); - - // Test REQUIRE_SAME_NCHANNELS - CHECK(roi, &dst, &rgb, &rgb, NULL, NULL, IBAprep_REQUIRE_SAME_NCHANNELS); - CHECK0(roi, &dst, &rgb, &rgba, NULL, NULL, IBAprep_REQUIRE_SAME_NCHANNELS); - - // Test NO_SUPPOERT_VOLUME - ImageSpec volspec(256, 256, 3); - volspec.depth = 256; - ImageBuf vol(volspec); - CHECK(roi, &dst, &rgb, IBAprep_NO_SUPPORT_VOLUME); - CHECK0(roi, &dst, &vol, IBAprep_NO_SUPPORT_VOLUME); - - // Test SUPPORT_DEEP - ImageSpec deepspec(256, 256, 3); - deepspec.deep = true; - ImageBuf deep(deepspec); - CHECK(roi, &dst, &deep, IBAprep_SUPPORT_DEEP); - CHECK0(roi, &dst, &deep); // deep should be rejected - - // Test DEEP_MIXED - CHECK(roi, &dst, &deep, &deep, NULL, - IBAprep_SUPPORT_DEEP | IBAprep_DEEP_MIXED); - CHECK(roi, &dst, &deep, &rgb, NULL, - IBAprep_SUPPORT_DEEP | IBAprep_DEEP_MIXED); - CHECK(roi, &dst, &deep, &deep, NULL, IBAprep_SUPPORT_DEEP); - CHECK0(roi, &dst, &deep, &rgb, NULL, IBAprep_SUPPORT_DEEP); - - // Test DST_FLOAT_PIXELS - { - ROI roi1, roi2; - ImageBuf dst1, dst2; - OIIO_CHECK_ASSERT(IBAprep(roi1, &dst1, &rgb)); - OIIO_CHECK_EQUAL(dst1.spec().format, TypeDesc::UINT8); - OIIO_CHECK_ASSERT(IBAprep(roi2, &dst2, &rgb, IBAprep_DST_FLOAT_PIXELS)); - OIIO_CHECK_EQUAL(dst2.spec().format, TypeDesc::FLOAT); - } - - // Test MINIMIZE_NCHANNELS - { - ROI roi1, roi2; - ImageBuf dst1, dst2; - OIIO_CHECK_ASSERT(IBAprep(roi1, &dst1, &rgb, &rgba)); - OIIO_CHECK_EQUAL(dst1.nchannels(), 4); - OIIO_CHECK_ASSERT(IBAprep(roi2, &dst2, &rgb, &rgba, NULL, NULL, - IBAprep_MINIMIZE_NCHANNELS)); - OIIO_CHECK_EQUAL(dst2.nchannels(), 3); - } -#undef CHECK -} - - - -// Test extra validation checks done by `st_warp` -void -test_validate_st_warp_checks() -{ - // using namespace ImageBufAlgo; - std::cout << "test st_warp validation checks" << std::endl; - - const int size = 16; - ImageSpec srcSpec(size, size, 3, TypeDesc::FLOAT); - ImageBuf SRC(srcSpec); - ImageBuf ST; - ImageBuf DST; - - ImageBufAlgo::zero(SRC); - - // Fail: Uninitialized ST buffer - OIIO_CHECK_ASSERT(!ImageBufAlgo::st_warp(DST, SRC, ST)); - - ROI disjointROI(size, size, size * 2, size * 2, 0, 1, 0, 2); - ImageSpec stSpec(disjointROI, TypeDesc::HALF); - ST.reset(stSpec); - // Fail: Non-intersecting ST and output ROIs - OIIO_CHECK_ASSERT(!ImageBufAlgo::st_warp(DST, SRC, ST)); - - stSpec = ImageSpec(size, size, 2, TypeDesc::HALF); - ST.reset(stSpec); - - DST.reset(); - // Fail: Out-of-range chan_s - OIIO_CHECK_ASSERT(!ImageBufAlgo::st_warp(DST, SRC, ST, nullptr, 2)); - // Fail: Out-of-range chan_t - OIIO_CHECK_ASSERT(!ImageBufAlgo::st_warp(DST, SRC, ST, nullptr, 0, 2)); - // Success - OIIO_CHECK_ASSERT(ImageBufAlgo::st_warp(DST, SRC, ST, nullptr)); -} - - -void -benchmark_parallel_image(int res, int iters) -{ - using namespace ImageBufAlgo; - std::cout << "\nTime old parallel_image for " << res << "x" << res - << std::endl; - - std::cout << " threads time rate (best of " << ntrials << ")\n"; - std::cout << " ------- ------- -------\n"; - ImageSpec spec(res, res, 3, TypeDesc::FLOAT); - ImageBuf X(spec), Y(spec); - float one[] = { 1, 1, 1 }; - ImageBufAlgo::zero(Y); - ImageBufAlgo::fill(X, one); - float a = 0.5f; - - // Lambda that does some exercise (a basic SAXPY) - auto exercise = [&](ROI roi) { - ImageBuf::Iterator y(Y, roi); - ImageBuf::ConstIterator x(X, roi); - for (; !y.done(); ++y, ++x) - for (int c = roi.chbegin; c < roi.chend; ++c) - y[c] = a * x[c] + y[c]; - }; - - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = wedge ? threadcounts[i] : numthreads; - ImageBufAlgo::zero(Y); - auto func = [&]() { - ImageBufAlgo::parallel_image(Y.roi(), nt, exercise); - }; - double range; - double t = time_trial(func, ntrials, iters, &range) / iters; - std::cout << Strutil::sprintf(" %4d %7.3f ms %5.1f Mpels/s\n", nt, - t * 1000, double(res * res) / t / 1.0e6); - if (!wedge) - break; // don't loop if we're not wedging - } - - std::cout << "\nTime new parallel_image for " << res << "x" << res << "\n"; - - std::cout << " threads time rate (best of " << ntrials << ")\n"; - std::cout << " ------- ------- -------\n"; - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = wedge ? threadcounts[i] : numthreads; - // default_thread_pool()->resize (nt); - zero(Y); - auto func = [&]() { parallel_image(Y.roi(), nt, exercise); }; - double range; - double t = time_trial(func, ntrials, iters, &range) / iters; - std::cout << Strutil::sprintf(" %4d %6.2f ms %5.1f Mpels/s\n", nt, - t * 1000, double(res * res) / t / 1.0e6); - if (!wedge) - break; // don't loop if we're not wedging - } -} - - - -void -test_opencv() -{ -#if USE_OPENCV - std::cout << "Testing OpenCV round trip\n"; - // Make a gradient RGB image, convert to OpenCV cv::Mat, then convert - // that back to ImageBuf, make sure the round trip has the same pixels - // as the original image. - ImageBuf src - = ImageBufAlgo::fill({ 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f }, { 1.0f, 1.0f, 1.0f }, - ROI(0, 64, 0, 64, 0, 1, 0, 3)); - cv::Mat mat; - ImageBufAlgo::to_OpenCV(mat, src); - OIIO_CHECK_ASSERT(!mat.empty()); - ImageBuf dst = ImageBufAlgo::from_OpenCV(mat); - OIIO_CHECK_ASSERT(!dst.has_error()); - auto comp = ImageBufAlgo::compare(src, dst, 0.0f, 0.0f); - OIIO_CHECK_EQUAL(comp.error, false); - OIIO_CHECK_EQUAL(comp.maxerror, 0.0f); -#endif -} - - - -void -test_color_management() -{ - ColorConfig config; - - // Test the IBA::colorconvert version that works on a color at a time - { - auto processor = config.createColorProcessor("lin_srgb", "srgb"); - float rgb[3] = { 0.5f, 0.5f, 0.5f }; - ImageBufAlgo::colorconvert(rgb, processor.get(), false); - OIIO_CHECK_EQUAL_THRESH(rgb[1], 0.735356983052449f, 1.0e-5); - } - { - auto processor = config.createColorProcessor("lin_srgb", "srgb"); - float rgb[4] = { 0.5f, 0.5f, 0.5f, 1.0f }; - ImageBufAlgo::colorconvert(rgb, processor.get(), true); - OIIO_CHECK_EQUAL_THRESH(rgb[1], 0.735356983052449f, 1.0e-5); - } -} - - - -static void -test_yee() -{ - print("Testing Yee comparison\n"); - ImageSpec spec(1, 1, 3, TypeDesc::FLOAT); - ImageBuf img1(spec); - ImageBufAlgo::fill(img1, { 0.1f, 0.1f, 0.1f }); - ImageBuf img2(spec); - ImageBufAlgo::fill(img2, { 0.1f, 0.6f, 0.1f }); - ImageBufAlgo::CompareResults cr; - int n = ImageBufAlgo::compare_Yee(img1, img2, cr); - OIIO_CHECK_EQUAL(n, 1); - OIIO_CHECK_EQUAL(cr.maxx, 0); - OIIO_CHECK_EQUAL(cr.maxy, 0); -} - - - -int -main(int argc, char** argv) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - test_type_merge(); - test_zero_fill(); - test_copy(); - test_crop(); - test_paste(); - test_channel_append(); - test_add(); - test_sub(); - test_mul(); - test_mad(); - test_min(); - test_max(); - test_over(TypeFloat); - test_over(TypeHalf); - test_zover(); - test_compare(); - test_isConstantColor(); - test_isConstantChannel(); - test_isMonochrome(); - test_computePixelStats(); - histogram_computation_test(); - test_maketx_from_imagebuf(); - test_IBAprep(); - test_validate_st_warp_checks(); - test_opencv(); - test_color_management(); - test_yee(); - - benchmark_parallel_image(64, iterations * 64); - benchmark_parallel_image(512, iterations * 16); - benchmark_parallel_image(1024, iterations * 4); - benchmark_parallel_image(2048, iterations); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imagecache_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imagecache_test.cpp deleted file mode 100644 index ba47a57e..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imagecache_test.cpp +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include -#include -#include - -#include - -using namespace OIIO; - - -static ustring udimpattern; -static ustring checkertex; -static std::vector files_to_delete; - - - -static void -create_temp_textures() -{ - // Make a texture - { - std::string temp_dir = Filesystem::temp_directory_path(); - OIIO_ASSERT(temp_dir.size()); - udimpattern = ustring::fmtformat("{}/checkertex..exr", temp_dir); - checkertex = ustring::fmtformat("{}/checkertex.1001.exr", temp_dir); - ImageBuf check = ImageBuf(ImageSpec(256, 256, 3, TypeUInt8)); - ImageBufAlgo::checker(check, 16, 16, 1, { 0.0f, 0.0f, 0.0f }, - { 1.0f, 1.0f, 1.0f }, 0, 0, 0); - ImageSpec config; - config.format = TypeHalf; - ImageBufAlgo::make_texture(ImageBufAlgo::MakeTxTexture, check, - checkertex, config); - check.write(checkertex); - files_to_delete.push_back(checkertex); - } - - ustring badfile("badfile.exr"); - Filesystem::write_text_file(badfile, "blahblah"); - files_to_delete.push_back(badfile); -} - - - -// Test various get_pixels error handling -static void -test_get_pixels_errors() -{ - Strutil::print("\nTesting get_pixels error handling\n"); - ImageCache* ic = ImageCache::create(); - float fpixels[4 * 4 * 3]; - const int fpixelsize = 3 * sizeof(float); - - OIIO_CHECK_FALSE(ic->get_pixels(ustring("noexist.exr"), 0, 0, 0, 2, 0, 2, 0, - 1, TypeFloat, fpixels)); - OIIO_CHECK_ASSERT(ic->has_error()); - Strutil::print("get_pixels of non-existant file:\n {}\n", ic->geterror()); - - OIIO_CHECK_FALSE(ic->get_pixels(ustring("badfile.exr"), 0, 0, 0, 2, 0, 2, 0, - 1, TypeFloat, fpixels)); - OIIO_CHECK_ASSERT(ic->has_error()); - Strutil::print("get_pixels of badfile:\n {}\n", ic->geterror()); - - OIIO_CHECK_FALSE( - ic->get_pixels(checkertex, 8, 0, 0, 2, 0, 2, 0, 1, TypeFloat, fpixels)); - Strutil::print("get_pixels of out-of-range subimage:\n {}\n", - ic->geterror()); - - OIIO_CHECK_FALSE(ic->get_pixels(checkertex, 0, 20, 0, 2, 0, 2, 0, 1, - TypeFloat, fpixels)); - Strutil::print("get_pixels of out-of-range miplevel:\n {}\n", - ic->geterror()); - - OIIO_CHECK_FALSE(ic->get_pixels(udimpattern, 0, 0, 0, 2, 0, 2, 0, 1, - TypeFloat, fpixels)); - Strutil::print("get_pixels of udim pattern:\n {}\n", ic->geterror()); - - // Check asking for out of range z - memset(fpixels, 255, sizeof(fpixels)); - OIIO_CHECK_ASSERT( - ic->get_pixels(checkertex, 0, 0, 0, 2, 0, 2, 1, 2, TypeFloat, fpixels)); - OIIO_CHECK_EQUAL(fpixels[0], 0.0f); - // and again for non-contiguous strides - memset(fpixels, 255, sizeof(fpixels)); - OIIO_CHECK_ASSERT(ic->get_pixels(checkertex, 0, 0, 0, 2, 0, 2, 1, 2, 0, 3, - TypeFloat, fpixels, 2 * fpixelsize)); - OIIO_CHECK_EQUAL(fpixels[0], 0.0f); - - // Check asking for out of range y - memset(fpixels, 255, sizeof(fpixels)); - OIIO_CHECK_ASSERT(ic->get_pixels(checkertex, 0, 0, 0, 2, 10000, 10001, 0, 1, - TypeFloat, fpixels)); - OIIO_CHECK_EQUAL(fpixels[0], 0.0f); - // and again for non-contiguous strides - memset(fpixels, 255, sizeof(fpixels)); - OIIO_CHECK_ASSERT(ic->get_pixels(checkertex, 0, 0, 0, 2, 10000, 10001, 0, 1, - 0, 3, TypeFloat, fpixels, 2 * fpixelsize)); - OIIO_CHECK_EQUAL(fpixels[0], 0.0f); - - // Check asking for out of range x - memset(fpixels, 255, sizeof(fpixels)); - OIIO_CHECK_ASSERT(ic->get_pixels(checkertex, 0, 0, 10000, 10001, 0, 2, 0, 1, - TypeFloat, fpixels)); - OIIO_CHECK_EQUAL(fpixels[0], 0.0f); -} - - - -// Tests various ways for the subset of channels to be cached in a -// many-channel image. -void -test_get_pixels_cachechannels(int chbegin = 0, int chend = 4, - int cache_chbegin = 0, int cache_chend = -1) -{ - std::cout << "\nTesting IC get_pixels of chans [" << chbegin << "," << chend - << ") with cache range [" << cache_chbegin << "," << cache_chend - << "):\n"; - ImageCache* imagecache = ImageCache::create(false /*not shared*/); - - // Create a 10 channel file - ustring filename("tenchannels.tif"); - const int nchans = 10; - ImageBuf A(ImageSpec(64, 64, nchans, TypeDesc::FLOAT)); - const float pixelvalue[nchans] = { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, - 0.5f, 0.6f, 0.7f, 0.8f, 0.9f }; - ImageBufAlgo::fill(A, pixelvalue); - A.write(filename); - files_to_delete.push_back(filename); - - // Retrieve 2 pixels of [chbegin,chend), make sure we got the right values - float p[2 * nchans] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; - OIIO_CHECK_ASSERT(imagecache->get_pixels(filename, 0, 0, 0, 2, 0, 1, 0, - 1, // pixel range - chbegin, chend, TypeDesc::FLOAT, p, - AutoStride, AutoStride, AutoStride, - cache_chbegin, cache_chend)); - int nc = chend - chbegin; - for (int x = 0; x < 2; ++x) { - for (int c = 0; c < nc; ++c) { - std::cout << ' ' << p[x * nc + c]; - OIIO_CHECK_EQUAL(p[x * nc + c], pixelvalue[c + chbegin]); - } - std::cout << "\n"; - } - for (int c = 2 * nc; c < 2 * nchans; ++c) - OIIO_CHECK_EQUAL(p[c], -1.0f); - - ImageCache::destroy(imagecache); -} - - - -// Wimple wrapper to return a raw "null" ImageInput*. -static ImageInput* -NullInputCreator() -{ - // Note: we can't create it directly, but we can ask for a managed - // pointer and then release the raw pointer from it. - return ImageInput::create("0.null").release(); -} - - -// Test the ability to add an application buffer to make it appear as if -// it's an image in the cache. -void -test_app_buffer() -{ - ImageCache* imagecache = ImageCache::create(false /*not shared*/); - - // Add a file entry with a "null" ImageInput proxy configured to look - // like a 2x2 RGB float image. - ustring fooname("foo"); - const int xres = 2, yres = 2, chans = 3; - TypeDesc imgtype = TypeDesc::FLOAT; - ImageSpec config(xres, yres, chans, imgtype); - config.tile_width = xres; - config.tile_height = yres; - config.attribute("null:force", 1); // necessary because no .null extension - bool fadded = imagecache->add_file(fooname, NullInputCreator, &config); - OIIO_CHECK_ASSERT(fadded); - - // Make sure it got added correctly - ImageSpec retrieved_spec; - imagecache->get_imagespec(fooname, retrieved_spec); - OIIO_CHECK_EQUAL(retrieved_spec.width, xres); - OIIO_CHECK_EQUAL(retrieved_spec.height, yres); - OIIO_CHECK_EQUAL(retrieved_spec.format, imgtype); - - // Here's our image of data, in our own buffer. - static float pixels[yres][xres][chans] = { { { 0, 0, 0 }, { 0, 1, 0 } }, - { { 1, 0, 0 }, { 1, 1, 0 } } }; - // Add a proxy tile that points to -- but does not copy -- the image. - bool ok = imagecache->add_tile(fooname, 0 /* subimage */, 0 /* miplevel */, - 0, 0, 0, /* origin */ - 0, chans, /* channel range */ - imgtype, pixels, /* the buffer */ - AutoStride, AutoStride, - AutoStride, /* strides */ - false /* DO NOT COPY THE PIXELS! */); - OIIO_CHECK_ASSERT(ok); - - // Check that we can retrieve the tile. - ImageCache::Tile* tile = imagecache->get_tile(fooname, 0, 0, 0, 0, 0); - OIIO_CHECK_ASSERT(tile != nullptr); - imagecache->release_tile(tile); // de-refcount what we got from get_tile - - // Check that the tile's pixels appear to actually be our own buffer - TypeDesc format; - const void* pels = imagecache->tile_pixels(tile, format); - OIIO_CHECK_EQUAL(pels, pixels); - OIIO_CHECK_EQUAL(format, TypeDesc::FLOAT); - - // Check that retrieving the pixel (as would be done by the texture - // system) returns the right color. This would work for texture calls - // and whatnot as well. - float testpixel[3] = { -1, -1, -1 }; - imagecache->get_pixels(fooname, 0, 0, 1, 2, 1, 2, 0, 1, 0, 3, - TypeDesc::FLOAT, testpixel); - OIIO_CHECK_EQUAL(testpixel[0], pixels[1][1][0]); - OIIO_CHECK_EQUAL(testpixel[1], pixels[1][1][1]); - OIIO_CHECK_EQUAL(testpixel[2], pixels[1][1][2]); - - ImageCache::destroy(imagecache); -} - - - -void -test_custom_threadinfo() -{ - Strutil::print("\nTesting creating/destroying custom IC and thread info\n"); - ImageCache* imagecache = ImageCache::create(true); - auto threadinfo = imagecache->create_thread_info(); - OIIO_CHECK_ASSERT(threadinfo != nullptr); - imagecache->destroy_thread_info(threadinfo); - imagecache->close_all(); -} - - - -void -test_tileptr() -{ - Strutil::print("\nTesting tile ptr things\n"); - ImageCache* imagecache = ImageCache::create(); - auto hand = imagecache->get_image_handle(checkertex); - ImageCache::Tile* tile = imagecache->get_tile(hand, nullptr, 0, 0, 4, 4, 0); - OIIO_CHECK_ASSERT(tile != nullptr); - Strutil::print("tile @ 4,4 format {} ROI {}\n", - imagecache->tile_format(tile), imagecache->tile_roi(tile)); - OIIO_CHECK_EQUAL(imagecache->tile_format(tile), TypeHalf); - OIIO_CHECK_EQUAL(imagecache->tile_roi(tile), - ROI(0, 256, 0, 256, 0, 1, 0, 3)); - TypeDesc tileformat; - OIIO_CHECK_ASSERT(imagecache->tile_pixels(tile, tileformat) != nullptr); - OIIO_CHECK_ASSERT(tileformat == TypeHalf); - - // Some error handling cases - OIIO_CHECK_ASSERT(imagecache->get_tile(nullptr, nullptr, 0, 0, 4, 4, 0) - == nullptr); // null tile ptr - OIIO_CHECK_ASSERT(imagecache->get_tile(hand, nullptr, 1, 0, 400, 400, 0) - == nullptr); // nonexistent tile - - imagecache->release_tile(tile); -} - - - -static void -test_imagespec() -{ - Strutil::print("\nTesting imagespec retrieval\n"); - ImageCache* ic = ImageCache::create(); - - { // basic get_imagespec() - ImageSpec spec; - OIIO_CHECK_ASSERT(ic->get_imagespec(checkertex, spec)); - OIIO_CHECK_EQUAL(spec.width, 256); - } - { // basic get_imagespec() with handle - auto hand = ic->get_image_handle(checkertex); - ImageSpec spec; - OIIO_CHECK_ASSERT(ic->get_imagespec(hand, nullptr, spec)); - OIIO_CHECK_EQUAL(spec.width, 256); - } - - { // get_imagespec() for nonexistant file - ImageSpec spec; - OIIO_CHECK_FALSE(ic->get_imagespec(ustring("noexist.exr"), spec)); - OIIO_CHECK_ASSERT(ic->has_error()); - Strutil::print("get_imagespec() of non-existant file:\n {}\n", - ic->geterror()); - } - { // imagespec() for nonexistant file - const ImageSpec* spec = ic->imagespec(ustring("noexist.exr")); - OIIO_CHECK_ASSERT(spec == nullptr && ic->has_error()); - Strutil::print("imagespec() of non-existant file:\n {}\n", - ic->geterror()); - } - { // imagespec() for nonexistant file - const ImageSpec* spec = ic->imagespec(ustring("noexist.exr")); - OIIO_CHECK_ASSERT(spec == nullptr && ic->has_error()); - Strutil::print("imagespec() of non-existant file:\n {}\n", - ic->geterror()); - } - { // imagespec() for null handle - const ImageSpec* spec = ic->imagespec(nullptr, nullptr); - OIIO_CHECK_ASSERT(spec == nullptr && ic->has_error()); - Strutil::print("imagespec(handle) of non-existant file:\n {}\n", - ic->geterror()); - } - { // imagespec() for out of range subimage - const ImageSpec* spec = ic->imagespec(checkertex, 10, 0); - OIIO_CHECK_ASSERT(spec == nullptr && ic->has_error()); - Strutil::print("imagespec() out-of-range subimage:\n {}\n", - ic->geterror()); - } - { // imagespec() for out of range mip level - const ImageSpec* spec = ic->imagespec(checkertex, 0, 100); - OIIO_CHECK_ASSERT(spec == nullptr && ic->has_error()); - Strutil::print("imagespec() out-of-range subimage:\n {}\n", - ic->geterror()); - } -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - create_temp_textures(); - - test_get_pixels_cachechannels(0, 10); - test_get_pixels_cachechannels(0, 4); - test_get_pixels_cachechannels(0, 4, 0, 6); - test_get_pixels_cachechannels(0, 4, 0, 4); - test_get_pixels_cachechannels(6, 9); - test_get_pixels_cachechannels(6, 9, 6, 9); - - test_app_buffer(); - test_tileptr(); - test_get_pixels_errors(); - test_custom_threadinfo(); - test_imagespec(); - - ImageCache* ic = ImageCache::create(); - Strutil::print("\n\n{}\n", ic->getstats(5)); - ic->reset_stats(); - - for (auto f : files_to_delete) - Filesystem::remove(f); - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imageinout_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imageinout_test.cpp deleted file mode 100644 index 8477a919..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imageinout_test.cpp +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -///////////////////////////////////////////////////////////////////////// -// Tests related to ImageInput and ImageOutput -///////////////////////////////////////////////////////////////////////// - -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - - -static std::string onlyformat = Sysutil::getenv("IMAGEINOUTTEST_ONLY_FORMAT"); -static bool nodelete = false; // Don't delete the test files - - - -static void -getargs(int argc, char* argv[]) -{ - // clang-format off - ArgParse ap; - ap.intro("imageinout_test -- unit test and benchmarks for image formats\n" - OIIO_INTRO_STRING) - .usage("imageinout_test [options]"); - - ap.arg("--no-delete", &nodelete) - .help("Don't delete temporary test files"); - ap.arg("--onlyformat %s:FORMAT", &onlyformat) - .help("Test only one format"); - - ap.parse_args(argc, (const char**)argv); - // clang-format on -} - - - -// Generate a small test image appropriate to the given format -static ImageBuf -make_test_image(string_view formatname) -{ - ImageBuf buf; - auto out = ImageOutput::create(formatname); - OIIO_DASSERT(out); - ImageSpec spec(64, 64, 4, TypeFloat); - float pval = 1.0f; - // Fill with 0 for lossy HEIF - if (formatname == "heif") - pval = 0.0f; - - // Accommodate limited numbers of channels - if (formatname == "zfile" || formatname == "fits") - spec.nchannels = 1; // these formats are single channel - else if (!out->supports("alpha")) - spec.nchannels = std::min(spec.nchannels, 3); - - // Webp library seems to automatically truncate alpha when it's 1.0, - // botching our comparisons. Just ease the headache of tests by sticking - // to RGB. - if (formatname == "webp") - spec.nchannels = 3; - - // Force a fixed datetime metadata so it can't differ between writes - // and make different file patterns for these tests. - spec.attribute("DateTime", "01/01/2000 00:00:00"); - - buf.reset(spec); - ImageBufAlgo::fill(buf, { pval, pval, pval, 1.0f }); - return buf; -} - - - -#define CHECKED(obj, call) \ - if (!obj->call) { \ - if (do_asserts) \ - OIIO_CHECK_ASSERT(false && #call); \ - if (errmsg) \ - *errmsg = obj->geterror(); \ - else \ - std::cout << " " << obj->geterror() << "\n"; \ - return false; \ - } - - -static bool -checked_write(ImageOutput* out, string_view filename, const ImageSpec& spec, - TypeDesc type, const void* data, bool do_asserts = true, - std::string* errmsg = nullptr, - Filesystem::IOProxy* ioproxy = nullptr) -{ - if (errmsg) - *errmsg = ""; - std::unique_ptr out_local; - if (!out) { - out_local = ImageOutput::create(filename, ioproxy); - out = out_local.get(); - } - OIIO_CHECK_ASSERT(out && "Failed to create output"); - if (!out) { - if (errmsg) - *errmsg = OIIO::geterror(); - else - std::cout << " " << OIIO::geterror() << "\n"; - return false; - } - - CHECKED(out, open(filename, spec)); - CHECKED(out, write_image(type, data)); - CHECKED(out, close()); - return true; -} - - - -static bool -checked_read(ImageInput* in, string_view filename, - std::vector& data, bool already_opened = false, - bool do_asserts = true, std::string* errmsg = nullptr) -{ - if (errmsg) - *errmsg = ""; - if (!already_opened) { - ImageSpec spec; - CHECKED(in, open(filename, spec)); - } - data.resize(in->spec().image_pixels() * in->spec().nchannels - * sizeof(float)); - CHECKED(in, - read_image(0, 0, 0, in->spec().nchannels, TypeFloat, data.data())); - CHECKED(in, close()); - return true; -} - - - -// Helper for test_all_formats: write the pixels in buf to an in-memory -// IOProxy, make sure it matches byte for byte the file named by disk_filename. -static bool -test_write_proxy(string_view formatname, string_view extension, - const std::string& disk_filename, ImageBuf& buf) -{ - std::cout << " Writing Proxy " << formatname << " ... "; - std::cout.flush(); - bool ok = true; - Sysutil::Term term(stdout); - - // Use ImageOutput.write_image interface to write to outproxy - Filesystem::IOVecOutput outproxy; - ok = checked_write(nullptr, disk_filename, buf.spec(), buf.spec().format, - buf.localpixels(), true, nullptr, &outproxy); - - // Use ImageBuf.write interface to write to outproxybuf - Filesystem::IOVecOutput outproxybuf; - buf.set_write_ioproxy(&outproxybuf); - buf.write(disk_filename); - - if (nodelete) { - // Debugging -- dump the proxies to disk - Filesystem::write_binary_file(Strutil::fmt::format("outproxy.{}", - extension), - outproxy.buffer()); - Filesystem::write_binary_file(Strutil::fmt::format("outproxybuf.{}", - extension), - outproxybuf.buffer()); - } - // Now read back in the actual disk file we wrote earlier. - uint64_t bytes_written = Filesystem::file_size(disk_filename); - std::vector readbuf(bytes_written); - size_t bread = Filesystem::read_bytes(disk_filename, readbuf.data(), - bytes_written); - - // OK, now we have three vectors: - // - readbuf contains the bytes we actually wrote to disk - // - outproxy.buffer() contains the bytes we wrote to the proxy using - // ImageOutput.write_image(). - // - outproxybuf.buffer() contains the bytes we wrote to the proxy using - // ImageBuf.write(). - // These should all match, byte-for-byte. - ok = (bread == bytes_written && outproxy.buffer() == readbuf - && outproxybuf.buffer() == readbuf); - OIIO_CHECK_ASSERT(bread == bytes_written - && "Bytes read didn't match bytes written"); - OIIO_CHECK_ASSERT(outproxy.buffer() == readbuf - && "Write proxy via ImageOutput didn't match write file"); - if (outproxy.buffer() != readbuf) { - Strutil::print("Write proxy via ImageBuf didn't match write file\n"); - Strutil::print("Sizes outproxy {} vs readbuf {}\n", - outproxy.buffer().size(), readbuf.size()); -#if 0 - for (size_t i = 0, e = std::min(outproxy.buffer().size(), readbuf.size()); - i < e; ++i) { - Strutil::print(" {0:2d}: {1:02x} '{1:c}' vs {2:02x} '{2:c}'\n", - i, outproxy.buffer()[i], readbuf[i]); - if (outproxy.buffer()[i] != readbuf[i]) { - Strutil::print(" Mismatch at byte {} outproxy {} vs readbuf {}\n", - i, outproxy.buffer()[i], readbuf[i]); - break; - } - } -#endif - } - OIIO_CHECK_ASSERT(outproxybuf.buffer() == readbuf - && "Write proxy via ImageBuf didn't match write file"); - if (ok) - std::cout << term.ansi("green", "OK\n"); - return ok; -} - - - -// Helper for test_all_formats: read the pixels of the given disk file into -// a buffer, then use an IOProxy to read the "file" from the buffer, and -// the pixels ought to match those of ImageBuf buf. -static bool -test_read_proxy(string_view formatname, string_view extension, - const std::string& disk_filename, const ImageBuf& buf) -{ - bool ok = true; - Sysutil::Term term(stdout); - std::cout << " Reading Proxy " << formatname << " ... "; - std::cout.flush(); - - // Read the disk file into readbuf as a blob -- just a byte-for-byte - // copy of the file, but in memory. - uint64_t bytes_written = Filesystem::file_size(disk_filename); - std::vector readbuf(bytes_written); - Filesystem::read_bytes(disk_filename, readbuf.data(), bytes_written); - - // Read the in-memory file using an ioproxy, with ImageInput - Filesystem::IOMemReader inproxy(readbuf); - std::string memname = Strutil::concat("mem.", extension); - auto in = ImageInput::open(memname, nullptr, &inproxy); - OIIO_CHECK_ASSERT(in && "Failed to open input with proxy"); - if (in) { - std::vector readpixels; - ok &= checked_read(in.get(), memname, readpixels, true); - ok &= memcmp(readpixels.data(), buf.localpixels(), readpixels.size()) - == 0; - OIIO_CHECK_ASSERT( - ok && "Read proxy with ImageInput didn't match original"); - } else { - ok = false; - std::cout << "Error was: " << OIIO::geterror() << "\n"; - } - - // Read the in-memory file using an ioproxy again, but with ImageInput - Filesystem::IOMemReader inproxybuf(readbuf); - ImageBuf inbuf(memname, 0, 0, nullptr, nullptr, &inproxybuf); - bool ok2 = inbuf.read(0, 0, /*force*/ true, TypeFloat); - if (!ok2) { - std::cout << "Read failed: " << inbuf.geterror() << "\n"; - OIIO_CHECK_ASSERT(ok2); - return false; - } - OIIO_ASSERT(inbuf.localpixels()); - OIIO_ASSERT(buf.localpixels()); - OIIO_CHECK_EQUAL(buf.spec().format, inbuf.spec().format); - OIIO_CHECK_EQUAL(buf.spec().image_bytes(), inbuf.spec().image_bytes()); - ok2 &= memcmp(inbuf.localpixels(), buf.localpixels(), - buf.spec().image_bytes()) - == 0; - OIIO_CHECK_ASSERT(ok2 && "Read proxy with ImageBuf didn't match original"); - ok &= ok2; - - if (ok) - std::cout << term.ansi("green", "OK\n"); - return ok; -} - - - -// Test writer's ability to detect and recover from errors when asked to -// write an unwritable file (such as in a nonexistent directory). -static bool -test_write_unwritable(string_view extension, const ImageBuf& buf) -{ - bool ok = true; - Sysutil::Term term(stdout); - std::string bad_filename = Strutil::concat("bad/bad.", extension); - std::cout << " Writing bad to " << bad_filename << " ... "; - auto badout = ImageOutput::create(bad_filename); - if (badout) { - std::string errmsg; - ok = checked_write(badout.get(), bad_filename, buf.spec(), - buf.spec().format, buf.localpixels(), - /*do_asserts=*/false, &errmsg); - if (!ok) - std::cout << term.ansi("green", "OK") << " (" - << errmsg.substr(0, 60) << ")\n"; - else - OIIO_CHECK_ASSERT(0 && "Bad write should not have 'succeeded'"); - } else { - OIIO_CHECK_ASSERT(badout); - ok = false; - } - return ok; -} - - - -static void -test_all_formats() -{ - Sysutil::Term term(stdout); - std::cout << "Testing formats:\n"; - auto all_fmts - = Strutil::splitsv(OIIO::get_string_attribute("extension_list"), ";"); - for (auto& e : all_fmts) { - auto fmtexts = Strutil::splitsv(e, ":"); - string_view formatname = fmtexts[0]; - // Skip "formats" that aren't amenable to this kind of testing - if (formatname == "null" || formatname == "term") - continue; - - if (onlyformat.size() && formatname != onlyformat) - continue; - - auto extensions = Strutil::splitsv(fmtexts[1], ","); - bool ok = true; - - // - // Try writing the file - // - std::string filename = Strutil::fmt::format("imageinout_test-{}.{}", - formatname, extensions[0]); - auto out = ImageOutput::create(filename); - if (!out) { - std::cout << " [skipping " << formatname << " -- no writer]\n"; - (void)OIIO::geterror(); // discard error - continue; - } - bool ioproxy_write_supported = out->supports("ioproxy"); - std::cout << " " << formatname << " (" - << Strutil::join(extensions, ", ") << "):\n"; - - ImageBuf buf = make_test_image(formatname); - const float* orig_pixels = (const float*)buf.localpixels(); - - std::cout << " Writing " << filename << " ... "; - ok = checked_write(out.get(), filename, buf.spec(), buf.spec().format, - orig_pixels); - if (ok) - std::cout << term.ansi("green", "OK\n"); - - // - // Try reading the file, and make sure it matches what we wrote - // - std::vector pixels; - auto in = ImageInput::create(filename); - OIIO_CHECK_ASSERT(in && "Could not create reader"); - bool ioproxy_read_supported = in && in->supports("ioproxy"); - if (in) { - std::cout << " Reading " << filename << " ... "; - ok = checked_read(in.get(), filename, pixels); - if (!ok) - continue; - ok = memcmp(orig_pixels, pixels.data(), pixels.size()) == 0; - OIIO_CHECK_ASSERT(ok && "Failed read/write comparison"); - if (ok) - std::cout << term.ansi("green", "OK\n"); - } else { - (void)OIIO::geterror(); // discard error - } - if (!ok) - continue; - - // - // If this format supports proxies, round trip through memory - // - if (ioproxy_write_supported) - test_write_proxy(formatname, extensions[0], filename, buf); - if (ioproxy_read_supported) - test_read_proxy(formatname, extensions[0], filename, buf); - - // - // Test what happens when we write to an unwritable or nonexistent - // directory. It should not crash! But appropriately return some - // error. - // - test_write_unwritable(extensions[0], buf); - - if (!nodelete) - Filesystem::remove(filename); - } - std::cout << "\n"; -} - - - -// This tests a particular troublesome case where we got the logic wrong. -// Read 1-channel float exr into 4-channel uint8 buffer with 4-byte xstride. -// The correct behavior is to translate the one channel from float to uint8 -// and put it in channel 0, leaving channels 1-3 untouched. The bug was that -// because the buffer stride and native stride were both 4 bytes, it was -// incorrectly doing a straight data copy. -void -test_read_tricky_sizes() -{ - // Make 4x4 1-channel float source image, value 0.5, write it. - char srcfilename[] = "tmp_f1.exr"; - ImageSpec fsize1(4, 4, 1, TypeFloat); - ImageBuf src(fsize1); - ImageBufAlgo::fill(src, 0.5f); - src.write(srcfilename); - - // Make a 4x4 4-channel uint8 buffer, initialize with 0 - unsigned char buf[4][4][4]; - memset(buf, 0, 4 * 4 * 4); - - // Read in, make sure it's right, several different ways - { - auto imgin = ImageInput::open(srcfilename); - imgin->read_image(0, 0, 0, 4, TypeUInt8, buf, 4 /* xstride */); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - { - memset(buf, 0, 4 * 4 * 4); - auto imgin = ImageInput::open(srcfilename); - imgin->read_scanlines(0, 0, 0, 4, 0, 0, 4, TypeUInt8, buf, - /*xstride=*/4); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - { - memset(buf, 0, 4 * 4 * 4); - auto imgin = ImageInput::open(srcfilename); - for (int y = 0; y < 4; ++y) - imgin->read_scanline(y, 0, TypeUInt8, buf, /*xstride=*/4); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - // And repeat for tiled - src.set_write_tiles(2, 2); - src.write(srcfilename); - { - memset(buf, 0, 4 * 4 * 4); - auto imgin = ImageInput::open(srcfilename); - imgin->read_image(0, 0, 0, 4, TypeUInt8, buf, 4 /* xstride */); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - { - memset(buf, 0, 4 * 4 * 4); - auto imgin = ImageInput::open(srcfilename); - imgin->read_tiles(0, 0, 0, 4, 0, 4, 0, 1, 0, 4, TypeUInt8, buf, - /*xstride=*/4); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - { - memset(buf, 0, 4 * 4 * 4); - auto imgin = ImageInput::open(srcfilename); - imgin->read_tile(0, 0, 0, TypeUInt8, buf, /*xstride=*/4); - OIIO_CHECK_EQUAL(int(buf[0][0][0]), 128); - OIIO_CHECK_EQUAL(int(buf[0][0][1]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][2]), 0); - OIIO_CHECK_EQUAL(int(buf[0][0][3]), 0); - } - - // Clean up - Filesystem::remove(srcfilename); -} - - - -int -main(int argc, char* argv[]) -{ - getargs(argc, argv); - - test_all_formats(); - test_read_tricky_sizes(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imagespec_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imagespec_test.cpp deleted file mode 100644 index 94501740..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imagespec_test.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include - -using namespace OIIO; - -const char* imagespec_xml_string = R"EOF( - -0 -0 -0 -1920 -1080 -1 -0 -0 -0 -1920 -1080 -1 -1920 -1080 -1 -float -4 - -R -G -B -A - -3 --1 -0 -scene_linear -none -1 -0.7347, 0.2653, 0, 1, 0.0001, -0.077, 0.32168, 0.33767 -1 -0, 0 -1 -1 - -)EOF"; - -void -test_imagespec_pixels() -{ - std::cout << "test_imagespec_pixels\n"; - // images with dimensions > 2^16 (65536) on a side have > 2^32 pixels - const long long WIDTH = 456789; - const long long HEIGHT = 345678; - const long long CHANNELS = 3; - const long long BYTES_IN_FLOAT = 4; - ImageSpec spec(WIDTH, HEIGHT, CHANNELS, TypeDesc::FLOAT); - - std::cout << "sizeof (int) = " << sizeof(int) << std::endl; - std::cout << "sizeof (long) = " << sizeof(long) << std::endl; - std::cout << "sizeof (long long) = " << sizeof(long long) << std::endl; - std::cout << "sizeof (size_t) = " << sizeof(size_t) << std::endl; - std::cout << "sizeof (imagesize_t) = " << sizeof(imagesize_t) << std::endl; - std::cout << "sizeof (stride_t) = " << sizeof(stride_t) << std::endl; - std::cout << "sizeof (float) = " << sizeof(float) << std::endl; - - OIIO_CHECK_EQUAL((size_t)BYTES_IN_FLOAT, sizeof(float)); - OIIO_CHECK_EQUAL(CHANNELS, spec.nchannels); - OIIO_CHECK_EQUAL(WIDTH, spec.width); - OIIO_CHECK_EQUAL(HEIGHT, spec.height); - OIIO_CHECK_EQUAL(1, spec.depth); - OIIO_CHECK_EQUAL(WIDTH, spec.full_width); - OIIO_CHECK_EQUAL(HEIGHT, spec.full_height); - OIIO_CHECK_EQUAL(1, spec.full_depth); - // FIXME(nemec): uncomment after figuring out linking - // OIIO_CHECK_EQUAL (TypeDesc::UINT8, spec.format); - OIIO_CHECK_EQUAL((size_t)BYTES_IN_FLOAT, spec.channel_bytes()); - OIIO_CHECK_EQUAL((size_t)(BYTES_IN_FLOAT * CHANNELS), spec.pixel_bytes()); - OIIO_CHECK_EQUAL((imagesize_t)(BYTES_IN_FLOAT * CHANNELS * WIDTH), - spec.scanline_bytes()); - OIIO_CHECK_EQUAL((imagesize_t)(WIDTH * HEIGHT), spec.image_pixels()); - - // check that the magnitude is right (not clamped) -- should be about > 2^40 - long long expected_bytes = BYTES_IN_FLOAT * CHANNELS * WIDTH * HEIGHT; - // log (x) / log (2) = log2 (x) - // log (2^32) / log (2) = log2 (2^32) = 32 - // log (2^32) * M_LOG2E = 32 - double log2_result = log((double)expected_bytes) * M_LOG2E; - OIIO_CHECK_LT(40, log2_result); - OIIO_CHECK_EQUAL((imagesize_t)expected_bytes, spec.image_bytes()); - - std::cout << "expected_bytes = " << expected_bytes << ", log " - << log((double)expected_bytes) << std::endl; -} - - - -static void -metadata_val_test(void* data, int num_elements, TypeDesc type, std::string& val) -{ - static ImageSpec spec; - ParamValue p; - - p.init("name", type, num_elements, data); - val = spec.metadata_val(p); -} - - - -void -test_imagespec_metadata_val() -{ - std::cout << "test_imagespec_metadata_val\n"; - std::string ret; - - int imatrix[] = { 100, 200, 300, 400 }; - metadata_val_test(&imatrix[0], 1, TypeInt, ret); - OIIO_CHECK_EQUAL(ret, "100"); - metadata_val_test(imatrix, sizeof(imatrix) / sizeof(int), TypeInt, ret); - OIIO_CHECK_EQUAL(ret, "100, 200, 300, 400"); - OIIO_CHECK_NE(ret, "100, 200, 300, 400,"); - - float fmatrix[] = { 10.12f, 200.34f, 300.11f, 400.9f }; - metadata_val_test(&fmatrix[0], 1, TypeFloat, ret); - OIIO_CHECK_EQUAL(ret, "10.12"); - metadata_val_test(fmatrix, sizeof(fmatrix) / sizeof(float), TypeFloat, ret); - OIIO_CHECK_EQUAL(ret, "10.12, 200.34, 300.11, 400.9"); - OIIO_CHECK_NE(ret, "10, 200, 300, 400"); - OIIO_CHECK_NE(ret, "10.12, 200.34, 300.11, 400.9,"); - - unsigned long long ullmatrix[] = { 0xffffffffffffffffULL, - 0xffffffffffffffffULL }; - metadata_val_test(&ullmatrix, 1, TypeDesc::UINT64, ret); - OIIO_CHECK_EQUAL(ret, "18446744073709551615"); - metadata_val_test(&ullmatrix, - sizeof(ullmatrix) / sizeof(unsigned long long), - TypeDesc::UINT64, ret); - OIIO_CHECK_EQUAL(ret, "18446744073709551615, 18446744073709551615"); - OIIO_CHECK_NE(ret, "-1, -1"); - OIIO_CHECK_NE(ret, "18446744073709551615, 18446744073709551615,"); - - const char* smatrix[] = { "this is \"a test\"", "this is another test" }; - metadata_val_test(smatrix, 1, TypeString, ret); - OIIO_CHECK_EQUAL(ret, "\"this is \\\"a test\\\"\""); - OIIO_CHECK_NE(ret, smatrix[0]); - OIIO_CHECK_NE(ret, "\"this is \"a test\"\","); - metadata_val_test(smatrix, sizeof(smatrix) / sizeof(char*), TypeString, - ret); - OIIO_CHECK_EQUAL(ret, - "\"this is \\\"a test\\\"\", \"this is another test\""); - - float matrix16[2][16] = { - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, - { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } - }; - metadata_val_test(&matrix16[0], 1, TypeMatrix, ret); - OIIO_CHECK_EQUAL(ret, - "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16"); - OIIO_CHECK_NE(ret, - "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,"); - metadata_val_test(matrix16, sizeof(matrix16) / (16 * sizeof(float)), - TypeMatrix, ret); - OIIO_CHECK_EQUAL( - ret, - "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25"); -} - - - -static void -attribute_test(const std::string& data, TypeDesc type, std::string& ret) -{ - ImageSpec spec; - spec.attribute("name", type, data); - ret = spec.metadata_val(spec.extra_attribs[0]); -} - - - -void -test_imagespec_attribute_from_string() -{ - std::cout << "test_imagespec_attribute_from_string\n"; - TypeDesc type = TypeInt; - std::string ret, data, invalid_data; - - data = "142"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, data); - - type = TypeFloat; - data = "1.23"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, data); - - type = TypeDesc(TypeDesc::FLOAT, 5); - data = "1.23, 34.23, 35.11, 99.99, 1999.99"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, data); - - type = TypeDesc::UINT64; - data = "18446744073709551615"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, data); - - type = TypeMatrix; - data = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, data); - - type = TypeString; - data = "foo"; - attribute_test(data, type, ret); - OIIO_CHECK_EQUAL(ret, "\"foo\""); -} - - - -static void -test_get_attribute() -{ - std::cout << "test_get_attribute\n"; - ImageSpec spec(640, 480, 4, TypeDesc::FLOAT); - spec.x = 10; - spec.y = 12; - spec.full_x = -5; - spec.full_y = -8; - spec.full_width = 1024; - spec.full_height = 800; - spec.tile_width = 64; - spec.tile_height = 32; - spec.attribute("foo", int(42)); - spec.attribute("pi", float(M_PI)); - spec.attribute("bar", "barbarbar?"); - spec["baz"] = (unsigned int)14; - - OIIO_CHECK_EQUAL(spec.get_int_attribute("width"), 640); - OIIO_CHECK_EQUAL(spec.get_int_attribute("height"), 480); - OIIO_CHECK_EQUAL(spec.get_int_attribute("nchannels"), 4); - OIIO_CHECK_EQUAL(spec.channelnames.size(), 4); - OIIO_CHECK_EQUAL(spec.channel_name(0), "R"); - OIIO_CHECK_EQUAL(spec.channel_name(1), "G"); - OIIO_CHECK_EQUAL(spec.channel_name(2), "B"); - OIIO_CHECK_EQUAL(spec.channel_name(3), "A"); - OIIO_CHECK_EQUAL(spec.channel_name(4), ""); - OIIO_CHECK_EQUAL(spec.get_int_attribute("x"), 10); - OIIO_CHECK_EQUAL(spec.get_int_attribute("y"), 12); - OIIO_CHECK_EQUAL(spec.get_int_attribute("full_x"), -5); - OIIO_CHECK_EQUAL(spec.get_int_attribute("full_y"), -8); - OIIO_CHECK_EQUAL(spec.get_int_attribute("full_width"), 1024); - OIIO_CHECK_EQUAL(spec.get_int_attribute("full_height"), 800); - OIIO_CHECK_EQUAL(spec.get_int_attribute("tile_width"), 64); - OIIO_CHECK_EQUAL(spec.get_int_attribute("tile_height"), 32); - OIIO_CHECK_EQUAL(spec.get_string_attribute("geom"), "640x480+10+12"); - OIIO_CHECK_EQUAL(spec.get_string_attribute("full_geom"), "1024x800-5-8"); - OIIO_CHECK_EQUAL(spec.get_int_attribute("foo"), 42); - OIIO_CHECK_EQUAL(spec.get_int_attribute("pi", 4), 4); // should fail int - OIIO_CHECK_EQUAL(spec.get_float_attribute("pi"), float(M_PI)); - OIIO_CHECK_EQUAL(spec.get_int_attribute("bar"), 0); - OIIO_CHECK_EQUAL(spec.get_int_attribute("bar"), 0); - OIIO_CHECK_EQUAL(spec.get_string_attribute("bar"), "barbarbar?"); - OIIO_CHECK_ASSERT(spec.find_attribute("foo") != NULL); - OIIO_CHECK_ASSERT(spec.find_attribute("Foo") != NULL); - OIIO_CHECK_ASSERT(spec.find_attribute("Foo", TypeDesc::UNKNOWN, false) - != NULL); - OIIO_CHECK_ASSERT(spec.find_attribute("Foo", TypeDesc::UNKNOWN, true) - == NULL); - OIIO_CHECK_ASSERT(spec.find_attribute("foo", TypeDesc::INT) != NULL); - OIIO_CHECK_ASSERT(spec.find_attribute("foo", TypeDesc::FLOAT) == NULL); - - ParamValue tmp; - const ParamValue* p; - int datawin[] = { 10, 12, 649, 491 }; - int dispwin[] = { -5, -8, 1018, 791 }; - bool ok; - p = spec.find_attribute("datawindow", tmp); - ok = cspan((const int*)p->data(), 4) == cspan(datawin); - OIIO_CHECK_ASSERT(ok); - p = spec.find_attribute("displaywindow", tmp); - ok = cspan((const int*)p->data(), 4) == cspan(dispwin); - OIIO_CHECK_ASSERT(ok); - - // Check [] syntax using AttribDelegate - OIIO_CHECK_EQUAL(spec["pi"].get(), float(M_PI)); - OIIO_CHECK_EQUAL(spec["foo"].get(), 42); - OIIO_CHECK_EQUAL(spec["foo"].get(), "42"); - OIIO_CHECK_EQUAL(spec.getattributetype("baz"), TypeUInt32); - OIIO_CHECK_EQUAL(spec["baz"].get(), (unsigned int)14); -} - - -static void -test_imagespec_from_ROI() -{ - ROI roi(0, 640, 0, 480, 0, 1, 0, 3); - ImageSpec spec(roi, "float"); - OIIO_CHECK_EQUAL(spec.nchannels, 3); - OIIO_CHECK_EQUAL(spec.width, 640); - OIIO_CHECK_EQUAL(spec.height, 480); - OIIO_CHECK_EQUAL(spec.depth, 1); - OIIO_CHECK_EQUAL(spec.full_width, 640); - OIIO_CHECK_EQUAL(spec.full_height, 480); - OIIO_CHECK_EQUAL(spec.full_depth, 1); - OIIO_CHECK_EQUAL(spec.format, TypeFloat); -} - -static void -test_imagespec_from_xml() -{ - std::cout << "test_imagespec_from_xml\n"; - ImageSpec spec; - spec.from_xml(imagespec_xml_string); - - OIIO_CHECK_EQUAL(spec.nchannels, 4); - OIIO_CHECK_EQUAL(spec.width, 1920); - OIIO_CHECK_EQUAL(spec.height, 1080); - OIIO_CHECK_EQUAL(spec.depth, 1); - OIIO_CHECK_EQUAL(spec.full_width, 1920); - OIIO_CHECK_EQUAL(spec.full_height, 1080); - OIIO_CHECK_EQUAL(spec.full_depth, 1); - OIIO_CHECK_EQUAL(spec.format, TypeFloat); - OIIO_CHECK_EQUAL(spec.get_string_attribute("oiio:ColorSpace"), - "scene_linear"); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_imagespec_pixels(); - test_imagespec_metadata_val(); - test_imagespec_attribute_from_string(); - test_get_attribute(); - test_imagespec_from_ROI(); - test_imagespec_from_xml(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libOpenImageIO/imagespeed_test.cpp b/Sources/OpenImageIO/libOpenImageIO/imagespeed_test.cpp deleted file mode 100644 index a67bfa77..00000000 --- a/Sources/OpenImageIO/libOpenImageIO/imagespeed_test.cpp +++ /dev/null @@ -1,622 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -using namespace OIIO; - -static bool verbose = false; -static int iterations = 1; -static int ntrials = 1; -static int numthreads = 0; -static int autotile_size = 64; -static bool iter_only = false; -static bool no_iter = false; -static std::string conversionname; -static TypeDesc conversion = TypeDesc::UNKNOWN; // native by default -static std::vector input_filename; -static std::string output_filename; -static std::string output_format; -static std::vector buffer; -static ImageSpec bufspec, outspec; -static ImageCache* imagecache = NULL; -static imagesize_t total_image_pixels = 0; -static float cache_size = 0; - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("imagespeed_test\n" OIIO_INTRO_STRING) - .usage("imagespeed_test [options]"); - - ap.arg("filename") - .hidden() - .action([&](cspan argv){ input_filename.emplace_back(argv[0]); }); - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--autotile %d", &autotile_size) - .help(Strutil::sprintf("Autotile size (when used; default: %d)", autotile_size)); - ap.arg("--iteronly", &iter_only) - .help("Run ImageBuf iteration tests only (not read tests)"); - ap.arg("--noiter", &no_iter) - .help("Don't run ImageBuf iteration tests"); - ap.arg("--convert %s", &conversionname) - .help("Convert to named type upon read (default: native)"); - ap.arg("--cache %f", &cache_size) - .help("Specify ImageCache size, in MB"); - ap.arg("-o %s", &output_filename) - .help("Test output by writing to this file"); - ap.arg("-od %s", &output_format) - .help("Requested output format"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -static void -time_read_image() -{ - for (ustring filename : input_filename) { - auto in = ImageInput::open(filename.c_str()); - OIIO_ASSERT(in); - in->read_image(0, 0, 0, in->spec().nchannels, conversion, &buffer[0]); - in->close(); - } -} - - - -static void -time_read_scanline_at_a_time() -{ - for (ustring filename : input_filename) { - auto in = ImageInput::open(filename.c_str()); - OIIO_ASSERT(in); - const ImageSpec& spec(in->spec()); - size_t pixelsize = spec.nchannels * conversion.size(); - if (!pixelsize) - pixelsize = spec.pixel_bytes(true); // UNKNOWN -> native - imagesize_t scanlinesize = spec.width * pixelsize; - for (int y = 0; y < spec.height; ++y) { - in->read_scanline(y + spec.y, 0, conversion, - &buffer[scanlinesize * y]); - } - in->close(); - } -} - - - -static void -time_read_64_scanlines_at_a_time() -{ - for (ustring filename : input_filename) { - auto in = ImageInput::open(filename.c_str()); - OIIO_ASSERT(in); - ImageSpec spec = in->spec_dimensions(0); - size_t pixelsize = spec.nchannels * conversion.size(); - if (!pixelsize) - pixelsize = spec.pixel_bytes(true); // UNKNOWN -> native - imagesize_t scanlinesize = spec.width * pixelsize; - for (int y = 0; y < spec.height; y += 64) { - in->read_scanlines(/*subimage=*/0, /*miplevel=*/0, y + spec.y, - std::min(y + spec.y + 64, spec.y + spec.height), - 0, 0, spec.nchannels, conversion, - &buffer[scanlinesize * y]); - } - in->close(); - } -} - - - -static void -time_read_imagebuf() -{ - imagecache->invalidate_all(true); - for (ustring filename : input_filename) { - ImageBuf ib(filename.string(), imagecache); - ib.read(0, 0, true, conversion); - } -} - - - -static void -time_ic_get_pixels() -{ - imagecache->invalidate_all(true); - for (ustring filename : input_filename) { - const ImageSpec spec = (*imagecache->imagespec(filename)); - imagecache->get_pixels(filename, 0, 0, spec.x, spec.x + spec.width, - spec.y, spec.y + spec.height, spec.z, - spec.z + spec.depth, conversion, &buffer[0]); - } -} - - - -static void -test_read(const std::string& explanation, void (*func)(), int autotile = 64, - int autoscanline = 1) -{ - imagecache->invalidate_all(true); // Don't hold anything - imagecache->attribute("autotile", autotile); - imagecache->attribute("autoscanline", autoscanline); - double t = time_trial(func, ntrials); - double rate = double(total_image_pixels) / t; - std::cout << " " << explanation << ": " - << Strutil::timeintervalformat(t, 2) << " = " - << Strutil::sprintf("%5.1f", rate / 1.0e6) << " Mpel/s" - << std::endl; -} - - - -static void -time_write_image() -{ - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - out->write_image(bufspec.format, &buffer[0]); -} - - - -static void -time_write_scanline_at_a_time() -{ - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - - size_t pixelsize = outspec.nchannels * sizeof(float); - imagesize_t scanlinesize = outspec.width * pixelsize; - for (int y = 0; y < outspec.height; ++y) { - out->write_scanline(y + outspec.y, outspec.z, bufspec.format, - &buffer[scanlinesize * y]); - } -} - - - -static void -time_write_64_scanlines_at_a_time() -{ - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - - size_t pixelsize = outspec.nchannels * sizeof(float); - imagesize_t scanlinesize = outspec.width * pixelsize; - for (int y = 0; y < outspec.height; y += 64) { - out->write_scanlines(y + outspec.y, - std::min(y + outspec.y + 64, - outspec.y + outspec.height), - outspec.z, bufspec.format, - &buffer[scanlinesize * y]); - } -} - - - -static void -time_write_tile_at_a_time() -{ - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - - size_t pixelsize = outspec.nchannels * sizeof(float); - imagesize_t scanlinesize = outspec.width * pixelsize; - imagesize_t planesize = outspec.height * scanlinesize; - for (int z = 0; z < outspec.depth; z += outspec.tile_depth) { - for (int y = 0; y < outspec.height; y += outspec.tile_height) { - for (int x = 0; x < outspec.width; x += outspec.tile_width) { - out->write_tile(x + outspec.x, y + outspec.y, z + outspec.z, - bufspec.format, - &buffer[scanlinesize * y + pixelsize * x], - pixelsize, scanlinesize, planesize); - } - } - } -} - - - -static void -time_write_tiles_row_at_a_time() -{ - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - - size_t pixelsize = outspec.nchannels * sizeof(float); - imagesize_t scanlinesize = outspec.width * pixelsize; - for (int z = 0; z < outspec.depth; z += outspec.tile_depth) { - for (int y = 0; y < outspec.height; y += outspec.tile_height) { - out->write_tiles(outspec.x, outspec.x + outspec.width, - y + outspec.y, y + outspec.y + outspec.tile_height, - z + outspec.z, z + outspec.z + outspec.tile_depth, - bufspec.format, &buffer[scanlinesize * y], - pixelsize /*xstride*/, scanlinesize /*ystride*/); - } - } -} - - - -static void -time_write_imagebuf() -{ - ImageBuf ib(output_filename, bufspec, &buffer[0]); // wrap the buffer - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool ok = out->open(output_filename, outspec); - OIIO_ASSERT(ok); - ib.write(out.get()); -} - - -static void -test_write(const std::string& explanation, void (*func)(), int tilesize = 0) -{ - outspec.tile_width = tilesize; - outspec.tile_height = tilesize; - outspec.tile_depth = 1; - double t = time_trial(func, ntrials); - double rate = double(total_image_pixels) / t; - std::cout << " " << explanation << ": " - << Strutil::timeintervalformat(t, 2) << " = " - << Strutil::sprintf("%5.1f", rate / 1.0e6) << " Mpel/s" - << std::endl; -} - - - -static float -time_loop_pixels_1D(ImageBuf& ib, int iters) -{ - OIIO_ASSERT(ib.localpixels() && ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - int nchannels = spec.nchannels; - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - const float* f = (const float*)ib.pixeladdr(spec.x, spec.y, spec.z); - OIIO_DASSERT(f); - for (imagesize_t p = 0; p < npixels; ++p) { - sum += f[0]; - f += nchannels; - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static float -time_loop_pixels_3D(ImageBuf& ib, int iters) -{ - OIIO_ASSERT(ib.localpixels() && ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - int nchannels = spec.nchannels; - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - const float* f = (const float*)ib.pixeladdr(spec.x, spec.y, spec.z); - OIIO_DASSERT(f); - for (int z = spec.z, ze = spec.z + spec.depth; z < ze; ++z) { - for (int y = spec.y, ye = spec.y + spec.height; y < ye; ++y) { - for (int x = spec.x, xe = spec.x + spec.width; x < xe; ++x) { - sum += f[0]; - f += nchannels; - } - } - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static float -time_loop_pixels_3D_getchannel(ImageBuf& ib, int iters) -{ - OIIO_DASSERT(ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - for (int z = spec.z, ze = spec.z + spec.depth; z < ze; ++z) { - for (int y = spec.y, ye = spec.y + spec.height; y < ye; ++y) { - for (int x = spec.x, xe = spec.x + spec.width; x < xe; ++x) { - sum += ib.getchannel(x, y, 0, 0); - } - } - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static float -time_iterate_pixels(ImageBuf& ib, int iters) -{ - OIIO_DASSERT(ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - for (ImageBuf::ConstIterator p(ib); !p.done(); ++p) { - sum += p[0]; - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static float -time_iterate_pixels_slave_pos(ImageBuf& ib, int iters) -{ - OIIO_DASSERT(ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - ImageBuf::ConstIterator slave(ib); - for (ImageBuf::ConstIterator p(ib); !p.done(); ++p) { - slave.pos(p.x(), p.y()); - sum += p[0]; - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static float -time_iterate_pixels_slave_incr(ImageBuf& ib, int iters) -{ - OIIO_DASSERT(ib.pixeltype() == TypeFloat); - const ImageSpec& spec(ib.spec()); - imagesize_t npixels = spec.image_pixels(); - double sum = 0.0f; - for (int i = 0; i < iters; ++i) { - ImageBuf::ConstIterator slave(ib); - for (ImageBuf::ConstIterator p(ib); !p.done(); ++p) { - sum += p[0]; - ++slave; - } - } - // std::cout << float(sum/npixels/iters) << "\n"; - return float(sum / npixels / iters); -} - - - -static void -test_pixel_iteration(const std::string& explanation, - float (*func)(ImageBuf&, int), bool preload, - int iters = 100, int autotile = 64) -{ - imagecache->invalidate_all(true); // Don't hold anything - // Force the whole image to be read at once - imagecache->attribute("autotile", autotile); - imagecache->attribute("autoscanline", 1); - ImageBuf ib(input_filename[0].string(), imagecache); - ib.read(0, 0, preload, TypeFloat); - double t = time_trial(std::bind(func, std::ref(ib), iters), ntrials); - double rate = double(ib.spec().image_pixels()) / (t / iters); - std::cout << " " << explanation << ": " - << Strutil::timeintervalformat(t / iters, 3) << " = " - << Strutil::sprintf("%5.1f", rate / 1.0e6) << " Mpel/s" - << std::endl; -} - - - -static void -set_dataformat(const std::string& output_format, ImageSpec& outspec) -{ - if (output_format == "uint8") - outspec.format = TypeDesc::UINT8; - else if (output_format == "int8") - outspec.format = TypeDesc::INT8; - else if (output_format == "uint16") - outspec.format = TypeDesc::UINT16; - else if (output_format == "int16") - outspec.format = TypeDesc::INT16; - else if (output_format == "half") - outspec.format = TypeDesc::HALF; - else if (output_format == "float") - outspec.format = TypeDesc::FLOAT; - else if (output_format == "double") - outspec.format = TypeDesc::DOUBLE; - // Otherwise leave at the default -} - - - -int -main(int argc, char** argv) -{ - getargs(argc, argv); - if (input_filename.size() == 0) { - std::cout << "Error: Must supply a filename.\n"; - return -1; - } - - OIIO::attribute("threads", numthreads); - OIIO::attribute("exr_threads", numthreads); - conversion.fromstring(conversionname); - - imagecache = ImageCache::create(); - if (cache_size) - imagecache->attribute("max_memory_MB", cache_size); - imagecache->attribute("forcefloat", 1); - - // Allocate a buffer big enough (for floats) - bool all_scanline = true; - total_image_pixels = 0; - imagesize_t maxpelchans = 0; - for (auto&& fn : input_filename) { - ImageSpec spec; - if (!imagecache->get_imagespec(fn, spec, 0, 0, true)) { - std::cout << "File \"" << fn << "\" could not be opened.\n"; - return -1; - } - total_image_pixels += spec.image_pixels(); - maxpelchans = std::max(maxpelchans, - spec.image_pixels() * spec.nchannels); - all_scanline &= (spec.tile_width == 0); - } - imagecache->invalidate_all(true); // Don't hold anything - - if (!iter_only) { - std::cout << "Timing various ways of reading images:\n"; - if (conversion == TypeDesc::UNKNOWN) - std::cout - << " ImageInput reads will keep data in native format.\n"; - else - std::cout << " ImageInput reads will convert data to " - << conversion << "\n"; - buffer.resize(maxpelchans * sizeof(float), 0); - test_read("read_image ", - time_read_image, 0, 0); - if (all_scanline) { - test_read("read_scanline (1 at a time) ", - time_read_scanline_at_a_time, 0, 0); - test_read("read_scanlines (64 at a time) ", - time_read_64_scanlines_at_a_time, 0, 0); - } - test_read("ImageBuf read ", - time_read_imagebuf, 0, 0); - test_read("ImageCache get_pixels ", - time_ic_get_pixels, 0, 0); - test_read("ImageBuf read (autotile) ", - time_read_imagebuf, autotile_size, 0); - test_read("ImageCache get_pixels (autotile) ", - time_ic_get_pixels, autotile_size, 0); - if (all_scanline) { // don't bother for tiled images - test_read("ImageBuf read (autotile+autoscanline) ", - time_read_imagebuf, autotile_size, 1); - test_read("ImageCache get_pixels (autotile+autoscanline)", - time_ic_get_pixels, autotile_size, 1); - } - if (verbose) - std::cout << "\n" << imagecache->getstats(2) << "\n"; - std::cout << std::endl; - } - - if (output_filename.size()) { - // Use the first image - auto in = ImageInput::open(input_filename[0].c_str()); - OIIO_ASSERT(in); - bufspec = in->spec(0, 0); - in->read_image(0, 0, 0, bufspec.nchannels, conversion, &buffer[0]); - in->close(); - in.reset(); - std::cout << "Timing ways of writing images:\n"; - // imagecache->get_imagespec (input_filename[0], bufspec, 0, 0, true); - auto out = ImageOutput::create(output_filename); - OIIO_ASSERT(out); - bool supports_tiles = out->supports("tiles"); - out.reset(); - outspec = bufspec; - set_dataformat(output_format, outspec); - std::cout << " writing as format " << outspec.format << "\n"; - - test_write("write_image (scanline) ", - time_write_image, 0); - if (supports_tiles) - test_write("write_image (tiled) ", - time_write_image, 64); - test_write("write_scanline (one at a time) ", - time_write_scanline_at_a_time, 0); - test_write("write_scanlines (64 at a time) ", - time_write_64_scanlines_at_a_time, 0); - if (supports_tiles) { - test_write("write_tile (one at a time) ", - time_write_tile_at_a_time, 64); - test_write("write_tiles (a whole row at a time) ", - time_write_tiles_row_at_a_time, 64); - } - test_write("ImageBuf::write (scanline) ", - time_write_imagebuf, 0); - if (supports_tiles) - test_write("ImageBuf::write (tiled) ", - time_write_imagebuf, 64); - std::cout << std::endl; - } - - if (!no_iter) { - const int iters = 64; - std::cout << "Timing ways of iterating over an image:\n"; - test_pixel_iteration("Loop pointers on loaded image (\"1D\") ", - time_loop_pixels_1D, true, iters); - test_pixel_iteration("Loop pointers on loaded image (\"3D\") ", - time_loop_pixels_3D, true, iters); - test_pixel_iteration("Loop + getchannel on loaded image (\"3D\")", - time_loop_pixels_3D_getchannel, true, iters / 32); - test_pixel_iteration("Loop + getchannel on cached image (\"3D\")", - time_loop_pixels_3D_getchannel, false, iters / 32); - test_pixel_iteration("Iterate over a loaded image ", - time_iterate_pixels, true, iters); - test_pixel_iteration("Iterate over a cache image ", - time_iterate_pixels, false, iters); - test_pixel_iteration("Iterate over a loaded image (pos slave) ", - time_iterate_pixels_slave_pos, true, iters); - test_pixel_iteration("Iterate over a cache image (pos slave) ", - time_iterate_pixels_slave_pos, false, iters); - test_pixel_iteration("Iterate over a loaded image (incr slave)", - time_iterate_pixels_slave_incr, true, iters); - test_pixel_iteration("Iterate over a cache image (incr slave) ", - time_iterate_pixels_slave_incr, false, iters); - } - if (verbose) - std::cout << "\n" << imagecache->getstats(2) << "\n"; - - ImageCache::destroy(imagecache); - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/argparse_test.cpp b/Sources/OpenImageIO/libutil/argparse_test.cpp deleted file mode 100644 index ffd4e37e..00000000 --- a/Sources/OpenImageIO/libutil/argparse_test.cpp +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include - -#include -#include -#include -#include -#include - -using namespace OIIO; - - - -// Split a command line into a vector of const char* arguments. -std::vector -split_commands(string_view commands) -{ - std::vector result; - for (auto& c : Strutil::splitsv(commands)) { - result.push_back(ustring(c).c_str()); - } - return result; -} - - - -static std::vector prearg; -static std::vector postarg; -static std::vector callbacklist; - - -static int -parse_prearg(int argc, const char* argv[]) -{ - for (int i = 0; i < argc; i++) - prearg.emplace_back(argv[i]); - return 0; -} - - -static int -parse_postarg(int argc, const char* argv[]) -{ - for (int i = 0; i < argc; i++) - postarg.emplace_back(argv[i]); - return 0; -} - - - -static int -callback(int argc, const char* argv[]) -{ - for (int i = 0; i < argc; i++) { - // std::cout << "callback " << argv[i] << "\n"; - callbacklist.emplace_back(argv[i]); - } - return 0; -} - - - -static void -test_old() -{ - auto args = split_commands("basic alpha --flag --unflag --intarg 42 " - "--floatarg 3.5 --stringarg foo " - "--append xxx --append yyy " - "--hidden " - "--callback who " - "bravo charlie"); - bool flag = false; - bool unflag = true; - bool hidden = false; - int i = 0; - float f = 0; - std::string s; - std::vector list; - prearg.clear(); - postarg.clear(); - callbacklist.clear(); - - ArgParse ap; - // clang-format off - ap.options( - "basic", - "%1", parse_prearg, "", - "%*", parse_postarg, "", - "--flag", &flag, "Set flag", - "--unflag %!", &unflag, "Unset flag", - "--hidden", &hidden, "", // no help means hidden - "--intarg %d", &i, "int", - "--floatarg %f", &f, "float", - "--stringarg %s", &s, "string", - "--callback %@ %s", callback, nullptr, "callback", - "--append %L", &list, "string list", - nullptr); - ap.usage(); - // clang-format on - - ap.parse(int(args.size()), args.data()); - OIIO_CHECK_EQUAL(flag, true); - OIIO_CHECK_EQUAL(unflag, false); - OIIO_CHECK_EQUAL(hidden, true); - OIIO_CHECK_EQUAL(i, 42); - OIIO_CHECK_EQUAL(f, 3.5f); - OIIO_CHECK_EQUAL(s, "foo"); - OIIO_CHECK_EQUAL(list.size(), 2); - if (list.size() == 2) { - OIIO_CHECK_EQUAL(list[0], "xxx"); - OIIO_CHECK_EQUAL(list[1], "yyy"); - } - OIIO_CHECK_EQUAL(prearg.size(), 1); - if (prearg.size() >= 1) { - OIIO_CHECK_EQUAL(prearg[0], "alpha"); - } - OIIO_CHECK_EQUAL(postarg.size(), 2); - if (postarg.size() >= 2) { - OIIO_CHECK_EQUAL(postarg[0], "bravo"); - OIIO_CHECK_EQUAL(postarg[1], "charlie"); - } - OIIO_CHECK_EQUAL(callbacklist.size(), 2); - if (callbacklist.size() >= 2) { - OIIO_CHECK_EQUAL(callbacklist[0], "--callback"); - OIIO_CHECK_EQUAL(callbacklist[1], "who"); - } -} - - - -static void -test_new() -{ - std::cout << "\nTesting new style:\n"; - auto args = split_commands("basic -f -u --ci --cs --cf --istore 15 " - "--fstore 12.5 --sstore hi " - "--color 0.25 0.5 0.75 " - "--app 14 --app 22 " - "--sapp hello --sapp world " - "--fbi a b c " - "bravo charlie"); - - // clang-format off - ArgParse ap; - ap.intro("new style!") - .usage("here is my usage") - .description("description") - .epilog("epilog"); - - ap.arg("filename") - .action(ArgParse::append()) - .hidden(); - ap.arg("-f") - .help("Simple flag argument") - .action(ArgParse::store_true()); - ap.arg("--f2") - .help("Simple flag argument (unused)") - .store_true(); - ap.arg("-u") - .help("Simple flag argument - store false if set") - .store_false(); - ap.arg("--u2") - .help("Simple flag argument - store false if set (unused)") - .store_false(); - ap.arg("--ci") - .help("Store constant int") - .action(ArgParse::store_const(42)); - ap.arg("--cf") - .help("Store constant float") - .action(ArgParse::store_const(3.14159f)); - ap.arg("--cfdef") - .help("Store constant float") - .defaultval(42.0f) - .action(ArgParse::store_const(3.14159f)); - ap.arg("--cs") - .help("Store constant string") - .action(ArgParse::store_const("hey hey")); - - ap.separator("Storing values:"); - ap.arg("--istore") - .help("store an int value") - .metavar("INT") - .action(ArgParse::store()); - ap.arg("--fstore") - .help("store a float value") - .metavar("FLOAT") - .action(ArgParse::store()); - ap.arg("--sstore") - .help("store a string value") - .metavar("STRING") - .action(ArgParse::store()); -#if 0 - ap.arg("--color %f:R %f:G %f:B") - .help("store 3 floats into a color") - .action(ArgParse::store()); -#else - ap.arg("--color R G B") - // .metavar("R G B") - .help("store 3 floats into a color") - .defaultval(Imath::Color3f(0.0f, 0.0f, 0.0f)) - .action(ArgParse::store()); -#endif - ap.arg("--unsettriple") - .help("store 3 floats into a triple") - .metavar("R G B") - .defaultval(Imath::Color3f(1.0f, 2.0f, 4.0f)) - .action(ArgParse::store()); - ap.arg("--app") - .help("store an int, will append to a list") - .metavar("VAL") - .action(ArgParse::append()); - ap.arg("--sapp") - .help("store a string, will append to a list") - .metavar("STR") - .action(ArgParse::append()); - ap.arg("--fbi") - .help("Call the FBI") - .nargs(3); - ap.add_help(true); - // clang-format on - - ap.parse(int(args.size()), args.data()); - ap.print_help(); - - OIIO_CHECK_EQUAL(ap["f"].get(), 1); - OIIO_CHECK_EQUAL(ap["f2"].get(), 0); - OIIO_CHECK_EQUAL(ap["u"].get(), 0); - OIIO_CHECK_EQUAL(ap["u2"].get(), 1); - OIIO_CHECK_EQUAL(ap["ci"].get(), 42); - OIIO_CHECK_EQUAL(ap["cf"].get(), 3.14159f); - OIIO_CHECK_EQUAL(ap["cfdef"].get(), 42.0f); - OIIO_CHECK_EQUAL(ap["cs"].get(), "hey hey"); - OIIO_CHECK_EQUAL(ap["istore"].get(), 15); - OIIO_CHECK_EQUAL(ap["fstore"].get(), 12.5f); - OIIO_CHECK_EQUAL(ap["sstore"].get(), "hi"); - OIIO_CHECK_EQUAL(ap["color"].get(), - Imath::Color3f(0.25f, 0.5f, 0.75f)); - OIIO_CHECK_EQUAL(ap["unsettriple"].get(), - Imath::Color3f(1.0f, 2.0f, 4.0f)); - OIIO_CHECK_EQUAL(ap["filename"].type(), TypeDesc("string[2]")); - std::cout << "\nAll args:\n"; - for (auto& a : ap.params()) - Strutil::print(" {} = {} [{}]\n", a.name(), a.get_string(), - a.type()); - std::cout << "Extracting filenames:\n"; - auto fn = ap["filename"].as_vec(); - for (auto& f : fn) - Strutil::print(" \"{}\"\n", f); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_old(); - test_new(); - - return unit_test_failures != 0; -} diff --git a/Sources/OpenImageIO/libutil/atomic_test.cpp b/Sources/OpenImageIO/libutil/atomic_test.cpp deleted file mode 100644 index 5d4f5f65..00000000 --- a/Sources/OpenImageIO/libutil/atomic_test.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace OIIO; - -// How do we test atomics? Run a whole bunch of threads, incrementing -// and decrementing the crap out of it, and make sure it has the right -// value at the end. - -static int iterations = 2000000; -static int numthreads = clamp((int)Sysutil::physical_concurrency(), 2, 16); -static int ntrials = 5; -static bool verbose = false; -static bool wedge = false; - -static spin_mutex print_mutex; // make the prints not clobber each other -atomic_int ai; -atomic_ll all; -std::atomic af(0.0f); -std::atomic ad(0.0); - - -static void -do_int_math(int iterations) -{ - for (int i = 0; i < iterations; ++i) { - ++ai; - ai += 3; - --ai; - ai++; - ai -= 3; - --ai; - // That should have a net change of 0, but since other threads - // are doing operations simultaneously, it's only after all - // threads have finished that we can be sure it's back to the - // initial value. - } -} - - - -void -test_atomic_int() -{ - // Test and, or, xor - ai = 42; - ai &= 15; - OIIO_CHECK_EQUAL(ai, 10); - ai |= 6; - OIIO_CHECK_EQUAL(ai, 14); - ai ^= 31; - OIIO_CHECK_EQUAL(ai, 17); - ai = 42; - int tmp; - tmp = ai.fetch_and(15); - OIIO_CHECK_EQUAL(tmp, 42); - OIIO_CHECK_EQUAL(ai, 10); - tmp = ai.fetch_or(6); - OIIO_CHECK_EQUAL(tmp, 10); - OIIO_CHECK_EQUAL(ai, 14); - tmp = ai.fetch_xor(31); - OIIO_CHECK_EQUAL(tmp, 14); - OIIO_CHECK_EQUAL(ai, 17); -} - - - -static void -do_int64_math(int iterations) -{ - for (int i = 0; i < iterations; ++i) { - ++all; - all += 3; - --all; - all++; - all -= 3; - --all; - // That should have a net change of 0, but since other threads - // are doing operations simultaneously, it's only after all - // threads have finished that we can be sure it's back to the - // initial value. - } -} - - - -void -test_atomic_int64() -{ - // Test and, or, xor - all = 42; - all &= 15; - OIIO_CHECK_EQUAL(all, 10); - all |= 6; - OIIO_CHECK_EQUAL(all, 14); - all ^= 31; - OIIO_CHECK_EQUAL(all, 17); - all = 42; - long long tmp; - tmp = all.fetch_and(15); - OIIO_CHECK_EQUAL(tmp, 42); - OIIO_CHECK_EQUAL(all, 10); - tmp = all.fetch_or(6); - OIIO_CHECK_EQUAL(tmp, 10); - OIIO_CHECK_EQUAL(all, 14); - tmp = all.fetch_xor(31); - OIIO_CHECK_EQUAL(tmp, 14); - OIIO_CHECK_EQUAL(all, 17); -} - - - -static void -do_float_math(int iterations) -{ - if (verbose) { - spin_lock lock(print_mutex); - std::cout << "thread " << std::this_thread::get_id() - << ", all = " << all << "\n"; - } - for (int i = 0; i < iterations; ++i) { - atomic_fetch_add(af, 1.0f); - atomic_fetch_add(af, 3.0f); - atomic_fetch_add(af, -1.0f); - atomic_fetch_add(af, 1.0f); - atomic_fetch_add(af, -3.0f); - atomic_fetch_add(af, -1.0f); - // That should have a net change of 0, but since other threads - // are doing operations simultaneously, it's only after all - // threads have finished that we can be sure it's back to the - // initial value. - } -} - - - -static void -do_double_math(int iterations) -{ - if (verbose) { - spin_lock lock(print_mutex); - std::cout << "thread " << std::this_thread::get_id() - << ", all = " << all << "\n"; - } - for (int i = 0; i < iterations; ++i) { - atomic_fetch_add(ad, 1.0); - atomic_fetch_add(ad, 3.0); - atomic_fetch_add(ad, -1.0); - atomic_fetch_add(ad, 1.0); - atomic_fetch_add(ad, -3.0); - atomic_fetch_add(ad, -1.0); - // That should have a net change of 0, but since other threads - // are doing operations simultaneously, it's only after all - // threads have finished that we can be sure it's back to the - // initial value. - } -} - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("atomic_test\n" OIIO_INTRO_STRING) - .usage("atomic_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - std::cout << "hw threads = " << Sysutil::hardware_concurrency() << "\n"; - - std::cout << "\natomic int:\n"; - test_atomic_int(); - ai = 0; - if (wedge) - timed_thread_wedge(do_int_math, numthreads, iterations, ntrials); - else - timed_thread_wedge(do_int_math, numthreads, iterations, ntrials, - numthreads); - OIIO_CHECK_EQUAL(ai, 0); - - std::cout << "\natomic int64:\n"; - test_atomic_int64(); - all = 0; - if (wedge) - timed_thread_wedge(do_int64_math, numthreads, iterations, ntrials); - else - timed_thread_wedge(do_int64_math, numthreads, iterations, ntrials, - numthreads); - OIIO_CHECK_EQUAL(all, 0); - - std::cout << "\natomic floats:\n"; - af = 0.0f; - if (wedge) - timed_thread_wedge(do_float_math, numthreads, iterations, ntrials); - else - timed_thread_wedge(do_float_math, numthreads, iterations, ntrials, - numthreads); - OIIO_CHECK_EQUAL(af, 0.0f); - - std::cout << "\natomic doubles:\n"; - ad = 0.0; - if (wedge) - timed_thread_wedge(do_double_math, numthreads, iterations, ntrials); - else - timed_thread_wedge(do_double_math, numthreads, iterations, ntrials, - numthreads); - OIIO_CHECK_EQUAL(ad, 0.0); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/filesystem_test.cpp b/Sources/OpenImageIO/libutil/filesystem_test.cpp deleted file mode 100644 index 6ad77455..00000000 --- a/Sources/OpenImageIO/libutil/filesystem_test.cpp +++ /dev/null @@ -1,618 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include -#include - -#include -#include -#include -#include - -#ifndef _WIN32 -# include -#endif - -using namespace OIIO; - - -// This will be run via testsuite/unit_filesystem, from the -// build/ARCH/src/libOpenImageIO directory. Two levels up will be -// build/ARCH. - - - -void -test_filename_decomposition() -{ - std::string test("/directoryA/directory/filename.ext"); - - std::cout << "Testing filename, extension, parent_path\n"; - OIIO_CHECK_EQUAL(Filesystem::filename(test), "filename.ext"); - OIIO_CHECK_EQUAL(Filesystem::extension(test), ".ext"); - OIIO_CHECK_EQUAL(Filesystem::extension("./foo.dir/../blah/./bar/file.ext"), - ".ext"); - OIIO_CHECK_EQUAL(Filesystem::extension("/directory/filename"), ""); - OIIO_CHECK_EQUAL(Filesystem::extension("/directory/filename."), "."); - OIIO_CHECK_EQUAL(Filesystem::extension("a.foo"), ".foo"); - OIIO_CHECK_EQUAL(Filesystem::extension("a.foo", false), "foo"); - OIIO_CHECK_EQUAL(Filesystem::extension("foo"), ""); - OIIO_CHECK_EQUAL(Filesystem::extension("foo", false), ""); - OIIO_CHECK_EQUAL(Filesystem::extension(".foo"), ""); - OIIO_CHECK_EQUAL(Filesystem::extension(".foo", false), ""); - - OIIO_CHECK_EQUAL(Filesystem::parent_path(test), "/directoryA/directory"); - - std::cout << "Testing path_is_absolute\n"; - OIIO_CHECK_EQUAL(Filesystem::path_is_absolute("/foo/bar"), true); - OIIO_CHECK_EQUAL(Filesystem::path_is_absolute("foo/bar"), false); - OIIO_CHECK_EQUAL(Filesystem::path_is_absolute("../foo/bar"), false); - - std::cout << "Testing replace_extension\n"; - OIIO_CHECK_EQUAL(Filesystem::replace_extension(test, "foo"), - "/directoryA/directory/filename.foo"); - - std::cout << "Testing generic_filepath\n"; -#if _WIN32 - OIIO_CHECK_EQUAL(Filesystem::generic_filepath("\\x\\y"), "/x/y"); - OIIO_CHECK_EQUAL(Filesystem::generic_filepath("c:\\x\\y"), "c:/x/y"); -#endif - - std::cout << "Testing filename_to_regex\n"; - OIIO_CHECK_EQUAL(Filesystem::filename_to_regex("/foo/bar/baz.exr"), - "/foo/bar/baz\\.exr"); - OIIO_CHECK_EQUAL(Filesystem::filename_to_regex("/f(o)o/b[a]r/b{a}z.exr"), - "/f\\(o\\)o/b\\[a\\]r/b\\{a\\}z\\.exr"); - OIIO_CHECK_EQUAL(Filesystem::filename_to_regex("/foo/bar/baz.*"), - "/foo/bar/baz\\..*"); - OIIO_CHECK_EQUAL(Filesystem::filename_to_regex("/fo?/b*r/b?z.*"), - "/fo.?/b.*r/b.?z\\..*"); -} - - - -void -test_filename_searchpath_find() -{ -#if _WIN32 -# define DIRSEP "\\" -#else -# define DIRSEP "/" -#endif -#define PATHSEP ":" - std::string pathlist(".." DIRSEP ".." PATHSEP ".." DIRSEP ".." DIRSEP - "cpack" PATHSEP "foo/bar/baz"); - - std::cout << "Testing searchpath_split\n"; - std::vector dirs; - - // Split of empty string should make an empty path vector - dirs.clear(); - Filesystem::searchpath_split("", dirs, false); - OIIO_CHECK_EQUAL(dirs.size(), 0); - - // Test that empty paths don't show up in the result vector - dirs.clear(); - Filesystem::searchpath_split(":", dirs, false); - OIIO_CHECK_EQUAL(dirs.size(), 0); - Filesystem::searchpath_split("::", dirs, false); - OIIO_CHECK_EQUAL(dirs.size(), 0); - dirs.clear(); - Filesystem::searchpath_split(":abc::def:", dirs, false); - OIIO_CHECK_EQUAL(dirs.size(), 2); - OIIO_CHECK_EQUAL(dirs[0], "abc"); - OIIO_CHECK_EQUAL(dirs[1], "def"); - - dirs.clear(); - Filesystem::searchpath_split(pathlist, dirs); - OIIO_CHECK_EQUAL(dirs.size(), 3); - OIIO_CHECK_EQUAL(dirs[0], ".." DIRSEP ".."); - OIIO_CHECK_EQUAL(dirs[1], ".." DIRSEP ".." DIRSEP "cpack"); - OIIO_CHECK_EQUAL(dirs[2], "foo/bar/baz"); - - std::cout << "Testing searchpath_find\n"; - - // non-recursive search success - OIIO_CHECK_EQUAL(Filesystem::searchpath_find("License.txt", dirs, false, - false), - ".." DIRSEP ".." DIRSEP "cpack" DIRSEP "License.txt"); - - // non-recursive search failure (file is in a subdirectory) - OIIO_CHECK_EQUAL(Filesystem::searchpath_find("oiioversion.h", dirs, false, - false), - ""); - - // recursive search success (file is in a subdirectory) - OIIO_CHECK_EQUAL(Filesystem::searchpath_find("oiioversion.h", dirs, false, - true), - ".." DIRSEP ".." DIRSEP "include" DIRSEP - "OpenImageIO" DIRSEP "oiioversion.h"); - - // Test find_program - OIIO_CHECK_ASSERT( - Filesystem::is_executable(Filesystem::find_program("bash"))); -} - - - -inline std::string -my_read_text_file(string_view filename) -{ - std::string err; - std::string contents; - bool ok = Filesystem::read_text_file(filename, contents); - OIIO_CHECK_ASSERT(ok); - return contents; -} - - -inline std::string -my_read_text_file(string_view filename, size_t size) -{ - std::string err; - std::string contents; - bool ok = Filesystem::read_text_file(filename, contents, size); - OIIO_CHECK_ASSERT(ok); - return contents; -} - - -inline std::string -my_read_text_from_command(string_view filename) -{ - std::string err; - std::string contents; - bool ok = Filesystem::read_text_from_command(filename, contents); - OIIO_CHECK_ASSERT(ok); - return contents; -} - - -inline std::string -my_read_text_from_command(string_view filename, size_t size) -{ - std::string err; - std::string contents; - bool ok = Filesystem::read_text_from_command(filename, contents, size); - OIIO_CHECK_ASSERT(ok); - return contents; -} - - - -static void -test_file_status() -{ - // Make test file, test Filesystem::fopen in the process. - FILE* file = Filesystem::fopen("testfile", "wb"); - OIIO_CHECK_ASSERT(file != NULL); - const char testtext[] = "test\nfoo\nbar\n"; - fputs(testtext, file); - fclose(file); - - std::cout << "Testing file_size:\n"; - OIIO_CHECK_EQUAL(Filesystem::file_size("testfile"), 13); - - std::cout << "Testing read_text_file\n"; - OIIO_CHECK_EQUAL(my_read_text_file("testfile"), testtext); - std::cout << "Testing write_text_file\n"; - Filesystem::write_text_file("testfile4", testtext); - OIIO_CHECK_EQUAL(my_read_text_file("testfile4"), testtext); - std::cout << "Testing read_text_file with size limit\n"; - OIIO_CHECK_EQUAL(my_read_text_file("testfile", 10), "test\nfoo\nb"); - std::cout << "Testing read_text_from_command\n"; - OIIO_CHECK_EQUAL(my_read_text_from_command("cat testfile"), testtext); - std::cout << "Testing read_text_from_command with size limit\n"; - OIIO_CHECK_EQUAL(my_read_text_from_command("cat testfile", 7), "test\nfo"); - - std::cout << "Testing read_bytes:\n"; - char buf[3]; - size_t nread = Filesystem::read_bytes("testfile", buf, 3, 5); - OIIO_CHECK_EQUAL(nread, 3); - OIIO_CHECK_EQUAL(buf[0], 'f'); - OIIO_CHECK_EQUAL(buf[1], 'o'); - OIIO_CHECK_EQUAL(buf[2], 'o'); - - std::cout << "Testing create_directory\n"; - Filesystem::create_directory("testdir"); - - std::cout << "Testing exists\n"; - OIIO_CHECK_ASSERT(Filesystem::exists("testfile")); - OIIO_CHECK_ASSERT(Filesystem::exists("testdir")); - OIIO_CHECK_ASSERT(!Filesystem::exists("noexist")); - std::cout << "Testing is_directory, is_regular, is_executable\n"; - OIIO_CHECK_ASSERT(Filesystem::is_regular("testfile")); - OIIO_CHECK_ASSERT(!Filesystem::is_directory("testfile")); - OIIO_CHECK_ASSERT(!Filesystem::is_executable("testfile")); - OIIO_CHECK_ASSERT(!Filesystem::is_regular("testdir")); - OIIO_CHECK_ASSERT(Filesystem::is_directory("testdir")); - OIIO_CHECK_ASSERT(!Filesystem::is_executable("testdir")); - OIIO_CHECK_ASSERT(!Filesystem::is_regular("noexist")); - OIIO_CHECK_ASSERT(!Filesystem::is_directory("noexist")); - OIIO_CHECK_ASSERT(!Filesystem::is_executable("noexist")); - OIIO_CHECK_ASSERT(Filesystem::is_executable(Sysutil::this_program_path())); - - std::cout << "Testing copy, rename, remove\n"; - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile2")); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile3")); - Filesystem::copy("testfile", "testfile2"); - OIIO_CHECK_ASSERT(Filesystem::exists("testfile2")); - OIIO_CHECK_EQUAL(my_read_text_file("testfile2"), testtext); - Filesystem::rename("testfile2", "testfile3"); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile2")); - OIIO_CHECK_ASSERT(Filesystem::exists("testfile3")); - OIIO_CHECK_EQUAL(my_read_text_file("testfile3"), testtext); - Filesystem::remove("testfile"); - Filesystem::remove("testfile3"); - Filesystem::remove("testfile4"); - Filesystem::remove("testdir"); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile")); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile2")); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile3")); - OIIO_CHECK_ASSERT(!Filesystem::exists("testfile4")); - OIIO_CHECK_ASSERT(!Filesystem::exists("testdir")); -} - - - -static void -test_seq(const char* str, const char* expected) -{ - std::vector sequence; - Filesystem::enumerate_sequence(str, sequence); - std::stringstream joined; - for (size_t i = 0; i < sequence.size(); ++i) { - if (i) - joined << " "; - joined << sequence[i]; - } - std::cout << " \"" << str << "\" -> " << joined.str() << "\n"; - OIIO_CHECK_EQUAL(joined.str(), std::string(expected)); -} - - - -static void -test_file_seq(const char* pattern, string_view overrideval, - const std::string& expected) -{ - std::vector numbers; - std::vector names; - std::string normalized_pattern; - std::string frame_range; - - Filesystem::parse_pattern(pattern, 0, normalized_pattern, frame_range); - if (overrideval.size()) - frame_range = overrideval; - Filesystem::enumerate_sequence(frame_range, numbers); - Filesystem::enumerate_file_sequence(normalized_pattern, numbers, names); - std::string joined = Strutil::join(names, " "); - Strutil::print(" {}{}{} -> {}\n", pattern, overrideval.size() ? " + " : "", - overrideval, joined); - OIIO_CHECK_EQUAL(joined, expected); -} - - - -static void -test_file_seq_with_view(const char* pattern, string_view overrideval, - string_view view, const std::string& expected) -{ - std::vector numbers; - std::vector views; - std::vector names; - std::string normalized_pattern; - std::string frame_range; - - Filesystem::parse_pattern(pattern, 0, normalized_pattern, frame_range); - if (overrideval.size()) - frame_range = overrideval; - Filesystem::enumerate_sequence(frame_range, numbers); - - if (view.size()) { - for (size_t i = 0, e = numbers.size(); i < e; ++i) - views.emplace_back(view); - } - - Filesystem::enumerate_file_sequence(normalized_pattern, numbers, views, - names); - std::string joined = Strutil::join(names, " "); - Strutil::print(" {}{}{} -> {}\n", pattern, overrideval.size() ? " + " : "", - overrideval, joined); - OIIO_CHECK_EQUAL(joined, expected); -} - - - -static void -test_scan_file_seq(const char* pattern, const std::string& expected) -{ - std::vector numbers; - std::vector names; - std::string normalized_pattern; - std::string frame_range; - - Filesystem::parse_pattern(pattern, 0, normalized_pattern, frame_range); - Filesystem::scan_for_matching_filenames(normalized_pattern, numbers, names); - std::string joined = Strutil::join(names, " "); - std::cout << " " << pattern; - std::cout << " -> " << joined << "\n"; - OIIO_CHECK_EQUAL(joined, expected); - - // Check that we don't crash from exceptions generated by strangely - // formed patterns. - const char* weird - = "{'cpu_model': 'Intel(R) Xeon(R) CPU E5-2630 @ 2.30GHz'}"; - Filesystem::parse_pattern(weird, 0, normalized_pattern, frame_range); - Filesystem::scan_for_matching_filenames(normalized_pattern, numbers, names); - OIIO_CHECK_EQUAL(names.size(), 0); - // If we didn't crash above, we're ok! -} - - - -static void -test_scan_file_seq_with_views(const char* pattern, const char** views_, - const std::string& expected) -{ - std::vector frame_numbers; - std::vector frame_views; - std::vector frame_names; - std::string normalized_pattern; - std::string frame_range; - std::vector views; - - for (size_t i = 0; views_[i]; ++i) - if (views_[i]) - views.emplace_back(views_[i]); - - Filesystem::parse_pattern(pattern, 0, normalized_pattern, frame_range); - Filesystem::scan_for_matching_filenames(normalized_pattern, views, - frame_numbers, frame_views, - frame_names); - for (auto& f : frame_names) - f = Filesystem::generic_filepath(f); - std::string joined = Strutil::join(frame_names, " "); - std::cout << " " << pattern; - std::cout << " -> " << joined << "\n"; - OIIO_CHECK_EQUAL(joined, expected); -} - - - -void -test_frame_sequences() -{ - std::cout << "Testing frame number sequences:\n"; - test_seq("3", "3"); - test_seq("1-5", "1 2 3 4 5"); - test_seq("5-1", "5 4 3 2 1"); - test_seq("1-3,6,10-12", "1 2 3 6 10 11 12"); - test_seq("1-5x2", "1 3 5"); - test_seq("1-5y2", "2 4"); - std::cout << "\n"; - - test_file_seq( - "foo.1-5#.exr", NULL, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq( - "foo.5-1#.exr", NULL, - "foo.0005.exr foo.0004.exr foo.0003.exr foo.0002.exr foo.0001.exr"); - test_file_seq( - "foo.1-3,6,10-12#.exr", NULL, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0006.exr foo.0010.exr foo.0011.exr foo.0012.exr"); - test_file_seq("foo.1-5x2#.exr", NULL, - "foo.0001.exr foo.0003.exr foo.0005.exr"); - test_file_seq("foo.1-5y2#.exr", NULL, "foo.0002.exr foo.0004.exr"); - - test_file_seq( - "foo.#.exr", "1-5", - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq("foo.#.exr", "1-5x2", - "foo.0001.exr foo.0003.exr foo.0005.exr"); - - test_file_seq("foo.1-3@@.exr", NULL, "foo.01.exr foo.02.exr foo.03.exr"); - test_file_seq("foo.1-3@#.exr", NULL, - "foo.00001.exr foo.00002.exr foo.00003.exr"); - - test_file_seq( - "foo.1-5%04d.exr", NULL, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq( - "foo.%04d.exr", "1-5", - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq( - "foo.%4d.exr", "1-5", - "foo. 1.exr foo. 2.exr foo. 3.exr foo. 4.exr foo. 5.exr"); - test_file_seq("foo.%d.exr", "1-5", - "foo.1.exr foo.2.exr foo.3.exr foo.4.exr foo.5.exr"); - - const char* views1[] = { "left", "right", "foo", "", NULL }; - for (auto view : views1) { - test_file_seq_with_view( - "foo.1-5#.exr", NULL, view, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq_with_view( - "foo.5-1#.exr", NULL, view, - "foo.0005.exr foo.0004.exr foo.0003.exr foo.0002.exr foo.0001.exr"); - test_file_seq_with_view( - "foo.1-3,6,10-12#.exr", NULL, view, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0006.exr foo.0010.exr foo.0011.exr foo.0012.exr"); - test_file_seq_with_view("foo.1-5x2#.exr", NULL, view, - "foo.0001.exr foo.0003.exr foo.0005.exr"); - test_file_seq_with_view("foo.1-5y2#.exr", NULL, view, - "foo.0002.exr foo.0004.exr"); - - test_file_seq_with_view( - "foo.#.exr", "1-5", view, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq_with_view("foo.#.exr", "1-5x2", view, - "foo.0001.exr foo.0003.exr foo.0005.exr"); - - test_file_seq_with_view("foo.1-3@@.exr", NULL, view, - "foo.01.exr foo.02.exr foo.03.exr"); - test_file_seq_with_view("foo.1-3@#.exr", NULL, view, - "foo.00001.exr foo.00002.exr foo.00003.exr"); - - test_file_seq_with_view( - "foo.1-5%04d.exr", NULL, view, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq_with_view( - "foo.%04d.exr", "1-5", view, - "foo.0001.exr foo.0002.exr foo.0003.exr foo.0004.exr foo.0005.exr"); - test_file_seq_with_view( - "foo.%4d.exr", "1-5", view, - "foo. 1.exr foo. 2.exr foo. 3.exr foo. 4.exr foo. 5.exr"); - test_file_seq_with_view( - "foo.%d.exr", "1-5", view, - "foo.1.exr foo.2.exr foo.3.exr foo.4.exr foo.5.exr"); - } - - // test_file_seq_with_view ("%V.%04d", NULL, NULL, ""); - // test_file_seq_with_view ("%v", NULL, NULL, ""); - // test_file_seq_with_view ("%V", NULL, "", ""); - // test_file_seq_with_view ("%v", NULL, "", ""); - // test_file_seq_with_view ("%V", NULL, "left", "left"); - // test_file_seq_with_view ("%V", NULL, "right", "right"); - // test_file_seq_with_view ("%v", NULL, "left", "l"); - // test_file_seq_with_view ("%v", NULL, "right", "r"); - test_file_seq_with_view("foo_%V.1-2#.exr", NULL, "left", - "foo_left.0001.exr foo_left.0002.exr"); - test_file_seq_with_view("%V/foo_%V.1-2#.exr", NULL, "left", - "left/foo_left.0001.exr left/foo_left.0002.exr"); - test_file_seq_with_view("%v/foo_%V.1-2#.exr", NULL, "left", - "l/foo_left.0001.exr l/foo_left.0002.exr"); - test_file_seq_with_view("%V/foo_%v.1-2#.exr", NULL, "left", - "left/foo_l.0001.exr left/foo_l.0002.exr"); - test_file_seq_with_view("%v/foo_%v.1-2#.exr", NULL, "left", - "l/foo_l.0001.exr l/foo_l.0002.exr"); - - std::cout << "\n"; -} - - - -void -create_test_file(string_view fn) -{ - Filesystem::write_text_file(fn, ""); -} - - - -void -test_scan_sequences() -{ - std::cout << "Testing frame sequence scanning:\n"; - - std::vector filenames; - - for (size_t i = 1; i <= 5; i++) { - std::string fn = Strutil::sprintf("foo.%04d.exr", i); - filenames.push_back(fn); - create_test_file(fn); - } - // Deliberate file that's not a match! Make sure dots in the filename - // aren't regex dots that match any character. - filenames.push_back("fooX0000Xexr"); - create_test_file("fooX0000Xexr"); - - test_scan_file_seq( - "foo.#.exr", - "./foo.0001.exr ./foo.0002.exr ./foo.0003.exr ./foo.0004.exr ./foo.0005.exr"); - - filenames.clear(); - - Filesystem::create_directory("left"); - Filesystem::create_directory("left/l"); - - for (size_t i = 1; i <= 5; i++) { - std::string fn = Strutil::sprintf("left/l/foo_left_l.%04d.exr", i); - filenames.push_back(fn); - create_test_file(fn); - } - - const char* views[] = { "left", NULL }; - - test_scan_file_seq_with_views( - "%V/%v/foo_%V_%v.#.exr", views, - "left/l/foo_left_l.0001.exr left/l/foo_left_l.0002.exr left/l/foo_left_l.0003.exr left/l/foo_left_l.0004.exr left/l/foo_left_l.0005.exr"); - - filenames.clear(); - - Filesystem::create_directory("right"); - Filesystem::create_directory("right/r"); - - std::string fn; - - fn = "left/l/foo_left_l"; - filenames.push_back(fn); - create_test_file(fn); - - fn = "right/r/foo_right_r"; - filenames.push_back(fn); - create_test_file(fn); - - const char* views2[] = { "left", "right", NULL }; - - test_scan_file_seq_with_views("%V/%v/foo_%V_%v", views2, - "left/l/foo_left_l right/r/foo_right_r"); -} - - - -void -test_mem_proxies() -{ - std::cout << "Testing memory file proxies:\n"; - std::vector input_buf { 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19 }; - std::vector output_buf; - - Filesystem::IOMemReader in(input_buf); - Filesystem::IOVecOutput out(output_buf); - char b[4]; - size_t len = 0; - while ((len = in.read(b, 4))) // read up to 4 bytes at a time - out.write(b, len); - OIIO_CHECK_ASSERT(input_buf == output_buf); - // Now test seeking - in.seek(3); - out.seek(1); - in.read(b, 2); - out.write(b, 2); - std::vector ref_buf { - 10, 13, 14, 13, 14, 15, 16, 17, 18, 19 - }; - OIIO_CHECK_ASSERT(output_buf == ref_buf); -} - - - -void -test_last_write_time() -{ - Filesystem::write_text_file("oiio-testtime.txt", "test"); - time_t t = Filesystem::last_write_time("oiio-testtime.txt"); - std::cout << "Last write time of oiio-testtime.txt is " << t << "\n"; - Filesystem::last_write_time("oiio-testtime.txt", t - 42); - OIIO_CHECK_EQUAL(Filesystem::last_write_time("oiio-testtime.txt"), t - 42); - Filesystem::remove("oiio-testtime.txt"); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_filename_decomposition(); - test_filename_searchpath_find(); - test_file_status(); - test_frame_sequences(); - test_scan_sequences(); - test_mem_proxies(); - test_last_write_time(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/filter_test.cpp b/Sources/OpenImageIO/libutil/filter_test.cpp deleted file mode 100644 index 2bced813..00000000 --- a/Sources/OpenImageIO/libutil/filter_test.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - -static int iterations = 10; -static int ntrials = 5; -static bool verbose = false; -static bool normalize = false; -static int graphxres = 1280, graphyres = 500; -static int graphyzero = graphyres * 3 / 4; -static int graphxzero = graphxres / 2; -static float graphunit = 200; - - - -static void -getargs(int argc, char* argv[]) -{ - // clang-format off - ArgParse ap; - ap.intro("filter_test\n" OIIO_INTRO_STRING) - .usage("filter_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - // ap.arg("--threads %d", &numthreads) - // .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--normalize", &normalize) - .help("Normalize/rescale all filters to peak at 1"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -void -test_1d() -{ - print("Testing 1D filters\n"); - - Benchmarker bench; - bench.iterations(iterations); - bench.trials(ntrials); - // bench.units (Benchmarker::Unit::ms); - - ImageBuf graph(ImageSpec(graphxres, graphyres, 3, TypeDesc::UINT8)); - float white[3] = { 1, 1, 1 }; - float black[3] = { 0, 0, 0 }; - ImageBufAlgo::fill(graph, white); - ImageBufAlgo::render_line(graph, 0, graphyzero, graphxres - 1, graphyzero, - black); - ImageBufAlgo::render_line(graph, graphxzero, 0, graphxzero, graphyres - 1, - black); - int lastx = 0, lasty = 0; - for (int i = 0, e = Filter1D::num_filters(); i < e; ++i) { - FilterDesc filtdesc; - Filter1D::get_filterdesc(i, &filtdesc); - Filter1D* f = Filter1D::create(filtdesc.name, filtdesc.width); - // Graph it - float scale = normalize ? 1.0f / (*f)(0.0f) : 1.0f; - float color[3] = { 0.25f * (i & 3), 0.25f * ((i >> 2) & 3), - 0.25f * ((i >> 4) & 3) }; - std::string filtname = filtdesc.name; - if (filtdesc.name != f->name()) - filtname = Strutil::fmt::format("{} ({})", filtname, f->name()); - ImageBufAlgo::render_text(graph, 10, 20 + i * 20, filtname, 16, - "" /*font name*/, color); - for (int x = 0; x < graphxres; ++x) { - float xx = float(x - graphxzero) / graphunit; - float yy = (*f)(xx)*scale; - int y = int(graphyzero - yy * graphunit); - if (x > 0) - ImageBufAlgo::render_line(graph, lastx, lasty, x, y, color); - lastx = x; - lasty = y; - } - - // Time it - bench(filtdesc.name, [=]() { DoNotOptimize((*f)(0.25f)); }); - - Filter1D::destroy(f); - } - - graph.write("filters.tif"); -} - - - -void -test_2d() -{ - print("\nTesting 2D filters\n"); - - Benchmarker bench; - bench.iterations(iterations); - bench.trials(ntrials); - // bench.units (Benchmarker::Unit::ms); - - ImageBuf graph(ImageSpec(graphxres, graphyres, 3, TypeDesc::UINT8)); - float white[3] = { 1, 1, 1 }; - float black[3] = { 0, 0, 0 }; - ImageBufAlgo::fill(graph, white); - ImageBufAlgo::render_line(graph, 0, graphyzero, graphxres - 1, graphyzero, - black); - ImageBufAlgo::render_line(graph, graphxzero, 0, graphxzero, graphyres - 1, - black); - int lastx = 0, lasty = 0; - for (int i = 0, e = Filter2D::num_filters(); i < e; ++i) { - FilterDesc filtdesc; - Filter2D::get_filterdesc(i, &filtdesc); - Filter2D* f = Filter2D::create(filtdesc.name, filtdesc.width, - filtdesc.width); - // Graph it - float scale = normalize ? 1.0f / (*f)(0.0f, 0.0f) : 1.0f; - float color[3] = { 0.25f * (i & 3), 0.25f * ((i >> 2) & 3), - 0.25f * ((i >> 4) & 3) }; - std::string filtname = filtdesc.name; - if (filtdesc.name != f->name()) - filtname = Strutil::fmt::format("{} ({})", filtname, f->name()); - ImageBufAlgo::render_text(graph, 10, 20 + i * 20, filtname, 16, - "" /*font name*/, color); - for (int x = 0; x < graphxres; ++x) { - float xx = float(x - graphxzero) / graphunit; - float yy = (*f)(xx, 0.0f) * scale; - int y = int(graphyzero - yy * graphunit); - if (x > 0) - ImageBufAlgo::render_line(graph, lastx, lasty, x, y, color); - lastx = x; - lasty = y; - } - - // Time it - bench(filtdesc.name, [=]() { DoNotOptimize((*f)(0.25f, 0.25f)); }); - - Filter2D::destroy(f); - } - - graph.write("filters2d.tif"); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - test_1d(); - test_2d(); -} diff --git a/Sources/OpenImageIO/libutil/fmath_test.cpp b/Sources/OpenImageIO/libutil/fmath_test.cpp deleted file mode 100644 index 84d70173..00000000 --- a/Sources/OpenImageIO/libutil/fmath_test.cpp +++ /dev/null @@ -1,776 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: BSD-3-Clause and Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace OIIO; - -// Aid for things that are too short to benchmark accurately -#define REP10(x) x, x, x, x, x, x, x, x, x, x - -static int iterations = 1000000; -static int ntrials = 5; -static bool verbose = false; - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("fmath_test\n" OIIO_INTRO_STRING) - .usage("fmath_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -void -test_int_helpers() -{ - std::cout << "\ntest_int_helpers\n"; - - // ispow2 - for (int i = 1; i < (1 << 30); i *= 2) { - OIIO_CHECK_ASSERT(ispow2(i)); - if (i > 1) - OIIO_CHECK_ASSERT(!ispow2(i + 1)); - } - OIIO_CHECK_ASSERT(ispow2(int(0))); - OIIO_CHECK_ASSERT(!ispow2(-1)); - OIIO_CHECK_ASSERT(!ispow2(-2)); - - // ispow2, try size_t, which is unsigned - for (size_t i = 1; i < (1 << 30); i *= 2) { - OIIO_CHECK_ASSERT(ispow2(i)); - if (i > 1) - OIIO_CHECK_ASSERT(!ispow2(i + 1)); - } - OIIO_CHECK_ASSERT(ispow2((unsigned int)0)); - - // ceil2 - OIIO_CHECK_EQUAL(ceil2(4), 4); - OIIO_CHECK_EQUAL(ceil2(5), 8); - OIIO_CHECK_EQUAL(ceil2(6), 8); - OIIO_CHECK_EQUAL(ceil2(7), 8); - OIIO_CHECK_EQUAL(ceil2(8), 8); - - // floor2 - OIIO_CHECK_EQUAL(floor2(4), 4); - OIIO_CHECK_EQUAL(floor2(5), 4); - OIIO_CHECK_EQUAL(floor2(6), 4); - OIIO_CHECK_EQUAL(floor2(7), 4); - OIIO_CHECK_EQUAL(floor2(8), 8); - - // round_to_multiple - OIIO_CHECK_EQUAL(round_to_multiple(0, 5), 0); - OIIO_CHECK_EQUAL(round_to_multiple(1, 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(2, 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(3, 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(4, 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(5, 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(6, 5), 10); - OIIO_CHECK_EQUAL(round_to_multiple(-1, 5), 0); - OIIO_CHECK_EQUAL(round_to_multiple(-4, 5), 0); - OIIO_CHECK_EQUAL(round_to_multiple(-5, 5), -5); - OIIO_CHECK_EQUAL(round_to_multiple(-6, 5), -5); - OIIO_CHECK_EQUAL(round_to_multiple(-9, 5), -5); - OIIO_CHECK_EQUAL(round_to_multiple(-10, 5), -10); - OIIO_CHECK_EQUAL(round_to_multiple(-11, 5), -10); - OIIO_CHECK_EQUAL(round_to_multiple(size_t(5), 5), 5); - OIIO_CHECK_EQUAL(round_to_multiple(size_t(6), 5), 10); - - // round_down_to_multiple - OIIO_CHECK_EQUAL(round_down_to_multiple(0, 5), 0); - OIIO_CHECK_EQUAL(round_down_to_multiple(1, 5), 0); - OIIO_CHECK_EQUAL(round_down_to_multiple(5, 5), 5); - OIIO_CHECK_EQUAL(round_down_to_multiple(6, 5), 5); - OIIO_CHECK_EQUAL(round_down_to_multiple(10, 5), 10); - OIIO_CHECK_EQUAL(round_down_to_multiple(11, 5), 10); - OIIO_CHECK_EQUAL(round_down_to_multiple(-1, 5), -5); - OIIO_CHECK_EQUAL(round_down_to_multiple(-4, 5), -5); - OIIO_CHECK_EQUAL(round_down_to_multiple(-5, 5), -5); - OIIO_CHECK_EQUAL(round_down_to_multiple(-6, 5), -10); - OIIO_CHECK_EQUAL(round_down_to_multiple(-9, 5), -10); - OIIO_CHECK_EQUAL(round_down_to_multiple(-10, 5), -10); - OIIO_CHECK_EQUAL(round_down_to_multiple(-11, 5), -15); - OIIO_CHECK_EQUAL(round_down_to_multiple(size_t(5), 5), 5); - OIIO_CHECK_EQUAL(round_down_to_multiple(size_t(6), 5), 5); - OIIO_CHECK_EQUAL(round_down_to_multiple(size_t(10), 5), 10); - OIIO_CHECK_EQUAL(round_down_to_multiple(size_t(11), 5), 10); - - // round_to_multiple_of_pow2 - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(int(1), 4), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(int(2), 4), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(int(3), 4), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(int(4), 4), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(int(5), 4), 8); - - // round_to_multiple_of_pow2 - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(size_t(1), size_t(4)), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(size_t(2), size_t(4)), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(size_t(3), size_t(4)), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(size_t(4), size_t(4)), 4); - OIIO_CHECK_EQUAL(round_to_multiple_of_pow2(size_t(5), size_t(4)), 8); - - OIIO_CHECK_EQUAL(rotl(uint32_t(0x12345678), 4), uint32_t(0x23456781)); - OIIO_CHECK_EQUAL(rotl(uint64_t(0x123456789abcdef0ULL), 4), - uint64_t(0x23456789abcdef01ULL)); -} - - - -void -test_math_functions() -{ - std::cout << "Testing math functions\n"; - Benchmarker bench; - - OIIO_CHECK_EQUAL(ifloor(0.0f), 0); - OIIO_CHECK_EQUAL(ifloor(-0.999f), -1); - OIIO_CHECK_EQUAL(ifloor(-1.0f), -1); - OIIO_CHECK_EQUAL(ifloor(-1.001f), -2); - OIIO_CHECK_EQUAL(ifloor(0.999f), 0); - OIIO_CHECK_EQUAL(ifloor(1.0f), 1); - OIIO_CHECK_EQUAL(ifloor(1.001f), 1); - float fval = 1.1f; - clobber(fval); - bench("ifloor", [&]() { return DoNotOptimize(ifloor(fval)); }); - fval = -1.1f; - clobber(fval); - bench("ifloor (neg)", [&]() { return DoNotOptimize(ifloor(fval)); }); - - int ival; - OIIO_CHECK_EQUAL_APPROX(floorfrac(0.0f, &ival), 0.0f); - OIIO_CHECK_EQUAL(ival, 0); - OIIO_CHECK_EQUAL_APPROX(floorfrac(-0.999f, &ival), 0.001f); - OIIO_CHECK_EQUAL(ival, -1); - OIIO_CHECK_EQUAL_APPROX(floorfrac(-1.0f, &ival), 0.0f); - OIIO_CHECK_EQUAL(ival, -1); - OIIO_CHECK_EQUAL_APPROX(floorfrac(-1.001f, &ival), 0.999f); - OIIO_CHECK_EQUAL(ival, -2); - OIIO_CHECK_EQUAL_APPROX(floorfrac(0.999f, &ival), 0.999f); - OIIO_CHECK_EQUAL(ival, 0); - OIIO_CHECK_EQUAL_APPROX(floorfrac(1.0f, &ival), 0.0f); - OIIO_CHECK_EQUAL(ival, 1); - OIIO_CHECK_EQUAL_APPROX(floorfrac(1.001f, &ival), 0.001f); - OIIO_CHECK_EQUAL(ival, 1); - bench( - "floorfrac", - [&](float x) { return DoNotOptimize(floorfrac(x, &ival)); }, fval); - - OIIO_CHECK_EQUAL(sign(3.1f), 1.0f); - OIIO_CHECK_EQUAL(sign(-3.1f), -1.0f); - OIIO_CHECK_EQUAL(sign(0.0f), 0.0f); - - { - OIIO_CHECK_EQUAL(fast_neg(1.5f), -1.5f); - OIIO_CHECK_EQUAL(fast_neg(-1.5f), 1.5f); - OIIO_CHECK_EQUAL(fast_neg(0.0f), 0.0f); - OIIO_CHECK_EQUAL(fast_neg(-0.0f), 0.0f); - float x = -3.5f; - clobber(x); - bench("-float x10", [&]() { return REP10(DoNotOptimize(-x)); }); - bench("fast_neg(float) x10", - [&]() { return REP10(DoNotOptimize(fast_neg(x))); }); - } - - { - float a = 2.5f, b = 1.5f, c = 8.5f; - clobber(a); - clobber(b); - clobber(c); - bench("madd fake a*b+c", [&]() { return DoNotOptimize(a * b + c); }); - bench("madd(a,b,c)", - [&]() { return DoNotOptimize(OIIO::madd(a, b, c)); }); - bench("std::fma(a,b,c)", - [&]() { return DoNotOptimize(std::fma(a, b, c)); }); - } - { - float a = 2.5f, b = 1.5f, c = 8.5f; - OIIO_CHECK_EQUAL(clamp(2.5f, 1.5f, 8.5f), 2.5f); - OIIO_CHECK_EQUAL(clamp(1.5f, 2.5f, 8.5f), 2.5f); - OIIO_CHECK_EQUAL(clamp(8.5f, 1.5f, 2.5f), 2.5f); - clobber(a); - clobber(b); - clobber(c); - bench("clamp(f,f,f) middle", - [&]() { return DoNotOptimize(clamp(a, b, c)); }); - bench("clamp(f,f,f) low", - [&]() { return DoNotOptimize(clamp(b, a, c)); }); - bench("clamp(f,f,f) high", - [&]() { return DoNotOptimize(clamp(c, b, a)); }); - } - - { - float x = 1.3f, y = 2.5f; - clobber(x, y); - bench("std::cos", [&]() { return DoNotOptimize(std::cos(x)); }); - bench("fast_cos", [&]() { return DoNotOptimize(fast_cos(x)); }); - bench("fast_cospi", [&]() { return DoNotOptimize(fast_cospi(x)); }); - bench("std::sin", [&]() { return DoNotOptimize(std::sin(x)); }); - bench("fast_sin", [&]() { return DoNotOptimize(fast_sin(x)); }); - bench("fast_sinpi", [&]() { return DoNotOptimize(fast_sinpi(x)); }); - bench("std::tan", [&]() { return DoNotOptimize(std::tan(x)); }); - bench("fast_tan", [&]() { return DoNotOptimize(fast_tan(x)); }); - bench("std::acos", [&]() { return DoNotOptimize(std::acos(x)); }); - bench("fast_acos", [&]() { return DoNotOptimize(fast_acos(x)); }); - bench("std::asin", [&]() { return DoNotOptimize(std::asin(x)); }); - bench("fast_asin", [&]() { return DoNotOptimize(fast_asin(x)); }); - bench("std::atan2", [&]() { return DoNotOptimize(std::atan2(y, x)); }); - bench("fast_atan2", [&]() { return DoNotOptimize(fast_atan2(y, x)); }); - - bench("std::log2", [&]() { return DoNotOptimize(std::log2(x)); }); - bench("fast_log2", [&]() { return DoNotOptimize(fast_log2(x)); }); - bench("std::log", [&]() { return DoNotOptimize(std::log(x)); }); - bench("fast_log", [&]() { return DoNotOptimize(fast_log(x)); }); - bench("std::log10", [&]() { return DoNotOptimize(std::log10(x)); }); - bench("fast_log10", [&]() { return DoNotOptimize(fast_log10(x)); }); - bench("std::exp", [&]() { return DoNotOptimize(std::exp(x)); }); - bench("fast_exp", [&]() { return DoNotOptimize(fast_exp(x)); }); - bench("fast_correct_exp", - [&]() { return DoNotOptimize(fast_correct_exp(x)); }); - bench("std::exp2", [&]() { return DoNotOptimize(std::exp2(x)); }); - bench("fast_exp2", [&]() { return DoNotOptimize(fast_exp2(x)); }); - - OIIO_CHECK_EQUAL(safe_fmod(5.0f, 2.5f), 0.0f); - OIIO_CHECK_EQUAL(safe_fmod(-5.0f, 2.5f), 0.0f); - OIIO_CHECK_EQUAL(safe_fmod(-5.0f, -2.5f), 0.0f); - OIIO_CHECK_EQUAL(safe_fmod(5.5f, 2.5f), 0.5f); - OIIO_CHECK_EQUAL(safe_fmod(-5.5f, 2.5f), -0.5f); - OIIO_CHECK_EQUAL(safe_fmod(-5.5f, -2.5f), -0.5f); - OIIO_CHECK_EQUAL(safe_fmod(5.5f, 0.0f), 0.0f); - bench("std::fmod", [&]() { return DoNotOptimize(std::fmod(y, x)); }); - bench("safe_fmod", [&]() { return DoNotOptimize(safe_fmod(y, x)); }); - } - - { - OIIO_CHECK_EQUAL(fast_rint(0.0f), 0); - OIIO_CHECK_EQUAL(fast_rint(-1.0f), -1); - OIIO_CHECK_EQUAL(fast_rint(-1.2f), -1); - OIIO_CHECK_EQUAL(fast_rint(-0.8f), -1); - OIIO_CHECK_EQUAL(fast_rint(-1.49f), -1); - OIIO_CHECK_EQUAL(fast_rint(-1.50f), -2); - OIIO_CHECK_EQUAL(fast_rint(-1.51f), -2); - OIIO_CHECK_EQUAL(fast_rint(1.0f), 1); - OIIO_CHECK_EQUAL(fast_rint(1.2f), 1); - OIIO_CHECK_EQUAL(fast_rint(0.8f), 1); - OIIO_CHECK_EQUAL(fast_rint(1.49f), 1); - OIIO_CHECK_EQUAL(fast_rint(1.50f), 2); - OIIO_CHECK_EQUAL(fast_rint(1.51f), 2); - float a = 1.5f; - clobber(a); - bench("fast_rint", [&]() { return DoNotOptimize(fast_rint(a)); }); - bench("std::lrint", [&]() { return DoNotOptimize(std::lrint(a)); }); - bench("int(std::rint)", - [&]() { return DoNotOptimize(static_cast(std::rint(a))); }); - bench("int(x+copysignf(0.5f,x))", [&]() { - return DoNotOptimize(static_cast(a + copysignf(0.5f, a))); - }); - } -} - - - -// Convert T to F to T, make sure value are preserved round trip -template -void -test_convert_type(double tolerance = 1e-6) -{ - if (std::numeric_limits::is_integer) { - for (long long i = std::numeric_limits::min(); - i <= std::numeric_limits::max(); ++i) { - T in = (T)i; - F f = convert_type(in); - T out = convert_type(f); - if (out != in) { - std::cout << " convert " << (long long)in << " -> " << f - << " -> " << (long long)out << "\n"; - ++unit_test_failures; - } - } - } else { - for (float i = 0.0f; i <= 1.0f; i += 0.001) { // NOLINT //NOSONAR - T in = (T)i; - F f = convert_type(in); - T out = convert_type(f); - if (fabs(double(out - in)) > tolerance) { - std::cout << " convert " << in << " -> " << f << " -> " << out - << " (diff = " << (out - in) << ")\n"; - ++unit_test_failures; - } - } - } -} - - - -template -void -do_convert_type(const std::vector& svec, std::vector& dvec) -{ - convert_type(&svec[0], &dvec[0], svec.size()); - DoNotOptimize(dvec[0]); // Be sure nothing is optimized away -} - - -template -void -benchmark_convert_type() -{ - const size_t repeats = 10; - const size_t size = iterations; - const S testval(1.0); - std::vector svec(size, testval); - std::vector dvec(size); - Strutil::print("Benchmark conversion of {:6} -> {:6} : ", - TypeDesc(BaseTypeFromC::value).c_str(), - TypeDesc(BaseTypeFromC::value).c_str()); - float time = time_trial(bind(do_convert_type, std::cref(svec), - std::ref(dvec)), - ntrials, repeats) - / repeats; - Strutil::print("{:7.1f} Mvals/sec\n", (size / 1.0e6) / time); - D r = convert_type(testval); - OIIO_CHECK_EQUAL(dvec[size - 1], r); -} - - - -void -test_bit_range_convert() -{ - OIIO_CHECK_EQUAL((bit_range_convert<10, 16>(1023)), 65535); - OIIO_CHECK_EQUAL((bit_range_convert<2, 8>(3)), 255); - OIIO_CHECK_EQUAL((bit_range_convert<8, 8>(255)), 255); - OIIO_CHECK_EQUAL((bit_range_convert<16, 10>(65535)), 1023); - OIIO_CHECK_EQUAL((bit_range_convert<2, 20>(3)), 1048575); - OIIO_CHECK_EQUAL((bit_range_convert<20, 2>(1048575)), 3); - OIIO_CHECK_EQUAL((bit_range_convert<20, 21>(1048575)), 2097151); - OIIO_CHECK_EQUAL((bit_range_convert<32, 32>(4294967295U)), 4294967295U); - OIIO_CHECK_EQUAL((bit_range_convert<32, 16>(4294967295U)), 65535); - // These are not expected to work, since bit_range_convert only takes a - // regular 'unsigned int' as parameter. If we need >32 bit conversion, - // we need to add a uint64_t version of bit_range_convert. - // OIIO_CHECK_EQUAL ((bit_range_convert<33,16>(8589934591)), 65535); - // OIIO_CHECK_EQUAL ((bit_range_convert<33,33>(8589934591)), 8589934591); - // OIIO_CHECK_EQUAL ((bit_range_convert<64,32>(18446744073709551615)), 4294967295); -} - - - -void -test_packbits() -{ - std::cout << "test_convert_pack_bits\n"; - - { - unsigned char foo[3] = { 0, 0, 0 }; - unsigned char* fp = foo; - int fpf = 0; - bitstring_add_n_bits(fp, fpf, 1, 4); - bitstring_add_n_bits(fp, fpf, 2, 8); - bitstring_add_n_bits(fp, fpf, 0xffff, 10); - // result should be 0x10 0x2f 0xfc - Strutil::printf(" bitstring_add_n_bits results %02x %02x %02x\n", - foo[0], foo[1], foo[2]); - OIIO_CHECK_EQUAL(foo[0], 0x10); - OIIO_CHECK_EQUAL(foo[1], 0x2f); - OIIO_CHECK_EQUAL(foo[2], 0xfc); - } - { - unsigned char foo[4] = { 0, 0, 0, 0 }; - unsigned char* fp = foo; - int fpf = 0; - bitstring_add_n_bits(fp, fpf, 1023, 10); - bitstring_add_n_bits(fp, fpf, 0, 10); - bitstring_add_n_bits(fp, fpf, 1023, 10); - // result should be 1111111111 0000000000 1111111111 00 - // f f c 0 0 f f c - Strutil::printf(" bitstring_add_n_bits results %02x %02x %02x %02x\n", - foo[0], foo[1], foo[2], foo[3]); - OIIO_CHECK_EQUAL(foo[0], 0xff); - OIIO_CHECK_EQUAL(foo[1], 0xc0); - OIIO_CHECK_EQUAL(foo[2], 0x0f); - OIIO_CHECK_EQUAL(foo[3], 0xfc); - } - - const uint16_t u16vals[8] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - uint16_t u10[5] = { 255, 255, 255, 255, 255 }; - Strutil::printf( - " in 16 bit values: %04x %04x %04x %04x %04x %04x %04x %04x\n", - u16vals[0], u16vals[1], u16vals[2], u16vals[3], u16vals[4], u16vals[5], - u16vals[6], u16vals[7]); - bit_pack(cspan(u16vals, 8), u10, 10); - Strutil::printf( - " packed to 10 bits, as 16 bit values: %04x %04x %04x %04x %04x\n", - u10[0], u10[1], u10[2], u10[3], u10[4]); - uint16_t u16[8]; - bit_unpack(8, (const unsigned char*)u10, 10, u16); - Strutil::printf( - " unpacked back to 16 bits: %04x %04x %04x %04x %04x %04x %04x %04x\n", - u16[0], u16[1], u16[2], u16[3], u16[4], u16[5], u16[6], u16[7]); - // Before: 00000000 00000001 00000000 00000001 00000000 00000001... - // After: 00000000 01000000 00010000 00000100 00000001 00000000 01000000 00010000 00000100 00000001 - // = 00 40 10 04 01 00 40 10 04 01 - // as little endian 16 bit: 4000 0410 0001 1040 0104 - for (size_t i = 0; i < 8; ++i) - OIIO_CHECK_EQUAL(u16vals[i], u16[i]); -} - - - -static void -test_interpolate_linear() -{ - std::cout << "\nTesting interpolate_linear\n"; - - // Test simple case of 2 knots - float knots2[] = { 1.0f, 2.0f }; - OIIO_CHECK_EQUAL(interpolate_linear(0.0f, knots2), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(0.25f, knots2), 1.25f); - OIIO_CHECK_EQUAL(interpolate_linear(0.0f, knots2), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.0f, knots2), 2.0f); - OIIO_CHECK_EQUAL(interpolate_linear(-0.1f, knots2), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.1f, knots2), 2.0f); - float inf = std::numeric_limits::infinity(); - float nan = std::numeric_limits::quiet_NaN(); - OIIO_CHECK_EQUAL(interpolate_linear(-inf, knots2), 1.0f); // Test -inf - OIIO_CHECK_EQUAL(interpolate_linear(inf, knots2), 2.0f); // Test inf - OIIO_CHECK_EQUAL(interpolate_linear(nan, knots2), 1.0f); // Test nan - - // More complex case of many knots - float knots4[] = { 1.0f, 2.0f, 4.0f, 6.0f }; - OIIO_CHECK_EQUAL(interpolate_linear(-0.1f, knots4), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(0.0f, knots4), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.0f / 3.0f, knots4), 2.0f); - OIIO_CHECK_EQUAL(interpolate_linear(0.5f, knots4), 3.0f); - OIIO_CHECK_EQUAL(interpolate_linear(5.0f / 6.0f, knots4), 5.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.0f, knots4), 6.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.1f, knots4), 6.0f); - - // Make sure it all works for strided arrays, too - float knots4_strided[] = { 1.0f, 0.0f, 2.0f, 0.0f, 4.0f, 0.0f, 6.0f, 0.0f }; - span_strided a(knots4_strided, 4, 2); - OIIO_CHECK_EQUAL(interpolate_linear(-0.1f, a), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(0.0f, a), 1.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.0f / 3.0f, a), 2.0f); - OIIO_CHECK_EQUAL(interpolate_linear(0.5f, a), 3.0f); - OIIO_CHECK_EQUAL(interpolate_linear(5.0f / 6.0f, a), 5.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.0f, a), 6.0f); - OIIO_CHECK_EQUAL(interpolate_linear(1.1f, a), 6.0f); -} - - - -inline std::string -bin16(int i) -{ - std::string out; - for (int b = 15; b >= 0; --b) { - out += (1 << b) & i ? '1' : '0'; - if (b == 15 || b == 10) - out += '\''; - } - return out; -} - - - -void -test_half_convert_accuracy() -{ - // Enumerate every half value - const int nhalfs = 1 << 16; - std::vector H(nhalfs, 0.0f); - for (auto i = 0; i < nhalfs; ++i) - H[i] = bitcast((uint16_t)i); - - // Convert the whole array to float equivalents in one shot (which will - // use SIMD ops if available). - std::vector F(nhalfs); - convert_type(H.data(), F.data(), nhalfs); - // And convert back in a batch as well (using SIMD if available) - std::vector H2(nhalfs); - convert_type(F.data(), H2.data(), nhalfs); - - // Compare the round trip as well as all the values to the result we get - // if we convert individually, which will use the table-based method - // from Imath. They should match! - int nwrong = 0; - for (auto i = 0; i < nhalfs; ++i) { - float f = H[i]; // single assignment uses table from Imath - half h = (half)f; - if ((f != F[i] || f != H2[i] || f != h || H[i] != H2[i] - || bitcast(h) != bitcast(H[i]) - || bitcast(h) != i) - && Imath::finitef(H[i])) { - ++nwrong; - Strutil::print("wrong {} 0b{} h={}, f={} {}\n", i, bin16(i), H[i], - F[i], isnan(f) ? "(nan)" : ""); - } - } - - Sysutil::Term term(std::cout); - if (nwrong) - std::cout << term.ansi("red"); - std::cout << "test_half_convert_accuracy: " << nwrong << " mismatches\n"; - std::cout << term.ansi("default"); - OIIO_CHECK_ASSERT(nwrong == 0); -} - - - -static void -test_bitcast() -{ - OIIO_CHECK_EQUAL((bitcast(half(0.0f))), 0); - OIIO_CHECK_EQUAL((bitcast(0.0f)), 0); - OIIO_CHECK_EQUAL((bitcast(0.0f)), 0); - OIIO_CHECK_EQUAL((bitcast(0)), 0.0f); - OIIO_CHECK_EQUAL((bitcast(0)), 0.0f); - OIIO_CHECK_EQUAL((bitcast(0.0)), 0); - OIIO_CHECK_EQUAL((bitcast(0.0)), 0); - OIIO_CHECK_EQUAL((bitcast(0)), 0.0); - OIIO_CHECK_EQUAL((bitcast(0)), 0.0); -} - - - -template -static void -test_swap_endian(T val, T swapval) -{ - std::string type = TypeDescFromC::value().c_str(); - static const int len = 100; - Benchmarker bench; - std::array v; - std::fill(v.begin(), v.end(), val); - swap_endian(&(v[0])); - OIIO_CHECK_EQUAL(v[0], swapval); - swap_endian(&(v[0]), len); - OIIO_CHECK_EQUAL(v[37], swapval); - clobber(v[0]); - bench(Strutil::fmt::format("swap_endian({})", type), - [&]() { swap_endian(&v[0]); }); - bench.work(len); - bench(Strutil::fmt::format("swap_endian({}, {})", type, len), - [&]() { swap_endian(v.data(), len); }); -} - - -static void -test_swap_endian() -{ - test_swap_endian(0x1234, 0x3412); - test_swap_endian(0x1234, 0x3412); - test_swap_endian(0x12345678, 0x78563412); - test_swap_endian(0x12345678, 0x78563412); - test_swap_endian(0x123456789abcdef0LL, 0xf0debc9a78563412LL); - test_swap_endian(0x123456789abcdef0ULL, - 0xf0debc9a78563412ULL); -} - - - -// Minimal vector class having x, y, z struct members. -struct XYZVector { - float x, y, z; - XYZVector() {} - XYZVector(float x, float y, float z) - : x(x) - , y(y) - , z(z) - { - } -}; - -// Minimal vector class enclosing an array[3]. -struct Arr3Vector { - float xyz[3]; - Arr3Vector() {} - Arr3Vector(float x, float y, float z) - { - xyz[0] = x; - xyz[1] = y; - xyz[2] = z; - } - float operator[](int i) const { return xyz[i]; } -}; - - - -// Function that takes a V3fParam, and must implicitly convert it to an -// Imath::V3f. -Imath::V3f -v3ffunc(V3fParam p) -{ - return p; -} - - -// Function that takes a M33Param, and must implicitly convert it to an -// Imath::M33f. -Imath::M33f -M33func(M33fParam p) -{ - return p; -} - - -// Function that takes a M44Param, and must implicitly convert it to an -// Imath::M44f. -Imath::M44f -m44func(M44fParam p) -{ - return p; -} - - -static void -test_vecparam() -{ - Strutil::print("Testing vec proxy passing\n"); - - // Can we pass an Imath::V3f as a V3fParam? - Imath::V3f iv3f(1.0f, 2.0f, 3.0f); - OIIO_CHECK_EQUAL(v3ffunc(iv3f), iv3f); - - // Can we pass a raw float[3] array as a V3fParam? - float arr[3] = { 1.0, 2.0, 3.0 }; - OIIO_CHECK_EQUAL(v3ffunc(arr), iv3f); - - // Can we pass a std::array as a V3fParam? - std::array stdarr { 1.0, 2.0, 3.0 }; - OIIO_CHECK_EQUAL(v3ffunc(stdarr), iv3f); - - // Can we pass an initializer list as a V3fParam? - OIIO_CHECK_EQUAL(v3ffunc({ 1.0f, 2.0f, 3.0f }), iv3f); - - // Can we pass a custom vector class with xyz components as a V3fParam? - XYZVector xyzv(1.0f, 2.0f, 3.0f); - OIIO_CHECK_EQUAL(v3ffunc(xyzv), iv3f); - - // Can we pass a custom vector class with array components as a V3fParam? - Arr3Vector av(1.0f, 2.0f, 3.0f); - OIIO_CHECK_EQUAL(v3ffunc(av), iv3f); - - // Can we pass our simd::vfloat3 as a V3fParam? - simd::vfloat3 vf3(1.0f, 2.0f, 3.0f); - OIIO_CHECK_EQUAL(v3ffunc(vf3), iv3f); - - OIIO_CHECK_ASSERT((has_xyz::value)); - OIIO_CHECK_ASSERT((has_subscript_N::value)); - OIIO_CHECK_ASSERT((has_subscript_N::value)); - - Imath::M44f m44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - OIIO_CHECK_EQUAL(m44func(m44f), m44f); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - -#if OIIO_SIMD_SSE && !OIIO_F16C_ENABLED - // Some rogue libraries (and icc runtime libs?) will turn on the cpu mode - // that causes floating point denormals get crushed to 0.0 in certain ops, - // and leave it that way! This can give us the wrong results for the - // particular sequence of SSE intrinsics we use to convert half->float for - // exr files containing pixels with denorm values. - simd::set_denorms_zero_mode(false); -#endif - - getargs(argc, argv); - - test_int_helpers(); - - test_math_functions(); - - std::cout << "\nround trip convert char/float/char\n"; - test_convert_type(); - std::cout << "round trip convert unsigned char/float/unsigned char\n"; - test_convert_type(); - std::cout - << "round trip convert unsigned char/unsigned short/unsigned char\n"; - test_convert_type(); - std::cout << "round trip convert short/float/short\n"; - test_convert_type(); - std::cout << "round trip convert unsigned short/float/unsigned short\n"; - test_convert_type(); - std::cout << "round trip convert float/int/float \n"; - test_convert_type(); - std::cout << "round trip convert double/float/double\n"; - test_convert_type(); - std::cout << "round trip convert double/long/double\n"; - test_convert_type(); - std::cout << "round trip convert float/unsigned int/float\n"; - test_convert_type(); - - test_half_convert_accuracy(); - - benchmark_convert_type(); - benchmark_convert_type(); - benchmark_convert_type(); - benchmark_convert_type(); - benchmark_convert_type(); - benchmark_convert_type(); - benchmark_convert_type(); - // conversion to a type smaller in bytes causes error - // std::cout << "round trip convert float/short/float\n"; - // test_convert_type (); - // std::cout << "round trip convert unsigned float/char/float\n"; - // test_convert_type (); - // std::cout << "round trip convert unsigned float/unsigned char/float\n"; - // test_convert_type (); - // std::cout << "round trip convert unsigned short/unsigned char/unsigned short\n"; - // test_convert_type (); - // std::cout << "round trip convert float/unsigned short/float\n"; - // test_convert_type (); - - test_bit_range_convert(); - test_packbits(); - test_bitcast(); - test_swap_endian(); - - test_interpolate_linear(); - - test_vecparam(); - - return unit_test_failures != 0; -} diff --git a/Sources/OpenImageIO/libutil/hash_test.cpp b/Sources/OpenImageIO/libutil/hash_test.cpp deleted file mode 100644 index 6d379981..00000000 --- a/Sources/OpenImageIO/libutil/hash_test.cpp +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - - - -using namespace OIIO; -using OIIO::Strutil::print; - -static int iterations = 100 << 20; -static int ntrials = 1; -static bool verbose = false; - -static std::vector data; - -uint64_t -test_bjhash(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += bjhash::hashlittle(ptr, len); - return a; -} - -uint64_t -test_xxhash(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += xxhash::xxhash(ptr, len, 0); - return a; -} - -uint64_t -test_farmhash(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += farmhash::Hash(ptr, len); - return a; -} - -uint64_t -test_farmhash_inlined(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += farmhash::inlined::Hash(ptr, len); - return a; -} - -uint64_t -test_fasthash64(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += fasthash::fasthash64(ptr, len, 0); - return a; -} - -#ifdef __AES__ - -// https://github.com/gamozolabs/falkhash - -// Licensed with the unlicense ( http://choosealicense.com/licenses/unlicense/ ) - -inline uint64_t -falkhash(const void* pbuf, uint64_t len, uint64_t pseed = 0) -{ - uint8_t* buf = (uint8_t*)pbuf; - - uint64_t iv[2]; - - __m128i hash, seed; - - /* Create the 128-bit seed. Low 64-bits gets seed, high 64-bits gets - * seed + len + 1. The +1 ensures that both 64-bits values will never be - * the same (with the exception of a length of -1. If you have that much - * ram, send me some). - */ - iv[0] = pseed; - iv[1] = pseed + len + 1; - - /* Load the IV into a __m128i */ - seed = _mm_loadu_si128((__m128i*)iv); - - /* Hash starts out with the seed */ - hash = seed; - - while (len) { - uint8_t tmp[0x50]; - - __m128i piece[5]; - - /* If the data is smaller than one chunk, pad it with zeros */ - if (len < 0x50) { - memset(tmp, 0, 0x50); - for (int i = 0; i < int(len); i++) - tmp[i] = buf[i]; - buf = tmp; - len = 0x50; - } - - /* Load up the data into __m128is */ - piece[0] = _mm_loadu_si128((__m128i*)(buf + 0 * 0x10)); - piece[1] = _mm_loadu_si128((__m128i*)(buf + 1 * 0x10)); - piece[2] = _mm_loadu_si128((__m128i*)(buf + 2 * 0x10)); - piece[3] = _mm_loadu_si128((__m128i*)(buf + 3 * 0x10)); - piece[4] = _mm_loadu_si128((__m128i*)(buf + 4 * 0x10)); - - /* xor each piece against the seed */ - piece[0] = _mm_xor_si128(piece[0], seed); - piece[1] = _mm_xor_si128(piece[1], seed); - piece[2] = _mm_xor_si128(piece[2], seed); - piece[3] = _mm_xor_si128(piece[3], seed); - piece[4] = _mm_xor_si128(piece[4], seed); - - /* aesenc all into piece[0] */ - piece[0] = _mm_aesenc_si128(piece[0], piece[1]); - piece[0] = _mm_aesenc_si128(piece[0], piece[2]); - piece[0] = _mm_aesenc_si128(piece[0], piece[3]); - piece[0] = _mm_aesenc_si128(piece[0], piece[4]); - - /* Finalize piece[0] by aesencing against seed */ - piece[0] = _mm_aesenc_si128(piece[0], seed); - - /* aesenc the piece into the hash */ - hash = _mm_aesenc_si128(hash, piece[0]); - - buf += 0x50; - len -= 0x50; - } - - /* Finalize hash by aesencing against seed four times */ - hash = _mm_aesenc_si128(hash, seed); - hash = _mm_aesenc_si128(hash, seed); - hash = _mm_aesenc_si128(hash, seed); - hash = _mm_aesenc_si128(hash, seed); - - return _mm_cvtsi128_si64(hash); -} - -uint64_t -test_falkhash(int len) -{ - char* ptr = reinterpret_cast(data.data()); - uint64_t a = 0; - for (int i = 0, e = iterations / len; i < e; i++, ptr += len) - a += falkhash(ptr, len, 0); - return a; -} -#endif - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("hash_test\n" OIIO_INTRO_STRING) - .usage("hash_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--iters %d", &iterations) - .help(Strutil::fmt::format("Number of iterations (default: {})", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - // fill data with random values so we can hash it a bunch of different ways - std::mt19937 rng(42); - data.resize(iterations / sizeof(data[0]), 0); - for (uint32_t& d : data) - d = rng(); - - print("All times are seconds per {}\n", Strutil::memformat(iterations)); - - // a sampling of sizes, both tiny and large-ish - int hashlen[] = { - 1, 2, 4, 8, 12, - 16, 20, 24, 32, 64, // small to medium - 3, 5, 6, 7, 13, - 15, 19, 23, 49, 67, // small to medium - odd sizes - 128, 256, 512, 1024, // large (even) - 95, 155, 243, 501, 1337, // large (odd sizes) - iterations // huge - }; - - // present results from smallest to largest - std::sort(std::begin(hashlen), std::end(hashlen)); - - auto candidates = { - std::make_pair("BJ hash ", test_bjhash), - std::make_pair("XX hash ", test_xxhash), - std::make_pair("farmhash ", test_farmhash), - std::make_pair("farmhash::inlined ", test_farmhash_inlined), - std::make_pair("fasthash64 ", test_fasthash64), -#ifdef __AES__ - std::make_pair("falkhash ", test_falkhash), -#endif - }; - - for (int len : hashlen) { - auto mem = Strutil::memformat(len, 2); - print("\nHash benchmark for {} hashes\n", mem); - - double best_time = std::numeric_limits::max(); - const char* best = ""; - for (auto&& c : candidates) { - double range; - double t = time_trial(std::bind(c.second, len), ntrials, 1, &range); - print(" {} took {} (range {})\n", c.first, - Strutil::timeintervalformat(t, 3), - Strutil::timeintervalformat(range, 3)); - if (t < best_time) { - best_time = t; - best = c.first; - } - } - - print("{} winner: {}\n", mem, best); - } - - print("\nTesting correctness\n"); - using hashfn_t = uint64_t(string_view); - auto hashes = { - std::make_pair("BJ hash ", - [](string_view s) -> uint64_t { - return bjhash::strhash(s); - }), - std::make_pair("XX hash ", - [](string_view s) -> uint64_t { - return xxhash::xxhash(s); - }), - std::make_pair("farmhash ", - [](string_view s) -> uint64_t { - return farmhash::Hash(s); - }), - std::make_pair( - "farmhash::inlined ", - [](string_view s) -> uint64_t { - return farmhash::inlined::Hash(s.data(), s.size()); - }), - std::make_pair("fasthash64 ", - [](string_view s) -> uint64_t { - return fasthash::fasthash64( - s.data(), s.size()); - }), -#ifdef __AES__ - std::make_pair("falkhash ", - [](string_view s) -> uint64_t { - return falkhash(s.data(), - s.size()); - }), -#endif - }; - const char* teststrings[] - = { "", // empty string - "P", // one-char string - "openimageio_2008", // identifier-length string - "/shots/abc/seq42/tex/my_texture/my_texture_acscg.0042.tx" }; - uint64_t expected[][4] = { - { - // bjhash - 0x0000000000000000, - 0x00000000b7656eb4, - 0x0000000055af8ab5, - 0x00000000c000c946, - }, - { - // xxhash - 0x03b139605dc5b187, - 0xa4820414c8aff387, - 0x4465cf017b51e76b, - 0x1c9ebf5ebae6e8ad, - }, - { - // farmhash - 0x9ae16a3b2f90404f, - 0x5b5dffc690bdcd30, - 0x0dd8ef814e8a4317, - 0x43ad136c828d5214, - }, - { - // farmhash::inlined - 0x9ae16a3b2f90404f, - 0x5b5dffc690bdcd30, - 0x0dd8ef814e8a4317, - 0x43ad136c828d5214, - }, - { - // fasthash64 - 0x5b38e9e25863460c, - 0x38951d1ac28aad44, - 0x91271089669c4608, - 0xc66714c1deabacf0, - }, - { - // falkhash - 0xaa7f7a3188504dd7, - 0x8bae7d7501558eeb, - 0x0af667ed264008a1, - 0x25f0142ed7151208, - }, - }; - - int stringno = 0; - for (string_view s : teststrings) { - print(" Hash testing '{}'\n", s); - int hashno = 0; - for (auto&& h : hashes) { - auto val = (*h.second)(s); - print(" {} {:016x}\n", h.first, val); - OIIO_CHECK_EQUAL(val, expected[hashno][stringno]); - ++hashno; - } - ++stringno; - } - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/optparser_test.cpp b/Sources/OpenImageIO/libutil/optparser_test.cpp deleted file mode 100644 index 918d8467..00000000 --- a/Sources/OpenImageIO/libutil/optparser_test.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include - -#include -#include -#include - - -using namespace OIIO; - - -class MySystem { -public: - MySystem() - : i(0) - , f(0) - { - } - - bool attribute(const std::string& name, int value) - { - std::cout << "iattribute '" << name << "' = " << value << "\n"; - if (name == "i") { - i = value; - return true; - } - return false; - } - bool attribute(const std::string& name, float value) - { - std::cout << "fattribute '" << name << "' = " << value << "\n"; - if (name == "f") { - f = value; - return true; - } - return false; - } - bool attribute(const std::string& name, const std::string& value) - { - std::cout << "sattribute '" << name << "' = '" << value << "'\n"; - if (name == "s") { - s = value; - return true; - } - return false; - } - - int i; - float f; - std::string s; -}; - - - -void -test_optparser() -{ - MySystem sys; - optparser(sys, "i=14"); - OIIO_CHECK_EQUAL(sys.i, 14); - optparser(sys, "i=-28"); - OIIO_CHECK_EQUAL(sys.i, -28); - - optparser(sys, "f=6.28"); - OIIO_CHECK_EQUAL(sys.f, 6.28f); - optparser(sys, "f=-56.0"); - OIIO_CHECK_EQUAL(sys.f, -56.0f); - optparser(sys, "f=-1."); - OIIO_CHECK_EQUAL(sys.f, -1.0f); - - optparser(sys, "s=foo"); - OIIO_CHECK_EQUAL(sys.s, "foo"); - optparser(sys, "s=\"foo, bar\""); - OIIO_CHECK_EQUAL(sys.s, "foo, bar"); - - optparser(sys, "f=256.29,s=\"phone call\",i=100"); - OIIO_CHECK_EQUAL(sys.i, 100); - OIIO_CHECK_EQUAL(sys.f, 256.29f); - OIIO_CHECK_EQUAL(sys.s, "phone call"); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_optparser(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/parallel_test.cpp b/Sources/OpenImageIO/libutil/parallel_test.cpp deleted file mode 100644 index bf09f18e..00000000 --- a/Sources/OpenImageIO/libutil/parallel_test.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - -static int iterations = 100000; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; -static int threadcounts[] = { 1, 2, 4, 8, 12, 16, 20, - 24, 28, 32, 64, 128, 1024, 1 << 30 }; - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("parallel_test\n" OIIO_INTRO_STRING) - .usage("parallel_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -void -time_parallel_for() -{ - std::cout << "\nTiming how long it takes to run parallel_for:\n"; - std::cout << "threads\ttime (best of " << ntrials << ")\n"; - std::cout << "-------\t----------\n"; - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = wedge ? threadcounts[i] : numthreads; - int its = iterations / nt; - - // make a lambda function that spawns a bunch of threads, calls a - // trivial function, then waits for them to finish and tears down - // the group. - auto func = [=]() { parallel_for(0, nt, [](int64_t) { /*empty*/ }); }; - - double range; - double t = time_trial(func, ntrials, its, &range); - - Strutil::printf("%2d\t%5.1f launch %8.1f threads/sec\n", nt, t, - (nt * its) / t); - if (!wedge) - break; // don't loop if we're not wedging - } -} - - - -void -test_parallel_for() -{ - // vector of ints, initialized to zero - const int length = 1000; - std::vector vals(length, 0); - - // Increment all the integers via parallel_for - parallel_for(0, length, [&](uint64_t i) { vals[i] += 1; }); - - // Verify that all elements are exactly 1 - bool all_one = std::all_of(vals.cbegin(), vals.cend(), - [&](int i) { return vals[i] == 1; }); - OIIO_CHECK_ASSERT(all_one); -} - - - -void -test_parallel_for_2D() -{ - // vector of ints, initialized to zero - const int size = 100; - std::vector vals(size * size, 0); - - // Increment all the integers via parallel_for - parallel_for_2D(0, size, 0, size, - [&](uint64_t i, uint64_t j) { vals[j * size + i] += 1; }); - - // Verify that all elements are exactly 1 - bool all_one = std::all_of(vals.cbegin(), vals.cend(), - [&](int i) { return vals[i] == 1; }); - OIIO_CHECK_ASSERT(all_one); -} - - - -void -test_thread_pool_recursion() -{ - std::cout << "\nTesting thread pool recursion" << std::endl; - static spin_mutex print_mutex; - thread_pool* pool(default_thread_pool()); - pool->resize(2); - parallel_for(0, 10, [&](int64_t /*i*/) { - // sleep long enough that we can push all the jobs before any get - // done. - Sysutil::usleep(10); - // then run something else that itself will push jobs onto the - // thread pool queue. - parallel_for(0, 10, [&](int64_t /*i*/) { - Sysutil::usleep(2); - spin_lock lock(print_mutex); - // std::cout << " recursive running thread " << id << std::endl; - }); - }); -} - - - -void -test_empty_thread_pool() -{ - std::cout << "\nTesting that pool size 0 makes all jobs run by caller" - << std::endl; - thread_pool* pool(default_thread_pool()); - pool->resize(0); - OIIO_CHECK_EQUAL(pool->size(), 0); - atomic_int count(0); - const int ntasks = 100; - task_set ts(pool); - for (int i = 0; i < ntasks; ++i) - ts.push(pool->push([&](int id) { - OIIO_ASSERT(id == -1 && "Must be run by calling thread"); - count += 1; - })); - ts.wait(); - OIIO_CHECK_EQUAL(count, ntasks); -} - - - -void -test_thread_pool_shutdown() -{ - // Test that we can shut down the pool before exiting - thread_pool* pool(default_thread_pool()); - pool->resize(3); - OIIO_CHECK_EQUAL(pool->size(), 3); - default_thread_pool_shutdown(); - OIIO_CHECK_EQUAL(pool->size(), 0); -} - - - -int -main(int argc, char** argv) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - std::cout << "hw threads = " << Sysutil::hardware_concurrency() << "\n"; - - test_parallel_for(); - test_parallel_for_2D(); - time_parallel_for(); - test_thread_pool_recursion(); - test_empty_thread_pool(); - test_thread_pool_shutdown(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/paramlist_test.cpp b/Sources/OpenImageIO/libutil/paramlist_test.cpp deleted file mode 100644 index 8924d496..00000000 --- a/Sources/OpenImageIO/libutil/paramlist_test.cpp +++ /dev/null @@ -1,390 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include - -#include -#include -#include - - -using namespace OIIO; - - -// Helper: create a single ParamValue, store data in it, make sure we can -// extract each element again, make sure we can convert to the appropriate -// int or float, and also return a string representation. -template -static std::string -test_numeric(T* data, int num_elements, TypeDesc type) -{ - ParamValue p("name", type, num_elements, data); - int n = type.numelements() * num_elements; - for (int i = 0; i < n; ++i) - OIIO_CHECK_EQUAL(p.get(i), ((const T*)data)[i]); - if (std::numeric_limits::is_integer) { - OIIO_CHECK_EQUAL(p.get_int(), int(data[0])); - for (int i = 0; i < n; ++i) - OIIO_CHECK_EQUAL(p.get_int_indexed(i), int(data[i])); - } else { - OIIO_CHECK_EQUAL(p.get_float(), float(data[0])); - for (int i = 0; i < n; ++i) - OIIO_CHECK_EQUAL(p.get_float_indexed(i), float(data[i])); - } - return p.get_string(); -} - - - -// Create ParamValue of various types and make sure it copies the data in -// and out. -void -test_value_types() -{ - std::cout << "test_value_types\n"; - std::string ret; - - { - int val = 42; - ret = test_numeric(&val, 1, TypeDesc::INT); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - unsigned int val = 42; - ret = test_numeric(&val, 1, TypeDesc::UINT); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - short val = 42; - ret = test_numeric(&val, 1, TypeDesc::INT16); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - unsigned short val = 42; - ret = test_numeric(&val, 1, TypeDesc::UINT16); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - char val = 42; - ret = test_numeric(&val, 1, TypeDesc::INT8); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - unsigned char val = 42; - ret = test_numeric(&val, 1, TypeDesc::UINT8); - OIIO_CHECK_EQUAL(ret, "42"); - } - - { - float val = 2.25; - ret = test_numeric(&val, 1, TypeDesc::FLOAT); - OIIO_CHECK_EQUAL(ret, "2.25"); - } - - { - double val = 2.25; - ret = test_numeric(&val, 1, TypeDesc::DOUBLE); - OIIO_CHECK_EQUAL(ret, "2.25"); - } - - { - half val = 2.25; - ret = test_numeric(&val, 1, TypeDesc::HALF); - OIIO_CHECK_EQUAL(ret, "2.25"); - } - - { - const char* val = "hello"; - ParamValue p("name", val); - OIIO_CHECK_EQUAL(p.get(), "hello"); - OIIO_CHECK_EQUAL(p.get_ustring(), "hello"); - OIIO_CHECK_EQUAL(p.get_string(), "hello"); - } - - { - ustringhash val("hello"); - ParamValue p("name", val); - OIIO_CHECK_EQUAL(p.get_string(), "hello"); - OIIO_CHECK_EQUAL(p.get_ustring(), "hello"); - OIIO_CHECK_EQUAL(p.get(), val); - } - - { - const void* ptr = reinterpret_cast(size_t(0xdeadbeef)); - ParamValue p("name", TypeDesc::PTR, 1, &ptr); - OIIO_CHECK_EQUAL(p.get(), ptr); - OIIO_CHECK_EQUAL(p.get_string(), "0xdeadbeef"); - } - - { - int imatrix[] = { 100, 200, 300, 400 }; - ret = test_numeric(&imatrix[0], 1, TypeInt); - OIIO_CHECK_EQUAL(ret, "100"); - ret = test_numeric(imatrix, sizeof(imatrix) / sizeof(int), TypeInt); - OIIO_CHECK_EQUAL(ret, "100, 200, 300, 400"); - OIIO_CHECK_NE(ret, "100, 200, 300, 400,"); - // Test it as an array as well - ret = test_numeric(&imatrix[0], 1, TypeDesc(TypeDesc::INT, 4)); - OIIO_CHECK_EQUAL(ret, "100, 200, 300, 400"); - } - - { - float fmatrix[] = { 10.12f, 200.34f, 300.11f, 400.9f }; - ret = test_numeric(&fmatrix[0], 1, TypeFloat); - OIIO_CHECK_EQUAL(ret, "10.12"); - ret = test_numeric(fmatrix, sizeof(fmatrix) / sizeof(float), TypeFloat); - OIIO_CHECK_EQUAL(ret, "10.12, 200.34, 300.11, 400.9"); - OIIO_CHECK_NE(ret, "10, 200, 300, 400"); - OIIO_CHECK_NE(ret, "10.12, 200.34, 300.11, 400.9,"); - ret = test_numeric(&fmatrix[0], 1, TypeDesc(TypeDesc::FLOAT, 4)); - OIIO_CHECK_EQUAL(ret, "10.12, 200.34, 300.11, 400.9"); - } - - { - unsigned long long ullmatrix[] = { 0xffffffffffffffffULL, - 0xffffffffffffffffULL }; - ret = test_numeric(&ullmatrix[0], 1, TypeDesc::UINT64); - OIIO_CHECK_EQUAL(ret, "18446744073709551615"); - ret = test_numeric(ullmatrix, - sizeof(ullmatrix) / sizeof(unsigned long long), - TypeDesc::UINT64); - OIIO_CHECK_EQUAL(ret, "18446744073709551615, 18446744073709551615"); - OIIO_CHECK_NE(ret, "-1, -1"); - OIIO_CHECK_NE(ret, "18446744073709551615, 18446744073709551615,"); - } - - { - const char* smatrix[] = { "this is \"a test\"", - "this is another test" }; - - ParamValue p("name", smatrix[0]); - OIIO_CHECK_EQUAL(p.get(), smatrix[0]); - OIIO_CHECK_EQUAL(p.get_string(), smatrix[0]); - - ParamValue q("name", TypeString, sizeof(smatrix) / sizeof(char*), - &smatrix); - OIIO_CHECK_EQUAL(q.get_string(), - "\"this is \\\"a test\\\"\", \"this is another test\""); - } - - { - float matrix16[2][16] = { - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }, - { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } - }; - ParamValue p("name", TypeMatrix, 1, matrix16); - std::string s = p.get_string(); - OIIO_CHECK_EQUAL( - s, "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16"); - ParamValue q("name", TypeMatrix, - sizeof(matrix16) / (16 * sizeof(float)), matrix16); - OIIO_CHECK_EQUAL( - q.get_string(), - "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25"); - } - - // Test rational - { - int rat[2] = { 1, 2 }; - ParamValue p("name", TypeRational, 1, rat); - // make sure we can retrieve it as int[2] (numerator, denominator) - OIIO_CHECK_EQUAL(p.get(0), rat[0]); - OIIO_CHECK_EQUAL(p.get(1), rat[1]); - // make sure we can retrieve rational as float, with conversion - OIIO_CHECK_EQUAL(p.get_float(), 0.5f); - // make sure we can retrieve rational as nicely formatted string - OIIO_CHECK_EQUAL(p.get_string(), "1/2"); - } - - // Double check that short data are "local", long data are allocated - ParamValue pvint("", TypeInt, 1, nullptr); - OIIO_CHECK_ASSERT(pvint.datasize() == 4); - OIIO_CHECK_ASSERT(!pvint.is_nonlocal()); - ParamValue pvcolor("", TypeColor, 1, nullptr); - OIIO_CHECK_ASSERT(pvcolor.datasize() == 12); - OIIO_CHECK_ASSERT(!pvcolor.is_nonlocal()); - ParamValue pvmatrix("", TypeMatrix, 1, nullptr); - OIIO_CHECK_ASSERT(pvmatrix.datasize() == 64); - OIIO_CHECK_ASSERT(pvmatrix.is_nonlocal()); -} - - - -static std::string -list_test(const std::string& data, TypeDesc type) -{ - ParamValue p("name", type, data); - return p.get_string(); -} - - - -void -test_from_string() -{ - std::cout << "test_from_string\n"; - TypeDesc type = TypeInt; - std::string ret, data, invalid_data; - - data = "142"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); - - type = TypeFloat; - data = "1.23"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); - - type = TypeDesc(TypeDesc::FLOAT, 5); - data = "1.23, 34.23, 35.11, 99.99, 1999.99"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); - - type = TypeDesc::UINT64; - data = "18446744073709551615"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); - - type = TypeMatrix; - data = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); - - type = TypeString; - data = "foo"; - OIIO_CHECK_EQUAL(data, list_test(data, type)); -} - - - -static void -test_paramlist() -{ - std::cout << "test_paramlist\n"; - ParamValueList pl; - pl.emplace_back("foo", int(42)); - pl.emplace_back("pi", float(M_PI)); - pl.emplace_back("bar", "barbarbar?"); - - OIIO_CHECK_EQUAL(pl.get_int("foo"), 42); - OIIO_CHECK_EQUAL(pl.get_int("pi", 4), 4); // should fail int - OIIO_CHECK_EQUAL(pl.get_float("pi"), float(M_PI)); - OIIO_CHECK_EQUAL(pl.get_int("bar"), 0); - OIIO_CHECK_EQUAL(pl.get_int("bar"), 0); - OIIO_CHECK_EQUAL(pl.get_string("bar"), "barbarbar?"); - OIIO_CHECK_EQUAL(pl.get_string("foo"), "42"); - OIIO_CHECK_ASSERT(pl.find("foo") != pl.cend()); - OIIO_CHECK_ASSERT(pl.find("Foo") == pl.cend()); - OIIO_CHECK_ASSERT(pl.find("Foo", TypeDesc::UNKNOWN, false) != pl.cend()); - OIIO_CHECK_ASSERT(pl.find("Foo", TypeDesc::UNKNOWN, true) == pl.cend()); - OIIO_CHECK_ASSERT(pl.find("foo", TypeDesc::INT) != pl.cend()); - OIIO_CHECK_ASSERT(pl.find("foo", TypeDesc::FLOAT) == pl.cend()); - - OIIO_CHECK_ASSERT(pl.contains("foo")); - OIIO_CHECK_ASSERT(!pl.contains("nonono")); - pl.remove("foo"); - OIIO_CHECK_ASSERT(!pl.contains("foo")); - OIIO_CHECK_ASSERT(pl.contains("bar")); - - { - // Check merge - ParamValueList list1, list2; - list1.emplace_back("b", 2); - list1.emplace_back("c", 3); - list1.emplace_back("a", 1); - list2.emplace_back("d", 11); - list2.emplace_back("c", 10); - list1.merge(list2, /*override=*/false); - OIIO_CHECK_EQUAL(list1.size(), 4); - OIIO_CHECK_EQUAL(list1.get_int("a"), 1); - OIIO_CHECK_EQUAL(list1.get_int("b"), 2); - OIIO_CHECK_EQUAL(list1.get_int("c"), 3); - OIIO_CHECK_EQUAL(list1.get_int("d"), 11); - list1.merge(list2, /*override=*/true); - OIIO_CHECK_EQUAL(list1.size(), 4); - OIIO_CHECK_EQUAL(list1.get_int("a"), 1); - OIIO_CHECK_EQUAL(list1.get_int("b"), 2); - OIIO_CHECK_EQUAL(list1.get_int("c"), 10); - OIIO_CHECK_EQUAL(list1.get_int("d"), 11); - - // Check sort - OIIO_CHECK_EQUAL(list1[0].name(), "b"); - OIIO_CHECK_EQUAL(list1[1].name(), "c"); - OIIO_CHECK_EQUAL(list1[2].name(), "a"); - OIIO_CHECK_EQUAL(list1[3].name(), "d"); - list1.sort(); - OIIO_CHECK_EQUAL(list1[0].name(), "a"); - OIIO_CHECK_EQUAL(list1[1].name(), "b"); - OIIO_CHECK_EQUAL(list1[2].name(), "c"); - OIIO_CHECK_EQUAL(list1[3].name(), "d"); - } -} - - - -static void -test_delegates() -{ - std::cout << "test_delegates\n"; - ParamValueList pl; - pl["foo"] = 42; - pl["pi"] = float(M_PI); - pl["bar"] = "barbarbar?"; - pl["bar2"] = std::string("barbarbar?"); - pl["bar3"] = ustring("barbarbar?"); - pl["bar4"] = string_view("barbarbar?"); - pl["red"] = Imath::Color3f(1.0f, 0.0f, 0.0f); - pl["xy"] = Imath::V3f(0.5f, 0.5f, 0.0f); - pl["Tx"] = Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0, 1); - - OIIO_CHECK_EQUAL(pl["absent"].get(), 0); - OIIO_CHECK_EQUAL(pl["absent"].type(), TypeUnknown); - OIIO_CHECK_EQUAL(pl["foo"].get(), 42); - OIIO_CHECK_EQUAL(pl["foo"].type(), TypeInt); - OIIO_CHECK_EQUAL(pl["foo"].as_string(), "42"); - OIIO_CHECK_EQUAL(pl["pi"].get(), float(M_PI)); - OIIO_CHECK_EQUAL(pl["bar"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar"].as_string(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar2"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar3"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["bar4"].get(), "barbarbar?"); - OIIO_CHECK_EQUAL(pl["red"].get(), - Imath::Color3f(1.0f, 0.0f, 0.0f)); - std::vector redvec { 1.0f, 0.0f, 0.0f }; - OIIO_CHECK_EQUAL(pl["red"].as_vec(), redvec); - OIIO_CHECK_EQUAL(pl["red"].get_indexed(0), 1.0f); - OIIO_CHECK_EQUAL(pl["red"].get_indexed(1), 0.0f); - OIIO_CHECK_EQUAL(pl["red"].get_indexed(2), 0.0f); - OIIO_CHECK_EQUAL(pl["xy"].get(), Imath::V3f(0.5f, 0.5f, 0.0f)); - OIIO_CHECK_EQUAL(pl["Tx"].get(), - Imath::M44f(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 42, 0, 0, - 1)); - std::string s = pl["foo"]; - OIIO_CHECK_EQUAL(s, "42"); - - string_view sv = pl["foo"].get(); - OIIO_CHECK_EQUAL(sv, "42"); - - Strutil::print("Delegate-loaded array is\n"); - for (auto&& p : pl) - Strutil::print(" {:16} : {}\n", p.name(), p.get_string()); - Strutil::print("\n"); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - std::cout << "ParamValue size = " << sizeof(ParamValue) << "\n"; - test_value_types(); - test_from_string(); - test_paramlist(); - test_delegates(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/simd_test.cpp b/Sources/OpenImageIO/libutil/simd_test.cpp deleted file mode 100644 index 5e056d9d..00000000 --- a/Sources/OpenImageIO/libutil/simd_test.cpp +++ /dev/null @@ -1,2058 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -// clang-format off - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -using namespace OIIO; - -using namespace OIIO::simd; - - -static int iterations = 1000000; -static int ntrials = 5; -static Sysutil::Term term(std::cout); -OIIO_SIMD16_ALIGN float dummy_float[16]; -OIIO_SIMD16_ALIGN float dummy_float2[16]; -OIIO_SIMD16_ALIGN float dummy_int[16]; - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - ap.intro("simd_test -- unit test and benchmarks for OpenImageIO/simd.h\n" - OIIO_INTRO_STRING) - .usage("simd_test [options]"); - - ap.arg("--iterations %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - - ap.parse_args(argc, (const char**)argv); -} - - - -static void -category_heading(string_view name) -{ - std::cout << "\n" << term.ansi("bold,underscore,yellow", name) << "\n\n"; -} - - - -static void -test_heading(string_view name, string_view name2 = "") -{ - std::cout << term.ansi("bold") << name << ' ' << name2 - << term.ansi("normal") << "\n"; -} - - - -// What I really want to do is merge benchmark() and benchmark2() into -// one template using variadic arguments, like this: -// template -// void benchmark (size_t work, string_view funcname, FUNC func, ARGS... args) -// But it seems that although this works for Clang, it does not for gcc 4.8 -// (but does for 4.9). Some day I'll get back to this simplification, but -// for now, gcc 4.8 seems like an important barrier. - - -template -void -benchmark(string_view funcname, FUNC func, T x, size_t work = 0) -{ - if (!work) - work = SimdElements::size; - auto repeat_func = [&](){ - // Unroll the loop 8 times - auto r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - r = func(x); DoNotOptimize (r); clobber_all_memory(); - }; - float time = time_trial(repeat_func, ntrials, iterations / 8); - Strutil::print(" {}: {:7.1f} Mvals/sec, ({:.1f} Mcalls/sec)\n", - funcname, ((iterations * work) / 1.0e6) / time, - (iterations / 1.0e6) / time); -} - - -template -void -benchmark2(string_view funcname, FUNC func, T x, U y, size_t work = 0) -{ - if (!work) - work = SimdElements::size; - auto repeat_func = [&]() { - // Unroll the loop 8 times - auto r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - r = func(x, y); DoNotOptimize (r); clobber_all_memory(); - }; - float time = time_trial(repeat_func, ntrials, iterations / 8); - Strutil::print(" {}: {:7.1f} Mvals/sec, ({:.1f} Mcalls/sec)\n", - funcname, ((iterations * work) / 1.0e6) / time, - (iterations / 1.0e6) / time); -} - - - -template -inline VEC -mkvec(typename VEC::value_t a, typename VEC::value_t b, typename VEC::value_t c, - typename VEC::value_t d = 0) -{ - return VEC(a, b, c, d); -} - -template<> -inline vfloat3 -mkvec(float a, float b, float c, float /*d*/) -{ - return vfloat3(a, b, c); -} - -template<> -inline vfloat8 -mkvec(float a, float b, float c, float d) -{ - return vfloat8(a, b, c, d, a, b, c, d); -} - -template<> -inline vfloat16 -mkvec(float a, float b, float c, float d) -{ - return vfloat16(a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d); -} - -template<> -inline vint8 -mkvec(int a, int b, int c, int d) -{ - return vint8(a, b, c, d, a, b, c, d); -} - -template<> -inline vint16 -mkvec(int a, int b, int c, int d) -{ - return vint16(a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d); -} - -template<> -inline vbool8 -mkvec(bool a, bool b, bool c, bool d) -{ - return vbool8(a, b, c, d, a, b, c, d); -} - -template<> -inline vbool16 -mkvec(bool a, bool b, bool c, bool d) -{ - return vbool16(a, b, c, d, a, b, c, d, a, b, c, d, a, b, c, d); -} - - - -template -inline VEC -mkvec(typename VEC::value_t a, typename VEC::value_t b, typename VEC::value_t c, - typename VEC::value_t d, typename VEC::value_t e, typename VEC::value_t f, - typename VEC::value_t g, typename VEC::value_t h) -{ - return VEC(a, b, c, d, e, f, g, h); -} - - -template<> -inline vbool4 -mkvec(bool a, bool b, bool c, bool d, bool, bool, bool, bool) -{ - return vbool4(a, b, c, d); -} - -template<> -inline vint4 -mkvec(int a, int b, int c, int d, int, int, int, int) -{ - return vint4(a, b, c, d); -} - -template<> -inline vint16 -mkvec(int a, int b, int c, int d, int e, int f, int g, int h) -{ - return vint16(a, b, c, d, e, f, g, h, h + 1, h + 2, h + 3, h + 4, h + 5, - h + 6, h + 7, h + 8); -} - -template<> -inline vfloat4 -mkvec(float a, float b, float c, float d, float, float, float, float) -{ - return vfloat4(a, b, c, d); -} - -template<> -inline vfloat3 -mkvec(float a, float b, float c, float, float, float, float, float) -{ - return vfloat3(a, b, c); -} - -template<> -inline vfloat16 -mkvec(float a, float b, float c, float d, float e, float f, float g, - float h) -{ - return vfloat16(a, b, c, d, e, f, g, h, h + 1, h + 2, h + 3, h + 4, h + 5, - h + 6, h + 7, h + 8); -} - - - -template -inline int -loadstore_vec(int /*dummy*/) -{ - typedef typename VEC::value_t ELEM; - ELEM B[VEC::elements]; - VEC v; - v.load((ELEM*)dummy_float); - DoNotOptimize(v); - clobber_all_memory(); - v.store((ELEM*)B); - DoNotOptimize(B[0]); - return 0; -} - -template -inline VEC -load_vec(int /*dummy*/) -{ - typedef typename VEC::value_t ELEM; - VEC v; - v.load((ELEM*)dummy_float); - return v; -} - -template -inline int -store_vec(const VEC& v) -{ - typedef typename VEC::value_t ELEM; - v.store((ELEM*)dummy_float); - return 0; -} - -template -inline VEC -load_scalar(int /*dummy*/) -{ - typedef typename VEC::value_t ELEM; - VEC v; -OIIO_PRAGMA_WARNING_PUSH -OIIO_GCC_ONLY_PRAGMA(GCC diagnostic ignored "-Wstrict-aliasing") - v.load(*(ELEM*)dummy_float); -OIIO_PRAGMA_WARNING_POP - return v; -} - -template -inline VEC -load_vec_N(typename VEC::value_t* /*B*/) -{ - typedef typename VEC::value_t ELEM; - VEC v; - v.load((ELEM*)dummy_float, N); - return v; -} - -template -inline int -store_vec_N(const VEC& v) -{ - typedef typename VEC::value_t ELEM; - v.store((ELEM*)dummy_float, N); - DoNotOptimize(dummy_float[0]); - return 0; -} - - - -inline float -dot_imath(const Imath::V3f& v) -{ - return v.dot(v); -} -inline float -dot_imath_simd(const Imath::V3f& v_) -{ - vfloat3 v(v_); - return simd::dot(v, v); -} -inline float -dot_simd(const simd::vfloat3& v) -{ - return dot(v, v); -} - -inline Imath::V3f -norm_imath(const Imath::V3f& a) -{ - return a.normalized(); -} - -inline Imath::V3f -norm_imath_simd(const vfloat3& a) -{ - return a.normalized().V3f(); -} - -inline Imath::V3f -norm_imath_simd_fast(const vfloat3& a) -{ - return a.normalized_fast().V3f(); -} - -inline vfloat3 -norm_simd_fast(const vfloat3& a) -{ - return a.normalized_fast(); -} - -inline vfloat3 -norm_simd(const vfloat3& a) -{ - return a.normalized(); -} - - -inline Imath::M44f -inverse_imath(const Imath::M44f& M) -{ - return M.inverse(); -} - - -inline matrix44 -inverse_simd(const matrix44& M) -{ - return M.inverse(); -} - - - -template -void -test_loadstore() -{ - typedef typename VEC::value_t ELEM; - test_heading("load/store ", VEC::type_name()); - OIIO_SIMD16_ALIGN ELEM oneval[] - = { 101, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 101, 101 }; - OIIO_CHECK_SIMD_EQUAL(VEC(oneval), VEC(oneval[0])); - { VEC a = oneval[0]; OIIO_CHECK_SIMD_EQUAL(VEC(oneval), a); } - OIIO_SIMD16_ALIGN VEC C1234 = VEC::Iota(1); - OIIO_SIMD16_ALIGN ELEM partial[] - = { 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116 }; - OIIO_CHECK_SIMD_EQUAL(VEC(partial), VEC::Iota(101)); - for (int i = 1; i <= VEC::elements; ++i) { - VEC a(ELEM(0)); - a.load(partial, i); - for (int j = 0; j < VEC::elements; ++j) - OIIO_CHECK_EQUAL(a[j], j < i ? partial[j] : ELEM(0)); - std::cout << " partial load " << i << " : " << a << "\n"; - ELEM stored[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - C1234.store(stored, i); - for (int j = 0; j < VEC::elements; ++j) - OIIO_CHECK_EQUAL(stored[j], j < i ? ELEM(j + 1) : ELEM(0)); - std::cout << " partial store " << i << " :"; - for (int c = 0; c < VEC::elements; ++c) - std::cout << ' ' << stored[c]; - std::cout << std::endl; - } - - benchmark("load scalar", load_scalar, 0, VEC::elements); - benchmark("load vec", load_vec, 0, VEC::elements); - benchmark("store vec", store_vec, 0, VEC::elements); - OIIO_SIMD16_ALIGN ELEM tmp[VEC::elements]; - if (VEC::elements == 16) { - benchmark("load 16 comps", load_vec_N, tmp, 16); - benchmark("load 13 comps", load_vec_N, tmp, 13); - benchmark("load 9 comps", load_vec_N, tmp, 9); - } - if (VEC::elements > 4) { - benchmark("load 8 comps", load_vec_N, tmp, 8); - benchmark("load 7 comps", load_vec_N, tmp, 7); - benchmark("load 6 comps", load_vec_N, tmp, 6); - benchmark("load 5 comps", load_vec_N, tmp, 5); - } - if (VEC::elements >= 4) { - benchmark("load 4 comps", load_vec_N, tmp, 4); - } - benchmark("load 3 comps", load_vec_N, tmp, 3); - benchmark("load 2 comps", load_vec_N, tmp, 2); - benchmark("load 1 comps", load_vec_N, tmp, 1); - - if (VEC::elements == 16) { - benchmark("store 16 comps", store_vec_N, C1234, 16); - benchmark("store 13 comps", store_vec_N, C1234, 13); - benchmark("store 9 comps", store_vec_N, C1234, 9); - } - if (VEC::elements > 4) { - benchmark("store 8 comps", store_vec_N, C1234, 8); - benchmark("store 7 comps", store_vec_N, C1234, 7); - benchmark("store 6 comps", store_vec_N, C1234, 6); - benchmark("store 5 comps", store_vec_N, C1234, 5); - } - if (VEC::elements >= 4) { - benchmark("store 4 comps", store_vec_N, C1234, 4); - } - benchmark("store 3 comps", store_vec_N, C1234, 3); - benchmark("store 2 comps", store_vec_N, C1234, 2); - benchmark("store 1 comps", store_vec_N, C1234, 1); -} - - - -template -void -test_conversion_loadstore_float() -{ - typedef typename VEC::value_t ELEM; - test_heading("load/store with conversion", VEC::type_name()); - VEC C1234 = VEC::Iota(1); - ELEM partial[] = { 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116 }; - OIIO_CHECK_SIMD_EQUAL(VEC(partial), VEC::Iota(101)); - - // Check load from integers - unsigned short us1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - short s1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - unsigned char uc1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - char c1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - half h1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - OIIO_CHECK_SIMD_EQUAL (VEC(us1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC( s1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC(uc1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC( c1234), C1234); - - benchmark ("load from unsigned short[]", [](const unsigned short *d){ return VEC(d); }, us1234); - benchmark ("load from short[]", [](const short *d){ return VEC(d); }, s1234); - benchmark ("load from unsigned char[]", [](const unsigned char *d){ return VEC(d); }, uc1234); - benchmark ("load from char[]", [](const char *d){ return VEC(d); }, c1234); - benchmark ("load from half[]", [](const half *d){ return VEC(d); }, h1234); - - benchmark ("store to half[]", [=](half *d){ C1234.store(d); return 0; }, h1234, VEC::elements); -} - - - -template -void test_conversion_loadstore_int () -{ - typedef typename VEC::value_t ELEM; - test_heading ("load/store with conversion", VEC::type_name()); - VEC C1234 = VEC::Iota(1); - ELEM partial[] = { 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116 }; - OIIO_CHECK_SIMD_EQUAL (VEC(partial), VEC::Iota(101)); - - // Check load from integers - int i1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - unsigned short us1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - short s1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - unsigned char uc1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - char c1234[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; - OIIO_CHECK_SIMD_EQUAL (VEC( i1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC(us1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC( s1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC(uc1234), C1234); - OIIO_CHECK_SIMD_EQUAL (VEC( c1234), C1234); - - benchmark ("load from int[]", [](const int *d){ return VEC(d); }, i1234); - benchmark ("load from unsigned short[]", [](const unsigned short *d){ return VEC(d); }, us1234); - benchmark ("load from short[]", [](const short *d){ return VEC(d); }, s1234); - benchmark ("load from unsigned char[]", [](const unsigned char *d){ return VEC(d); }, uc1234); - benchmark ("load from char[]", [](const char *d){ return VEC(d); }, c1234); - - benchmark ("store to unsigned short[]", [=](unsigned short *d){ C1234.store(d); return 0; }, us1234, VEC::elements); - benchmark ("store to unsigned char[]", [=](unsigned char *d){ C1234.store(d); return 0; }, uc1234, VEC::elements); -} - - - -template -void test_vint_to_uint16s () -{ - test_heading (Strutil::sprintf("test converting %s to uint16", VEC::type_name())); - VEC ival = VEC::Iota (0xffff0000); - unsigned short buf[VEC::elements]; - ival.store (buf); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL (int(buf[i]), i); - - benchmark2 ("load from uint16", [](VEC& a, unsigned short *s){ a.load(s); return 1; }, ival, buf, VEC::elements); - benchmark2 ("convert to uint16", [](const VEC& a, unsigned short *s){ a.store(s); return 1; }, ival, buf, VEC::elements); -} - - - -template -void test_vint_to_uint8s () -{ - test_heading (Strutil::sprintf("test converting %s to uint8", VEC::type_name())); - VEC ival = VEC::Iota (0xffffff00); - unsigned char buf[VEC::elements]; - ival.store (buf); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL (int(buf[i]), i); - - benchmark2 ("load from uint8", [](VEC& a, unsigned char *s){ a.load(s); return 1; }, ival, buf, VEC::elements); - benchmark2 ("convert to uint16", [](const VEC& a, unsigned char *s){ a.store(s); return 1; }, ival, buf, VEC::elements); -} - - - -template -void test_masked_loadstore () -{ - typedef typename VEC::value_t ELEM; - typedef typename VEC::vbool_t BOOL; - test_heading ("masked loadstore ", VEC::type_name()); - ELEM iota[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; - BOOL mask1 = mkvec (true, false, true, false); - BOOL mask2 = mkvec (true, true, false,false); - - VEC v; - v = -1; - v.load_mask (mask1, iota); - ELEM r1[] = { 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 0, 15, 0 }; - OIIO_CHECK_SIMD_EQUAL (v, VEC(r1)); - ELEM buf[] = { -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 }; - v.store_mask (mask2, buf); - ELEM r2[] = { 1, 0, -2, -2, 5, 0, -2, -2, 9, 0, -2, -2, 13, 0, -2, -2 }; - OIIO_CHECK_SIMD_EQUAL (VEC(buf), VEC(r2)); - - benchmark ("masked load with int mask", [](const ELEM *d){ VEC v; v.load_mask (0xffff, d); return v; }, iota); - benchmark ("masked load with bool mask", [](const ELEM *d){ VEC v; v.load_mask (BOOL::True(), d); return v; }, iota); - benchmark ("masked store with int mask", [&](ELEM *d){ v.store_mask (0xffff, d); return 0; }, r2); - benchmark ("masked store with bool mask", [&](ELEM *d){ v.store_mask (BOOL::True(), d); return 0; }, r2); -} - - - -template -void -test_gatherscatter() -{ - typedef typename VEC::value_t ELEM; - typedef typename VEC::vbool_t BOOL; - test_heading("scatter & gather ", VEC::type_name()); - - const int spacing = 3; - const int bufsize = VEC::elements * 3 + 1; - std::vector gather_source(bufsize); - for (int i = 0; i < bufsize; ++i) - gather_source[i] = ((i % spacing) == 1) ? i / 3 : -1; - // gather_source will contain: -1 0 -1 -1 1 -1 -1 2 -1 -1 3 -1 ... - - auto indices = VEC::vint_t::Iota(1, 3); - VEC g, gm; - g.gather(gather_source.data(), indices); - OIIO_CHECK_SIMD_EQUAL(g, VEC::Iota()); - - BOOL mask = BOOL::from_bitmask(0x55555555); // every other one - ELEM every_other_iota[] = { 0, 0, 2, 0, 4, 0, 6, 0, 8, 0, 10, 0, 12, 0, 14, 0 }; - gm = 0; - gm.gather_mask (mask, gather_source.data(), indices); - OIIO_CHECK_SIMD_EQUAL (gm, VEC(every_other_iota)); - - std::vector scatter_out (bufsize, (ELEM)-1); - g.scatter (scatter_out.data(), indices); - OIIO_CHECK_ASSERT (scatter_out == gather_source); - - std::fill (scatter_out.begin(), scatter_out.end(), -1); - VEC::Iota().scatter_mask (mask, scatter_out.data(), indices); - for (int i = 0; i < (int)scatter_out.size(); ++i) - OIIO_CHECK_EQUAL (scatter_out[i], ((i%3) == 1 && (i&1) ? i/3 : -1)); - - benchmark ("gather", [&](const ELEM *d){ VEC v; v.gather (d, indices); return v; }, gather_source.data()); - benchmark ("gather_mask", [&](const ELEM *d){ VEC v; v.gather_mask (mask, d, indices); return v; }, gather_source.data()); - benchmark ("scatter", [&](ELEM *d){ g.scatter (d, indices); return g; }, scatter_out.data()); - benchmark ("scatter_mask", [&](ELEM *d){ g.scatter_mask (mask, d, indices); return g; }, scatter_out.data()); -} - - - -template -void test_extract3 () -{ - const T vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - using VEC = typename VecType::type; - VEC b (vals); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL (b[i], vals[i]); - OIIO_CHECK_EQUAL (extract<0>(b), 0); - OIIO_CHECK_EQUAL (extract<1>(b), 1); - OIIO_CHECK_EQUAL (extract<2>(b), 2); -} - -template -void -test_extract4() -{ - const T vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - using VEC = typename VecType::type; - VEC b(vals); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL(b[i], vals[i]); - OIIO_CHECK_EQUAL(extract<0>(b), 0); - OIIO_CHECK_EQUAL(extract<1>(b), 1); - OIIO_CHECK_EQUAL(extract<2>(b), 2); - OIIO_CHECK_EQUAL(extract<3>(b), 3); -} - -template -void -test_extract8() -{ - test_extract4(); - - const T vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - using VEC = typename VecType::type; - VEC b(vals); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL(b[i], vals[i]); - OIIO_CHECK_EQUAL(extract<4>(b), 4); - OIIO_CHECK_EQUAL(extract<5>(b), 5); - OIIO_CHECK_EQUAL(extract<6>(b), 6); - OIIO_CHECK_EQUAL(extract<7>(b), 7); -} - -template -void -test_extract16() -{ - test_extract8(); - - const T vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - using VEC = typename VecType::type; - VEC b(vals); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL(b[i], vals[i]); - OIIO_CHECK_EQUAL(extract<8>(b), 8); - OIIO_CHECK_EQUAL(extract<9>(b), 9); - OIIO_CHECK_EQUAL(extract<10>(b), 10); - OIIO_CHECK_EQUAL(extract<11>(b), 11); - OIIO_CHECK_EQUAL(extract<12>(b), 12); - OIIO_CHECK_EQUAL(extract<13>(b), 13); - OIIO_CHECK_EQUAL(extract<14>(b), 14); - OIIO_CHECK_EQUAL(extract<15>(b), 15); -} - - - -template void test_extract (); -template<> void test_extract () { test_extract16(); } -template<> void test_extract () { test_extract16(); } -template<> void test_extract () { test_extract8(); } -template<> void test_extract () { test_extract8(); } -template<> void test_extract () { test_extract4(); } -template<> void test_extract () { test_extract4(); } -template<> void test_extract () { test_extract3(); } - - - -template -void -test_component_access() -{ - typedef typename VEC::value_t ELEM; - test_heading("component_access ", VEC::type_name()); - - const ELEM vals[] - = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - VEC a = VEC::Iota(); - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL(a[i], vals[i]); - - if (VEC::elements <= 4) { - OIIO_CHECK_EQUAL(a.x(), 0); - OIIO_CHECK_EQUAL(a.y(), 1); - OIIO_CHECK_EQUAL(a.z(), 2); - if (SimdElements::size > 3) - OIIO_CHECK_EQUAL(a.w(), 3); - VEC t; - t = a; - t.set_x(42); - OIIO_CHECK_SIMD_EQUAL(t, mkvec(42, 1, 2, 3, 4, 5, 6, 7)); - t = a; - t.set_y(42); - OIIO_CHECK_SIMD_EQUAL(t, mkvec(0, 42, 2, 3, 4, 5, 6, 7)); - t = a; - t.set_z(42); - OIIO_CHECK_SIMD_EQUAL(t, mkvec(0, 1, 42, 3, 4, 5, 6, 7)); - if (SimdElements::size > 3) { - t = a; - t.set_w(42); - OIIO_CHECK_SIMD_EQUAL(t, mkvec(0, 1, 2, 42, 4, 5, 6, 7)); - } - } - - OIIO_CHECK_EQUAL(extract<0>(a), 0); - OIIO_CHECK_EQUAL(extract<1>(a), 1); - OIIO_CHECK_EQUAL(extract<2>(a), 2); - if (SimdElements::size > 3) - OIIO_CHECK_EQUAL (extract<3>(a), 3); - OIIO_CHECK_SIMD_EQUAL (insert<0>(a, ELEM(42)), mkvec(42,1,2,3,4,5,6,7)); - OIIO_CHECK_SIMD_EQUAL (insert<1>(a, ELEM(42)), mkvec(0,42,2,3,4,5,6,7)); - OIIO_CHECK_SIMD_EQUAL (insert<2>(a, ELEM(42)), mkvec(0,1,42,3,4,5,6,7)); - if (SimdElements::size > 3) - OIIO_CHECK_SIMD_EQUAL (insert<3>(a, ELEM(42)), mkvec(0,1,2,42,4,5,6,7)); - - VEC b(vals); -#if 1 - test_extract(); -#else - for (int i = 0; i < VEC::elements; ++i) - OIIO_CHECK_EQUAL(b[i], vals[i]); - OIIO_CHECK_EQUAL(extract<0>(b), 0); - OIIO_CHECK_EQUAL(extract<1>(b), 1); - OIIO_CHECK_EQUAL(extract<2>(b), 2); - if (SimdElements::size > 3) - OIIO_CHECK_EQUAL(extract<3>(b), 3); - if (SimdElements::size > 4) { - OIIO_CHECK_EQUAL(extract<4>(b), 4); - OIIO_CHECK_EQUAL(extract<5>(b), 5); - OIIO_CHECK_EQUAL(extract<6>(b), 6); - OIIO_CHECK_EQUAL(extract<7>(b), 7); - } - if (SimdElements::size > 8) { - OIIO_CHECK_EQUAL(extract<8>(b), 8); - OIIO_CHECK_EQUAL(extract<9>(b), 9); - OIIO_CHECK_EQUAL(extract<10>(b), 10); - OIIO_CHECK_EQUAL(extract<11>(b), 11); - OIIO_CHECK_EQUAL(extract<12>(b), 12); - OIIO_CHECK_EQUAL(extract<13>(b), 13); - OIIO_CHECK_EQUAL(extract<14>(b), 14); - OIIO_CHECK_EQUAL(extract<15>(b), 15); - } -#endif - - benchmark2 ("operator[i]", [&](const VEC& v, int i){ return v[i]; }, b, 2, 1 /*work*/); - benchmark2 ("operator[2]", [&](const VEC& v, int /*i*/){ return v[2]; }, b, 2, 1 /*work*/); - benchmark2 ("operator[0]", [&](const VEC& v, int /*i*/){ return v[0]; }, b, 0, 1 /*work*/); - benchmark2 ("extract<2> ", [&](const VEC& v, int /*i*/){ return extract<2>(v); }, b, 2, 1 /*work*/); - benchmark2 ("extract<0> ", [&](const VEC& v, int /*i*/){ return extract<0>(v); }, b, 0, 1 /*work*/); - benchmark2 ("insert<2> ", [&](const VEC& v, ELEM i){ return insert<2>(v, i); }, b, ELEM(1), 1 /*work*/); -} - - - -template<> -void -test_component_access() -{ - typedef vbool4 VEC; - test_heading("component_access ", VEC::type_name()); - - for (int bit = 0; bit < VEC::elements; ++bit) { - VEC ctr(bit == 0, bit == 1, bit == 2, bit == 3); - VEC a; - a.clear(); - for (int b = 0; b < VEC::elements; ++b) - a.setcomp(b, b == bit); - OIIO_CHECK_SIMD_EQUAL(ctr, a); - for (int b = 0; b < VEC::elements; ++b) - OIIO_CHECK_EQUAL(bool(a[b]), b == bit); - OIIO_CHECK_EQUAL(extract<0>(a), bit == 0); - OIIO_CHECK_EQUAL(extract<1>(a), bit == 1); - OIIO_CHECK_EQUAL(extract<2>(a), bit == 2); - OIIO_CHECK_EQUAL(extract<3>(a), bit == 3); - } - - VEC a; - a.load(0, 0, 0, 0); - OIIO_CHECK_SIMD_EQUAL(insert<0>(a, 1), VEC(1, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<1>(a, 1), VEC(0, 1, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<2>(a, 1), VEC(0, 0, 1, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<3>(a, 1), VEC(0, 0, 0, 1)); - a.load(1, 1, 1, 1); - OIIO_CHECK_SIMD_EQUAL(insert<0>(a, 0), VEC(0, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<1>(a, 0), VEC(1, 0, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<2>(a, 0), VEC(1, 1, 0, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<3>(a, 0), VEC(1, 1, 1, 0)); -} - - - -template<> -void -test_component_access() -{ - typedef vbool8 VEC; - test_heading("component_access ", VEC::type_name()); - - for (int bit = 0; bit < VEC::elements; ++bit) { - VEC ctr(bit == 0, bit == 1, bit == 2, bit == 3, bit == 4, bit == 5, - bit == 6, bit == 7); - VEC a; - a.clear(); - for (int b = 0; b < VEC::elements; ++b) - a.setcomp(b, b == bit); - OIIO_CHECK_SIMD_EQUAL(ctr, a); - for (int b = 0; b < VEC::elements; ++b) - OIIO_CHECK_EQUAL(bool(a[b]), b == bit); - OIIO_CHECK_EQUAL(extract<0>(a), bit == 0); - OIIO_CHECK_EQUAL(extract<1>(a), bit == 1); - OIIO_CHECK_EQUAL(extract<2>(a), bit == 2); - OIIO_CHECK_EQUAL(extract<3>(a), bit == 3); - OIIO_CHECK_EQUAL(extract<4>(a), bit == 4); - OIIO_CHECK_EQUAL(extract<5>(a), bit == 5); - OIIO_CHECK_EQUAL(extract<6>(a), bit == 6); - OIIO_CHECK_EQUAL(extract<7>(a), bit == 7); - } - - VEC a; - a.load(0, 0, 0, 0, 0, 0, 0, 0); - OIIO_CHECK_SIMD_EQUAL(insert<0>(a, 1), VEC(1, 0, 0, 0, 0, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<1>(a, 1), VEC(0, 1, 0, 0, 0, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<2>(a, 1), VEC(0, 0, 1, 0, 0, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<3>(a, 1), VEC(0, 0, 0, 1, 0, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<4>(a, 1), VEC(0, 0, 0, 0, 1, 0, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<5>(a, 1), VEC(0, 0, 0, 0, 0, 1, 0, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<6>(a, 1), VEC(0, 0, 0, 0, 0, 0, 1, 0)); - OIIO_CHECK_SIMD_EQUAL(insert<7>(a, 1), VEC(0, 0, 0, 0, 0, 0, 0, 1)); - a.load(1, 1, 1, 1, 1, 1, 1, 1); - OIIO_CHECK_SIMD_EQUAL(insert<0>(a, 0), VEC(0, 1, 1, 1, 1, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<1>(a, 0), VEC(1, 0, 1, 1, 1, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<2>(a, 0), VEC(1, 1, 0, 1, 1, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<3>(a, 0), VEC(1, 1, 1, 0, 1, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<4>(a, 0), VEC(1, 1, 1, 1, 0, 1, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<5>(a, 0), VEC(1, 1, 1, 1, 1, 0, 1, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<6>(a, 0), VEC(1, 1, 1, 1, 1, 1, 0, 1)); - OIIO_CHECK_SIMD_EQUAL(insert<7>(a, 0), VEC(1, 1, 1, 1, 1, 1, 1, 0)); -} - - - -template<> -void -test_component_access() -{ - typedef vbool16 VEC; - test_heading("component_access ", VEC::type_name()); - - for (int bit = 0; bit < VEC::elements; ++bit) { - VEC ctr(bit == 0, bit == 1, bit == 2, bit == 3, bit == 4, bit == 5, - bit == 6, bit == 7, bit == 8, bit == 9, bit == 10, bit == 11, - bit == 12, bit == 13, bit == 14, bit == 15); - VEC a; - a.clear(); - for (int b = 0; b < VEC::elements; ++b) - a.setcomp(b, b == bit); - OIIO_CHECK_SIMD_EQUAL(ctr, a); - for (int b = 0; b < VEC::elements; ++b) - OIIO_CHECK_EQUAL(bool(a[b]), b == bit); - OIIO_CHECK_EQUAL(extract<0>(a), bit == 0); - OIIO_CHECK_EQUAL(extract<1>(a), bit == 1); - OIIO_CHECK_EQUAL(extract<2>(a), bit == 2); - OIIO_CHECK_EQUAL(extract<3>(a), bit == 3); - OIIO_CHECK_EQUAL(extract<4>(a), bit == 4); - OIIO_CHECK_EQUAL(extract<5>(a), bit == 5); - OIIO_CHECK_EQUAL(extract<6>(a), bit == 6); - OIIO_CHECK_EQUAL(extract<7>(a), bit == 7); - OIIO_CHECK_EQUAL(extract<8>(a), bit == 8); - OIIO_CHECK_EQUAL(extract<9>(a), bit == 9); - OIIO_CHECK_EQUAL(extract<10>(a), bit == 10); - OIIO_CHECK_EQUAL(extract<11>(a), bit == 11); - OIIO_CHECK_EQUAL(extract<12>(a), bit == 12); - OIIO_CHECK_EQUAL(extract<13>(a), bit == 13); - OIIO_CHECK_EQUAL(extract<14>(a), bit == 14); - OIIO_CHECK_EQUAL(extract<15>(a), bit == 15); - } - - VEC a; - a.load (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); - OIIO_CHECK_SIMD_EQUAL (insert<0> (a, 1), VEC(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<1> (a, 1), VEC(0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<2> (a, 1), VEC(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<3> (a, 1), VEC(0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<4> (a, 1), VEC(0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<5> (a, 1), VEC(0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<6> (a, 1), VEC(0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<7> (a, 1), VEC(0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<8> (a, 1), VEC(0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<9> (a, 1), VEC(0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<10>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<11>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<12>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<13>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0)); - OIIO_CHECK_SIMD_EQUAL (insert<14>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0)); - OIIO_CHECK_SIMD_EQUAL (insert<15>(a, 1), VEC(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1)); - a.load (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); - OIIO_CHECK_SIMD_EQUAL (insert<0> (a, 0), VEC(0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<1> (a, 0), VEC(1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<2> (a, 0), VEC(1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<3> (a, 0), VEC(1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<4> (a, 0), VEC(1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<5> (a, 0), VEC(1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<6> (a, 0), VEC(1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<7> (a, 0), VEC(1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<8> (a, 0), VEC(1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<9> (a, 0), VEC(1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<10>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<11>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<12>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<13>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1)); - OIIO_CHECK_SIMD_EQUAL (insert<14>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1)); - OIIO_CHECK_SIMD_EQUAL (insert<15>(a, 0), VEC(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0)); -} - - - -template inline T do_neg (const T &a) { return -a; } -template inline T do_add (const T &a, const T &b) { return a+b; } -template inline T do_sub (const T &a, const T &b) { return a-b; } -template inline auto do_mul (const T &a, const U &b) -> decltype(a*b) { return a*b; } -template inline T do_div (const T &a, const T &b) { return a/b; } -template inline T do_safe_div (const T &a, const T &b) { return T(safe_div(a,b)); } -inline Imath::V3f add_vec_simd (const Imath::V3f &a, const Imath::V3f &b) { - return (vfloat3(a)+vfloat3(b)).V3f(); -} -template inline T do_abs (const T &a) { return abs(a); } - - -template -void test_arithmetic () -{ - typedef typename VEC::value_t ELEM; - test_heading ("arithmetic ", VEC::type_name()); - - ELEM eps = static_cast(1.0e-6); - VEC a = VEC::Iota (1, 3); - VEC b = VEC::Iota (1, 1); - VEC add(ELEM(0)), sub(ELEM(0)), mul(ELEM(0)), div(ELEM(0)); - ELEM bsum(ELEM(0)); - for (int i = 0; i < VEC::elements; ++i) { - add[i] = a[i] + b[i]; - sub[i] = a[i] - b[i]; - mul[i] = a[i] * b[i]; - div[i] = a[i] / b[i]; - bsum += b[i]; - } - OIIO_CHECK_SIMD_EQUAL (a+b, add); - OIIO_CHECK_SIMD_EQUAL (a-b, sub); - OIIO_CHECK_SIMD_EQUAL (a*b, mul); - OIIO_CHECK_SIMD_EQUAL_THRESH (a/b, div, eps); - OIIO_CHECK_SIMD_EQUAL (a*ELEM(2), a*VEC(ELEM(2))); - OIIO_CHECK_SIMD_EQUAL (ELEM(2)*a, a*VEC(ELEM(2))); - { VEC r = a; r += b; OIIO_CHECK_SIMD_EQUAL (r, add); } - { VEC r = a; r -= b; OIIO_CHECK_SIMD_EQUAL (r, sub); } - { VEC r = a; r *= b; OIIO_CHECK_SIMD_EQUAL (r, mul); } - { VEC r = a; r /= b; OIIO_CHECK_SIMD_EQUAL_THRESH (r, div, eps); } - { VEC r = a; r *= ELEM(2); OIIO_CHECK_SIMD_EQUAL (r, a*ELEM(2)); } - // Test to make sure * works for negative 32 bit ints on all SIMD levels, - // because it's a different code path for sse2. - VEC negA = mkvec(-1, 1, -2, 2); - VEC negB = mkvec(2, 2, -2, -2); - OIIO_CHECK_SIMD_EQUAL(negA * negB, mkvec(-2, 2, 4, -4)); - - OIIO_CHECK_EQUAL (reduce_add(b), bsum); - OIIO_CHECK_SIMD_EQUAL (vreduce_add(b), VEC(bsum)); - OIIO_CHECK_EQUAL (reduce_add(VEC(1.0f)), SimdElements::size); - - benchmark2 ("operator+", do_add, a, b); - benchmark2 ("operator-", do_sub, a, b); - benchmark ("operator- (neg)", do_neg, a); - benchmark2 ("operator*", do_mul, a, b); - benchmark2 ("operator* (scalar)", do_mul, a, ELEM(2)); - benchmark2 ("operator/", do_div, a, b); - benchmark ("abs", do_abs, a); - benchmark ("reduce_add", [](const VEC& a){ return vreduce_add(a); }, a); - if (is_same::value) { // For vfloat3, compare to Imath - Imath::V3f a(2.51f,1.0f,1.0f), b(3.1f,1.0f,1.0f); - benchmark2 ("add Imath::V3f", do_add, a, b, 3 /*work*/); - benchmark2 ("add Imath::V3f with simd", add_vec_simd, a, b, 3 /*work*/); - benchmark2 ("sub Imath::V3f", do_sub, a, b, 3 /*work*/); - benchmark2 ("mul Imath::V3f", do_mul, a, b, 3 /*work*/); - benchmark2 ("div Imath::V3f", do_div, a, b, 3 /*work*/); - } - benchmark2 ("reference: add scalar", do_add, a[2], b[1]); - benchmark2 ("reference: mul scalar", do_mul, a[2], b[1]); - benchmark2 ("reference: div scalar", do_div, a[2], b[1]); -} - - - -template -void test_fused () -{ - test_heading ("fused ", VEC::type_name()); - - VEC a = VEC::Iota (10); - VEC b = VEC::Iota (1); - VEC c = VEC::Iota (0.5f); - OIIO_CHECK_SIMD_EQUAL (madd (a, b, c), a*b+c); - OIIO_CHECK_SIMD_EQUAL (msub (a, b, c), a*b-c); - OIIO_CHECK_SIMD_EQUAL (nmadd (a, b, c), -(a*b)+c); - OIIO_CHECK_SIMD_EQUAL (nmsub (a, b, c), -(a*b)-c); - - benchmark2 ("madd old *+", [&](const VEC& a, const VEC& b){ return a*b+c; }, a, b); - benchmark2 ("madd fused", [&](const VEC& a, const VEC& b){ return madd(a,b,c); }, a, b); - benchmark2 ("msub old *-", [&](const VEC& a, const VEC& b){ return a*b-c; }, a, b); - benchmark2 ("msub fused", [&](const VEC& a, const VEC& b){ return msub(a,b,c); }, a, b); - benchmark2 ("nmadd old (-*)+", [&](const VEC& a, const VEC& b){ return c-(a*b); }, a, b); - benchmark2 ("nmadd fused", [&](const VEC& a, const VEC& b){ return nmadd(a,b,c); }, a, b); - benchmark2 ("nmsub old -(*+)", [&](const VEC& a, const VEC& b){ return -(a*b)-c; }, a, b); - benchmark2 ("nmsub fused", [&](const VEC& a, const VEC& b){ return nmsub(a,b,c); }, a, b); -} - - - -template T do_and (const T& a, const T& b) { return a & b; } -template T do_or (const T& a, const T& b) { return a | b; } -template T do_xor (const T& a, const T& b) { return a ^ b; } -template T do_compl (const T& a) { return ~a; } -template T do_andnot (const T& a, const T& b) { return andnot(a,b); } - - - -template -void -test_bitwise_int() -{ - test_heading("bitwise ", VEC::type_name()); - - VEC a(0x12341234); - VEC b(0x11111111); - OIIO_CHECK_SIMD_EQUAL(a & b, VEC(0x10101010)); - OIIO_CHECK_SIMD_EQUAL(a | b, VEC(0x13351335)); - OIIO_CHECK_SIMD_EQUAL(a ^ b, VEC(0x03250325)); - OIIO_CHECK_SIMD_EQUAL(~(a), VEC(0xedcbedcb)); - OIIO_CHECK_SIMD_EQUAL(andnot(b, a), (~(b)) & a); - OIIO_CHECK_SIMD_EQUAL(andnot(b, a), VEC(0x02240224)); - - VEC atest(15); - atest[1] = 7; - OIIO_CHECK_EQUAL(reduce_and(atest), 7); - - VEC otest(0); - otest[1] = 3; - otest[2] = 4; - OIIO_CHECK_EQUAL(reduce_or(otest), 7); - - benchmark2("operator&", do_and, a, b); - benchmark2("operator|", do_or, a, b); - benchmark2("operator^", do_xor, a, b); - benchmark("operator!", do_compl, a); - benchmark2("andnot", do_andnot, a, b); - benchmark("reduce_and", [](const VEC& a) { return reduce_and(a); }, a); - benchmark("reduce_or ", [](const VEC& a) { return reduce_or(a); }, a); -} - - - -template -void test_bitwise_bool () -{ - test_heading ("bitwise ", VEC::type_name()); - - bool A[] = { true, true, false, false, false, false, true, true, - true, true, false, false, false, false, true, true }; - bool B[] = { true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false }; - bool AND[] = { true, false, false, false, false, false, true, false, - true, false, false, false, false, false, true, false }; - bool OR[] = { true, true, true, false, true, false, true, true, - true, true, true, false, true, false, true, true }; - bool XOR[] = { false, true, true, false, true, false, false, true, - false, true, true, false, true, false, false, true }; - bool NOT[] = { false, false, true, true, true, true, false, false, - false, false, true, true, true, true, false, false }; - VEC a(A), b(B), rand(AND), ror(OR), rxor(XOR), rnot(NOT); - OIIO_CHECK_SIMD_EQUAL (a & b, rand); - OIIO_CHECK_SIMD_EQUAL (a | b, ror); - OIIO_CHECK_SIMD_EQUAL (a ^ b, rxor); - OIIO_CHECK_SIMD_EQUAL (~a, rnot); - - VEC onebit(false); onebit.setcomp(3,true); - OIIO_CHECK_EQUAL (reduce_or(VEC::False()), false); - OIIO_CHECK_EQUAL (reduce_or(onebit), true); - OIIO_CHECK_EQUAL (reduce_and(VEC::True()), true); - OIIO_CHECK_EQUAL (reduce_and(onebit), false); - OIIO_CHECK_EQUAL (all(VEC::True()), true); - OIIO_CHECK_EQUAL (any(VEC::True()), true); - OIIO_CHECK_EQUAL (none(VEC::True()), false); - OIIO_CHECK_EQUAL (all(VEC::False()), false); - OIIO_CHECK_EQUAL (any(VEC::False()), false); - OIIO_CHECK_EQUAL (none(VEC::False()), true); - - benchmark2 ("operator&", do_and, a, b); - benchmark2 ("operator|", do_or, a, b); - benchmark2 ("operator^", do_xor, a, b); - benchmark ("operator!", do_compl, a); - benchmark ("reduce_and", [](const VEC& a){ return reduce_and(a); }, a); - benchmark ("reduce_or ", [](const VEC& a){ return reduce_or(a); }, a); -} - - - -template B do_lt (const T& a, const T& b) { return a < b; } -template B do_gt (const T& a, const T& b) { return a > b; } -template B do_le (const T& a, const T& b) { return a <= b; } -template B do_ge (const T& a, const T& b) { return a >= b; } -template B do_eq (const T& a, const T& b) { return a == b; } -template B do_ne (const T& a, const T& b) { return a != b; } - - - -template -void -test_comparisons() -{ - typedef typename VEC::value_t ELEM; - typedef typename VEC::vbool_t bool_t; - test_heading("comparisons ", VEC::type_name()); - - VEC a = VEC::Iota(); - bool lt2[] = { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - bool gt2[] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - bool le2[] = { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - bool ge2[] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - bool eq2[] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - bool ne2[] = { 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - OIIO_CHECK_SIMD_EQUAL((a < 2), bool_t(lt2)); - OIIO_CHECK_SIMD_EQUAL((a > 2), bool_t(gt2)); - OIIO_CHECK_SIMD_EQUAL((a <= 2), bool_t(le2)); - OIIO_CHECK_SIMD_EQUAL((a >= 2), bool_t(ge2)); - OIIO_CHECK_SIMD_EQUAL((a == 2), bool_t(eq2)); - OIIO_CHECK_SIMD_EQUAL((a != 2), bool_t(ne2)); - VEC b(ELEM(2)); - OIIO_CHECK_SIMD_EQUAL((a < b), bool_t(lt2)); - OIIO_CHECK_SIMD_EQUAL((a > b), bool_t(gt2)); - OIIO_CHECK_SIMD_EQUAL((a <= b), bool_t(le2)); - OIIO_CHECK_SIMD_EQUAL((a >= b), bool_t(ge2)); - OIIO_CHECK_SIMD_EQUAL((a == b), bool_t(eq2)); - OIIO_CHECK_SIMD_EQUAL((a != b), bool_t(ne2)); - - benchmark2("operator< ", do_lt, a, b); - benchmark2("operator> ", do_gt, a, b); - benchmark2("operator<=", do_le, a, b); - benchmark2("operator>=", do_ge, a, b); - benchmark2("operator==", do_eq, a, b); - benchmark2("operator!=", do_ne, a, b); -} - - - -template -void -test_shuffle4() -{ - typedef typename VEC::value_t ELEM; - test_heading("shuffle ", VEC::type_name()); - - VEC a(0, 1, 2, 3); - OIIO_CHECK_SIMD_EQUAL((shuffle<3, 2, 1, 0>(a)), VEC(3, 2, 1, 0)); - OIIO_CHECK_SIMD_EQUAL((shuffle<0, 0, 2, 2>(a)), VEC(0, 0, 2, 2)); - OIIO_CHECK_SIMD_EQUAL((shuffle<1, 1, 3, 3>(a)), VEC(1, 1, 3, 3)); - OIIO_CHECK_SIMD_EQUAL((shuffle<0, 1, 0, 1>(a)), VEC(0, 1, 0, 1)); - OIIO_CHECK_SIMD_EQUAL((shuffle<2>(a)), VEC(ELEM(2))); - - benchmark("shuffle<...> ", - [&](const VEC& v) { return shuffle<3, 2, 1, 0>(v); }, a); - benchmark("shuffle<0> ", [&](const VEC& v) { return shuffle<0>(v); }, a); - benchmark("shuffle<1> ", [&](const VEC& v) { return shuffle<1>(v); }, a); - benchmark("shuffle<2> ", [&](const VEC& v) { return shuffle<2>(v); }, a); - benchmark("shuffle<3> ", [&](const VEC& v) { return shuffle<3>(v); }, a); -} - - - -template -void test_shuffle8 () -{ - typedef typename VEC::value_t ELEM; - test_heading ("shuffle ", VEC::type_name()); - VEC a (0, 1, 2, 3, 4, 5, 6, 7); - OIIO_CHECK_SIMD_EQUAL ((shuffle<3,2,1,0,3,2,1,0>(a)), VEC(3,2,1,0,3,2,1,0)); - OIIO_CHECK_SIMD_EQUAL ((shuffle<0,0,2,2,0,0,2,2>(a)), VEC(0,0,2,2,0,0,2,2)); - OIIO_CHECK_SIMD_EQUAL ((shuffle<1,1,3,3,1,1,3,3>(a)), VEC(1,1,3,3,1,1,3,3)); - OIIO_CHECK_SIMD_EQUAL ((shuffle<0,1,0,1,0,1,0,1>(a)), VEC(0,1,0,1,0,1,0,1)); - OIIO_CHECK_SIMD_EQUAL ((shuffle<2>(a)), VEC(ELEM(2))); - - benchmark ("shuffle<...> ", [&](const VEC& v){ return shuffle<7,6,5,4,3,2,1,0>(v); }, a); - benchmark ("shuffle<0> ", [&](const VEC& v){ return shuffle<0>(v); }, a); - benchmark ("shuffle<1> ", [&](const VEC& v){ return shuffle<1>(v); }, a); - benchmark ("shuffle<2> ", [&](const VEC& v){ return shuffle<2>(v); }, a); - benchmark ("shuffle<3> ", [&](const VEC& v){ return shuffle<3>(v); }, a); - benchmark ("shuffle<4> ", [&](const VEC& v){ return shuffle<4>(v); }, a); - benchmark ("shuffle<5> ", [&](const VEC& v){ return shuffle<5>(v); }, a); - benchmark ("shuffle<6> ", [&](const VEC& v){ return shuffle<6>(v); }, a); - benchmark ("shuffle<7> ", [&](const VEC& v){ return shuffle<7>(v); }, a); -} - - - -template -void test_shuffle16 () -{ - test_heading ("shuffle ", VEC::type_name()); - VEC a (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - - // Shuffle groups of 4 - OIIO_CHECK_SIMD_EQUAL ((shuffle4<3,2,1,0>(a)), - VEC(12,13,14,15,8,9,10,11,4,5,6,7,0,1,2,3)); - OIIO_CHECK_SIMD_EQUAL ((shuffle4<3>(a)), - VEC(12,13,14,15,12,13,14,15,12,13,14,15,12,13,14,15)); - - // Shuffle within groups of 4 - OIIO_CHECK_SIMD_EQUAL ((shuffle<3,2,1,0>(a)), - VEC(3,2,1,0,7,6,5,4,11,10,9,8,15,14,13,12)); - OIIO_CHECK_SIMD_EQUAL ((shuffle<3>(a)), - VEC(3,3,3,3,7,7,7,7,11,11,11,11,15,15,15,15)); - - benchmark ("shuffle4<> ", [&](const VEC& v){ return shuffle<3,2,1,0>(v); }, a); - benchmark ("shuffle<> ", [&](const VEC& v){ return shuffle<3,2,1,0>(v); }, a); -} - - - -template -void -test_swizzle() -{ - test_heading("swizzle ", VEC::type_name()); - - VEC a = VEC::Iota(0); - VEC b = VEC::Iota(10); - OIIO_CHECK_SIMD_EQUAL(AxyBxy(a, b), VEC(0, 1, 10, 11)); - OIIO_CHECK_SIMD_EQUAL(AxBxAyBy(a, b), VEC(0, 10, 1, 11)); - OIIO_CHECK_SIMD_EQUAL(b.xyz0(), VEC(10, 11, 12, 0)); - OIIO_CHECK_SIMD_EQUAL(b.xyz1(), VEC(10, 11, 12, 1)); -} - - - -template -void test_blend () -{ - test_heading ("blend ", VEC::type_name()); - typedef typename VEC::value_t ELEM; - typedef typename VEC::vbool_t bool_t; - - VEC a = VEC::Iota (1); - VEC b = VEC::Iota (10); - bool_t f(false), t(true); - bool tf_values[] = { true, false, true, false, true, false, true, false, - true, false, true, false, true, false, true, false }; - bool_t tf ((bool *)tf_values); - - OIIO_CHECK_SIMD_EQUAL (blend (a, b, f), a); - OIIO_CHECK_SIMD_EQUAL (blend (a, b, t), b); - - ELEM r1[] = { 10, 2, 12, 4, 14, 6, 16, 8, 18, 10, 20, 12, 22, 14, 24, 16 }; - OIIO_CHECK_SIMD_EQUAL (blend (a, b, tf), VEC(r1)); - - OIIO_CHECK_SIMD_EQUAL (blend0 (a, f), VEC::Zero()); - OIIO_CHECK_SIMD_EQUAL (blend0 (a, t), a); - ELEM r2[] = { 1, 0, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 0, 15, 0 }; - OIIO_CHECK_SIMD_EQUAL (blend0 (a, tf), VEC(r2)); - - OIIO_CHECK_SIMD_EQUAL (blend0not (a, f), a); - OIIO_CHECK_SIMD_EQUAL (blend0not (a, t), VEC::Zero()); - ELEM r3[] = { 0, 2, 0, 4, 0, 6, 0, 8, 0, 10, 0, 12, 0, 14, 0, 16 }; - OIIO_CHECK_SIMD_EQUAL (blend0not (a, tf), VEC(r3)); - - benchmark2 ("blend", [&](const VEC& a, const VEC& b){ return blend(a,b,tf); }, a, b); - benchmark2 ("blend0", [](const VEC& a, const bool_t& b){ return blend0(a,b); }, a, tf); - benchmark2 ("blend0not", [](const VEC& a, const bool_t& b){ return blend0not(a,b); }, a, tf); -} - - - -template -void -test_transpose4() -{ - test_heading("transpose ", VEC::type_name()); - - VEC a(0, 1, 2, 3); - VEC b(4, 5, 6, 7); - VEC c(8, 9, 10, 11); - VEC d(12, 13, 14, 15); - - OIIO_CHECK_SIMD_EQUAL(AxBxCxDx(a, b, c, d), VEC(0, 4, 8, 12)); - - std::cout << " before transpose:\n"; - std::cout << "\t" << a << "\n"; - std::cout << "\t" << b << "\n"; - std::cout << "\t" << c << "\n"; - std::cout << "\t" << d << "\n"; - transpose(a, b, c, d); - std::cout << " after transpose:\n"; - std::cout << "\t" << a << "\n"; - std::cout << "\t" << b << "\n"; - std::cout << "\t" << c << "\n"; - std::cout << "\t" << d << "\n"; - OIIO_CHECK_SIMD_EQUAL(a, VEC(0, 4, 8, 12)); - OIIO_CHECK_SIMD_EQUAL(b, VEC(1, 5, 9, 13)); - OIIO_CHECK_SIMD_EQUAL(c, VEC(2, 6, 10, 14)); - OIIO_CHECK_SIMD_EQUAL(d, VEC(3, 7, 11, 15)); -} - - - -template inline T do_shl (const T &a, int b) { return a< inline T do_shr (const T &a, int b) { return a>>b; } -template inline T do_srl (const T &a, int b) { return srl(a,b); } -template inline T do_rotl (const T &a, int b) { return rotl(a,b); } - - -template -void -test_shift() -{ - test_heading("shift ", VEC::type_name()); - - // Basics of << and >> - VEC i = VEC::Iota(10, 10); // 10, 20, 30 ... - OIIO_CHECK_SIMD_EQUAL(i << 2, VEC::Iota(40, 40)); - OIIO_CHECK_SIMD_EQUAL(i >> 1, VEC::Iota(5, 5)); - - // Tricky cases with high bits, and the difference between >> and srl - int vals[4] = { 1 << 31, -1, 0xffff, 3 }; - for (auto hard : vals) { - VEC vhard(hard); - OIIO_CHECK_SIMD_EQUAL (vhard >> 1, VEC(hard>>1)); - OIIO_CHECK_SIMD_EQUAL (srl(vhard,1), VEC(unsigned(hard)>>1)); - Strutil::print(" [{:x}] >> 1 == [{:x}]\n", vhard, vhard>>1); - Strutil::print(" [{:x}] srl 1 == [{:x}]\n", vhard, srl(vhard,1)); - OIIO_CHECK_SIMD_EQUAL (srl(vhard,4), VEC(unsigned(hard)>>4)); - Strutil::print(" [{:x}] >> 4 == [{:x}]\n", vhard, vhard>>4); - Strutil::print(" [{:x}] srl 4 == [{:x}]\n", vhard, srl(vhard,4)); - } - - // Test <<= and >>= - i = VEC::Iota (10, 10); i <<= 2; - OIIO_CHECK_SIMD_EQUAL (i, VEC::Iota(40, 40)); - i = VEC::Iota (10, 10); i >>= 1; - OIIO_CHECK_SIMD_EQUAL (i, VEC::Iota(5, 5)); - - // Test rotl - { - vint4 v (0x12345678, 0xabcdef01, 0x98765432, 0x31415926); - vint4 r (0x23456781, 0xbcdef01a, 0x87654329, 0x14159263); - OIIO_CHECK_SIMD_EQUAL (rotl(v,4), r); - } - - // Benchmark - benchmark2 ("operator<<", do_shl, i, 2); - benchmark2 ("operator>>", do_shr, i, 2); - benchmark2 ("srl ", do_srl, i, 2); - benchmark2 ("rotl ", do_rotl, i, 2); -} - - - -void -test_vectorops_vfloat4() -{ - typedef vfloat4 VEC; - typedef VEC::value_t ELEM; - test_heading("vectorops ", VEC::type_name()); - - VEC a = mkvec (10, 11, 12, 13); - VEC b = mkvec (1, 2, 3, 4); - OIIO_CHECK_EQUAL (dot(a,b), ELEM(10+22+36+52)); - OIIO_CHECK_EQUAL (dot3(a,b), ELEM(10+22+36)); - OIIO_CHECK_SIMD_EQUAL (vdot(a,b), VEC(10+22+36+52)); - OIIO_CHECK_SIMD_EQUAL (vdot3(a,b), VEC(10+22+36)); - OIIO_CHECK_SIMD_EQUAL (hdiv(vfloat4(1.0f,2.0f,3.0f,2.0f)), vfloat3(0.5f,1.0f,1.5f)); - - benchmark2 ("vdot", [](const VEC& a, const VEC& b){ return vdot(a,b); }, a, b); - benchmark2 ("dot", [](const VEC& a, const VEC& b){ return dot(a,b); }, a, b); - benchmark2 ("vdot3", [](const VEC& a, const VEC& b){ return vdot3(a,b); }, a, b); - benchmark2 ("dot3", [](const VEC& a, const VEC& b){ return dot3(a,b); }, a, b); -} - - - -void test_vectorops_vfloat3 () -{ - typedef vfloat3 VEC; - typedef VEC::value_t ELEM; - test_heading ("vectorops ", VEC::type_name()); - - VEC a = mkvec (10, 11, 12); - VEC b = mkvec (1, 2, 3); - OIIO_CHECK_EQUAL (dot(a,b), ELEM(10+22+36)); - OIIO_CHECK_EQUAL (dot3(a,b), ELEM(10+22+36)); - OIIO_CHECK_SIMD_EQUAL (vdot(a,b), VEC(10+22+36)); - OIIO_CHECK_SIMD_EQUAL (vdot3(a,b), VEC(10+22+36)); - OIIO_CHECK_SIMD_EQUAL (vfloat3(1.0f,2.0f,3.0f).normalized(), - vfloat3(norm_imath(Imath::V3f(1.0f,2.0f,3.0f)))); - OIIO_CHECK_SIMD_EQUAL_THRESH (vfloat3(1.0f,2.0f,3.0f).normalized_fast(), - vfloat3(norm_imath(Imath::V3f(1.0f,2.0f,3.0f))), 0.0005); - - benchmark2 ("vdot", [](const VEC& a, const VEC& b){ return vdot(a,b); }, a, b); - benchmark2 ("dot", [](const VEC& a, const VEC& b){ return dot(a,b); }, a, b); - benchmark ("dot vfloat3", dot_simd, vfloat3(2.0f,1.0f,0.0f), 1); - // benchmark2 ("dot Imath::V3f", [](Imath::V3f& a, Imath::V3f& b){ return a.dot(b); }, a.V3f(), b.V3f()); - benchmark ("dot Imath::V3f", dot_imath, Imath::V3f(2.0f,1.0f,0.0f), 1); - benchmark ("dot Imath::V3f with simd", dot_imath_simd, Imath::V3f(2.0f,1.0f,0.0f), 1); - benchmark ("normalize Imath", norm_imath, Imath::V3f(1.0f,4.0f,9.0f)); - benchmark ("normalize Imath with simd", norm_imath_simd, Imath::V3f(1.0f,4.0f,9.0f)); - benchmark ("normalize Imath with simd fast", norm_imath_simd_fast, Imath::V3f(1.0f,4.0f,9.0f)); - benchmark ("normalize simd", norm_simd, vfloat3(1.0f,4.0f,9.0f)); - benchmark ("normalize simd fast", norm_simd_fast, vfloat3(1.0f,4.0f,9.0f)); -} - - - -void test_constants () -{ - test_heading ("constants"); - - OIIO_CHECK_SIMD_EQUAL (vbool4::False(), vbool4(false)); - OIIO_CHECK_SIMD_EQUAL (vbool4::True(), vbool4(true)); - - OIIO_CHECK_SIMD_EQUAL (vbool8::False(), vbool8(false)); - OIIO_CHECK_SIMD_EQUAL (vbool8::True(), vbool8(true)); - - OIIO_CHECK_SIMD_EQUAL (vbool16::False(), vbool16(false)); - OIIO_CHECK_SIMD_EQUAL (vbool16::True(), vbool16(true)); - OIIO_CHECK_SIMD_EQUAL (vbool16::False(), vbool16(false)); - OIIO_CHECK_SIMD_EQUAL (vbool16::True(), vbool16(true)); - - OIIO_CHECK_SIMD_EQUAL (vint4::Zero(), vint4(0)); - OIIO_CHECK_SIMD_EQUAL (vint4::One(), vint4(1)); - OIIO_CHECK_SIMD_EQUAL (vint4::NegOne(), vint4(-1)); - OIIO_CHECK_SIMD_EQUAL (vint4::Iota(), vint4(0,1,2,3)); - OIIO_CHECK_SIMD_EQUAL (vint4::Iota(3), vint4(3,4,5,6)); - OIIO_CHECK_SIMD_EQUAL (vint4::Iota(3,2), vint4(3,5,7,9)); - OIIO_CHECK_SIMD_EQUAL (vint4::Giota(), vint4(1,2,4,8)); - - OIIO_CHECK_SIMD_EQUAL (vint8::Zero(), vint8(0)); - OIIO_CHECK_SIMD_EQUAL (vint8::One(), vint8(1)); - OIIO_CHECK_SIMD_EQUAL (vint8::NegOne(), vint8(-1)); - OIIO_CHECK_SIMD_EQUAL (vint8::Iota(), vint8(0,1,2,3, 4,5,6,7)); - OIIO_CHECK_SIMD_EQUAL (vint8::Iota(3), vint8(3,4,5,6, 7,8,9,10)); - OIIO_CHECK_SIMD_EQUAL (vint8::Iota(3,2), vint8(3,5,7,9, 11,13,15,17)); - OIIO_CHECK_SIMD_EQUAL (vint8::Giota(), vint8(1,2,4,8, 16,32,64,128)); - - OIIO_CHECK_SIMD_EQUAL (vint16::Zero(), vint16(0)); - OIIO_CHECK_SIMD_EQUAL (vint16::One(), vint16(1)); - OIIO_CHECK_SIMD_EQUAL (vint16::NegOne(), vint16(-1)); - OIIO_CHECK_SIMD_EQUAL (vint16::Iota(), vint16(0,1,2,3, 4,5,6,7, 8,9,10,11, 12,13,14,15)); - OIIO_CHECK_SIMD_EQUAL (vint16::Iota(3), vint16(3,4,5,6, 7,8,9,10, 11,12,13,14, 15,16,17,18)); - OIIO_CHECK_SIMD_EQUAL (vint16::Iota(3,2), vint16(3,5,7,9, 11,13,15,17, 19,21,23,25, 27,29,31,33)); - OIIO_CHECK_SIMD_EQUAL (vint16::Giota(), vint16(1,2,4,8, 16,32,64,128, 256,512,1024,2048, 4096,8192,16384,32768)); - - OIIO_CHECK_SIMD_EQUAL (vfloat4::Zero(), vfloat4(0.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4::One(), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4::Iota(), vfloat4(0,1,2,3)); - OIIO_CHECK_SIMD_EQUAL (vfloat4::Iota(3.0f), vfloat4(3,4,5,6)); - OIIO_CHECK_SIMD_EQUAL (vfloat4::Iota(3.0f,2.0f), vfloat4(3,5,7,9)); - - OIIO_CHECK_SIMD_EQUAL (vfloat3::Zero(), vfloat3(0.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat3::One(), vfloat3(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat3::Iota(), vfloat3(0,1,2)); - OIIO_CHECK_SIMD_EQUAL (vfloat3::Iota(3.0f), vfloat3(3,4,5)); - OIIO_CHECK_SIMD_EQUAL (vfloat3::Iota(3.0f,2.0f), vfloat3(3,5,7)); - - OIIO_CHECK_SIMD_EQUAL (vfloat8::Zero(), vfloat8(0.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat8::One(), vfloat8(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat8::Iota(), vfloat8(0,1,2,3,4,5,6,7)); - OIIO_CHECK_SIMD_EQUAL (vfloat8::Iota(3.0f), vfloat8(3,4,5,6,7,8,9,10)); - OIIO_CHECK_SIMD_EQUAL (vfloat8::Iota(3.0f,2.0f), vfloat8(3,5,7,9,11,13,15,17)); - - OIIO_CHECK_SIMD_EQUAL (vfloat16::Zero(), vfloat16(0.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat16::One(), vfloat16(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat16::Iota(), vfloat16(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)); - OIIO_CHECK_SIMD_EQUAL (vfloat16::Iota(3.0f), vfloat16(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18)); - OIIO_CHECK_SIMD_EQUAL (vfloat16::Iota(3.0f,2.0f), vfloat16(3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33)); - - benchmark ("vfloat4 = float(const)", [](float f){ return vfloat4(f); }, 1.0f); - benchmark ("vfloat4 = Zero()", [](int){ return vfloat4::Zero(); }, 0); - benchmark ("vfloat4 = One()", [](int){ return vfloat4::One(); }, 0); - benchmark ("vfloat4 = Iota()", [](int){ return vfloat4::Iota(); }, 0); - - benchmark ("vfloat8 = float(const)", [](float f){ return vfloat8(f); }, 1.0f); - benchmark ("vfloat8 = Zero()", [](int){ return vfloat8::Zero(); }, 0); - benchmark ("vfloat8 = One()", [](int){ return vfloat8::One(); }, 0); - benchmark ("vfloat8 = Iota()", [](int){ return vfloat8::Iota(); }, 0); - - benchmark ("vfloat16 = float(const)", [](float f){ return vfloat16(f); }, 1.0f); - benchmark ("vfloat16 = Zero()", [](int){ return vfloat16::Zero(); }, 0); - benchmark ("vfloat16 = One()", [](int){ return vfloat16::One(); }, 0); - benchmark ("vfloat16 = Iota()", [](int){ return vfloat16::Iota(); }, 0); -} - - - -// Miscellaneous one-off stuff not caught by other tests -void -test_special() -{ - test_heading("special"); - { - // Make sure a vfloat4 constructed from saturated unsigned short, - // short, unsigned char, or char values, then divided by the float - // max, exactly equals 1.0. - short s32767[] = {32767, 32767, 32767, 32767}; - unsigned short us65535[] = {65535, 65535, 65535, 65535}; - char c127[] = {127, 127, 127, 127}; - unsigned char uc255[] = {255, 255, 255, 255}; - OIIO_CHECK_SIMD_EQUAL (vfloat4(us65535)/vfloat4(65535.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(us65535)*vfloat4(1.0f/65535.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(s32767)/vfloat4(32767.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(s32767)*vfloat4(1.0f/32767.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(uc255)/vfloat4(255.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(uc255)*vfloat4(1.0f/255.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(c127)/vfloat4(127.0), vfloat4(1.0f)); - OIIO_CHECK_SIMD_EQUAL (vfloat4(c127)*vfloat4(1.0f/127.0), vfloat4(1.0f)); - } -} - - - -// Wrappers to resolve the return type ambiguity -inline float fast_exp_float (float x) { return fast_exp(x); } -inline vfloat4 fast_exp_vfloat4 (const vfloat4& x) { return fast_exp(x); } -inline float fast_log_float (float x) { return fast_log(x); } -//inline vfloat4 fast_log_float (const vfloat4& x) { return fast_log(x); } -inline float rsqrtf (float f) { return 1.0f / sqrtf(f); } -inline float rcp (float f) { return 1.0f / f; } - - - -template -void test_mathfuncs () -{ - typedef typename VEC::vint_t vint_t; - test_heading ("mathfuncs", VEC::type_name()); - - VEC F = mkvec (-1.5f, 0.0f, 1.9f, 4.1f); - OIIO_CHECK_SIMD_EQUAL (abs(F), mkvec(std::abs(F[0]), std::abs(F[1]), std::abs(F[2]), std::abs(F[3]))); - // OIIO_CHECK_SIMD_EQUAL (sign(F), mkvec(std::sign(F[0]), std::sign(F[1]), std::sign(F[2]), std::sign(F[3]))); - OIIO_CHECK_SIMD_EQUAL (ceil(F), mkvec(std::ceil(F[0]), std::ceil(F[1]), std::ceil(F[2]), std::ceil(F[3]))); - OIIO_CHECK_SIMD_EQUAL (floor(F), mkvec(std::floor(F[0]), std::floor(F[1]), std::floor(F[2]), std::floor(F[3]))); - OIIO_CHECK_SIMD_EQUAL (round(F), mkvec(std::round(F[0]), std::round(F[1]), std::round(F[2]), std::round(F[3]))); - benchmark ("simd abs", [](const VEC& v){ return abs(v); }, 1.1f); - benchmark ("simd sign", [](const VEC& v){ return sign(v); }, 1.1f); - benchmark ("simd ceil", [](const VEC& v){ return ceil(v); }, 1.1f); - benchmark ("simd floor", [](const VEC& v){ return floor(v); }, 1.1f); - benchmark ("simd round", [](const VEC& v){ return round(v); }, 1.1f); - - VEC A = mkvec (-1.0f, 0.0f, 1.0f, 4.5f); - VEC expA = mkvec (0.367879441171442f, 1.0f, 2.718281828459045f, 90.0171313005218f); - OIIO_CHECK_SIMD_EQUAL (exp(A), expA); - OIIO_CHECK_SIMD_EQUAL_THRESH (log(expA), A, 1e-6f); - OIIO_CHECK_SIMD_EQUAL (fast_exp(A), - mkvec(fast_exp(A[0]), fast_exp(A[1]), fast_exp(A[2]), fast_exp(A[3]))); - OIIO_CHECK_SIMD_EQUAL_THRESH (fast_log(expA), - mkvec(fast_log(expA[0]), fast_log(expA[1]), fast_log(expA[2]), fast_log(expA[3])), 0.00001f); - OIIO_CHECK_SIMD_EQUAL_THRESH (fast_pow_pos(VEC(2.0f), A), - mkvec(0.5f, 1.0f, 2.0f, 22.62741699796952f), 0.0001f); - - OIIO_CHECK_SIMD_EQUAL (safe_div(mkvec(1.0f,2.0f,3.0f,4.0f), mkvec(2.0f,0.0f,2.0f,0.0f)), - mkvec(0.5f,0.0f,1.5f,0.0f)); - OIIO_CHECK_SIMD_EQUAL_THRESH (sqrt(mkvec(1.0f,4.0f,9.0f,16.0f)), mkvec(1.0f,2.0f,3.0f,4.0f), 0.00001); - OIIO_CHECK_SIMD_EQUAL_THRESH (rsqrt(mkvec(1.0f,4.0f,9.0f,16.0f)), VEC(1.0f)/mkvec(1.0f,2.0f,3.0f,4.0f), 0.00001); - OIIO_CHECK_SIMD_EQUAL_THRESH (rsqrt_fast(mkvec(1.0f,4.0f,9.0f,16.0f)), - VEC(1.0f)/mkvec(1.0f,2.0f,3.0f,4.0f), 0.0005f); - OIIO_CHECK_SIMD_EQUAL_THRESH (rcp_fast(VEC::Iota(1.0f)), - VEC(1.0f)/VEC::Iota(1.0f), 0.0005f); - - benchmark2 ("simd operator/", do_div, A, A); - benchmark2 ("simd safe_div", do_safe_div, A, A); - benchmark ("simd rcp_fast", [](const VEC& v){ return rcp_fast(v); }, mkvec(1.0f,4.0f,9.0f,16.0f)); - - OIIO_CHECK_SIMD_EQUAL (ifloor(mkvec(0.0f, 0.999f, 1.0f, 1.001f)), - mkvec(0, 0, 1, 1)); - OIIO_CHECK_SIMD_EQUAL (ifloor(mkvec(0.0f, -0.999f, -1.0f, -1.001f)), - mkvec(0, -1, -1, -2)); - benchmark ("float ifloor", [](float&v){ return ifloor(v); }, 1.1f); - benchmark ("simd ifloor", [](const VEC&v){ return simd::ifloor(v); }, VEC(1.1f)); - - int iscalar; - vint_t ival; - VEC fval = -1.1; - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(0.0f), &ival), 0.0f); OIIO_CHECK_SIMD_EQUAL (ival, 0); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(-0.999f), &ival), 0.001f); OIIO_CHECK_SIMD_EQUAL (ival, -1); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(-1.0f), &ival), 0.0f); OIIO_CHECK_SIMD_EQUAL (ival, -1); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(-1.001f), &ival), 0.999f); OIIO_CHECK_SIMD_EQUAL (ival, -2); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(0.999f), &ival), 0.999f); OIIO_CHECK_SIMD_EQUAL (ival, 0); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(1.0f), &ival), 0.0f); OIIO_CHECK_SIMD_EQUAL (ival, 1); - OIIO_CHECK_EQUAL_APPROX (floorfrac(VEC(1.001f), &ival), 0.001f); OIIO_CHECK_SIMD_EQUAL (ival, 1); - benchmark ("float floorfrac", [&](float x){ return DoNotOptimize(floorfrac(x,&iscalar)); }, 1.1f); - benchmark ("simd floorfrac", [&](const VEC& x){ return DoNotOptimize(floorfrac(x,&ival)); }, fval); - - benchmark ("float expf", expf, 0.67f); - benchmark ("float fast_exp", fast_exp_float, 0.67f); - benchmark ("simd exp", [](const VEC& v){ return simd::exp(v); }, VEC(0.67f)); - benchmark ("simd fast_exp", [](const VEC& v){ return fast_exp(v); }, VEC(0.67f)); - - benchmark ("float logf", logf, 0.67f); - benchmark ("fast_log", fast_log_float, 0.67f); - benchmark ("simd log", [](const VEC& v){ return simd::log(v); }, VEC(0.67f)); - benchmark ("simd fast_log", fast_log, VEC(0.67f)); - benchmark2 ("float powf", powf, 0.67f, 0.67f); - benchmark2 ("simd fast_pow_pos", [](const VEC& x,const VEC& y){ return fast_pow_pos(x,y); }, VEC(0.67f), VEC(0.67f)); - benchmark ("float sqrt", sqrtf, 4.0f); - benchmark ("simd sqrt", [](const VEC& v){ return sqrt(v); }, mkvec(1.0f,4.0f,9.0f,16.0f)); - benchmark ("float rsqrt", rsqrtf, 4.0f); - benchmark ("simd rsqrt", [](const VEC& v){ return rsqrt(v); }, mkvec(1.0f,4.0f,9.0f,16.0f)); - benchmark ("simd rsqrt_fast", [](const VEC& v){ return rsqrt_fast(v); }, mkvec(1.0f,4.0f,9.0f,16.0f)); -} - - - -void test_metaprogramming () -{ - test_heading ("metaprogramming"); - OIIO_CHECK_EQUAL (SimdSize::size, 4); - OIIO_CHECK_EQUAL (SimdSize::size, 4); - OIIO_CHECK_EQUAL (SimdSize::size, 4); - OIIO_CHECK_EQUAL (SimdSize::size, 4); - OIIO_CHECK_EQUAL (SimdSize::size, 8); - OIIO_CHECK_EQUAL (SimdSize::size, 8); - OIIO_CHECK_EQUAL (SimdSize::size, 8); - OIIO_CHECK_EQUAL (SimdSize::size, 16); - OIIO_CHECK_EQUAL (SimdSize::size, 16); - OIIO_CHECK_EQUAL (SimdSize::size, 16); - OIIO_CHECK_EQUAL (SimdSize::size, 1); - OIIO_CHECK_EQUAL (SimdSize::size, 1); - OIIO_CHECK_EQUAL (SimdSize::size, 1); - - OIIO_CHECK_EQUAL (SimdElements::size, 4); - OIIO_CHECK_EQUAL (SimdElements::size, 3); - OIIO_CHECK_EQUAL (SimdElements::size, 4); - OIIO_CHECK_EQUAL (SimdElements::size, 4); - OIIO_CHECK_EQUAL (SimdElements::size, 8); - OIIO_CHECK_EQUAL (SimdElements::size, 8); - OIIO_CHECK_EQUAL (SimdElements::size, 8); - OIIO_CHECK_EQUAL (SimdElements::size, 16); - OIIO_CHECK_EQUAL (SimdElements::size, 16); - OIIO_CHECK_EQUAL (SimdElements::size, 16); - OIIO_CHECK_EQUAL (SimdElements::size, 1); - OIIO_CHECK_EQUAL (SimdElements::size, 1); - OIIO_CHECK_EQUAL (SimdElements::size, 1); - - OIIO_CHECK_EQUAL (vfloat4::elements, 4); - OIIO_CHECK_EQUAL (vfloat3::elements, 3); - OIIO_CHECK_EQUAL (vint4::elements, 4); - OIIO_CHECK_EQUAL (vbool4::elements, 4); - // OIIO_CHECK_EQUAL (vfloat8::elements, 8); - OIIO_CHECK_EQUAL (vint8::elements, 8); - OIIO_CHECK_EQUAL (vbool8::elements, 8); - OIIO_CHECK_EQUAL (vfloat16::elements, 16); - OIIO_CHECK_EQUAL (vint16::elements, 16); - OIIO_CHECK_EQUAL (vbool16::elements, 16); - - // Make sure that VTYPE::value_t returns the right element type - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - - // Make sure that VTYPE::vfloat_t returns the same-sized float type - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - - // Make sure that VTYPE::vint_t returns the same-sized int type - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - - // Make sure that VTYPE::vbool_t returns the same-sized bool type - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT((std::is_same::value)); -} - - - -// Transform a point by a matrix using regular Imath -inline Imath::V3f -transformp_imath(const Imath::V3f& v, const Imath::M44f& m) -{ - Imath::V3f r; - m.multVecMatrix(v, r); - return r; -} - -// Transform a point by a matrix using simd ops on Imath types. -inline Imath::V3f -transformp_imath_simd(const Imath::V3f& v, const Imath::M44f& m) -{ - return simd::transformp(m, v).V3f(); -} - -// Transform a simd point by an Imath matrix using SIMD -inline vfloat3 -transformp_simd(const vfloat3& v, const Imath::M44f& m) -{ - return simd::transformp(m, v); -} - -// Transform a point by a matrix using regular Imath -inline Imath::V3f -transformv_imath(const Imath::V3f& v, const Imath::M44f& m) -{ - Imath::V3f r; - m.multDirMatrix(v, r); - return r; -} - -inline Imath::V4f -mul_vm_imath(const Imath::V4f& v, const Imath::M44f& m) -{ - return v*m; -} - -// inline Imath::V4f -// mul_mv_imath(const Imath::M44f& m, const Imath::V4f& v) -// { -// return m*v; -// } - -inline vfloat4 -mul_vm_simd(const vfloat4& v, const matrix44& m) -{ - return v*m; -} - -inline vfloat4 -mul_mv_simd(const matrix44& m, const vfloat4 v) -{ - return m*v; -} - - - -inline bool -mx_equal_thresh(const matrix44& a, const matrix44& b, float thresh) -{ - for (int j = 0; j < 4; ++j) - for (int i = 0; i < 4; ++i) - if (fabsf(a[j][i] - b[j][i]) > thresh) - return false; - return true; -} - - - -inline Imath::M44f -mat_transpose(const Imath::M44f& m) -{ - return m.transposed(); -} - -inline Imath::M44f -mat_transpose_simd(const Imath::M44f& m) -{ - return matrix44(m).transposed().M44f(); -} - - - -void -test_matrix() -{ - Imath::V3f P(1.0f, 0.0f, 0.0f); - Imath::M44f Mtrans(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 11, 12, 1); - Imath::M44f Mrot = Imath::M44f().rotate(Imath::V3f(0.0f, M_PI_2, 0.0f)); - - test_heading("Testing matrix ops:"); - std::cout << " P = " << P << "\n"; - std::cout << " Mtrans = " << Mtrans << "\n"; - std::cout << " Mrot = " << Mrot << "\n"; - OIIO_CHECK_EQUAL(simd::transformp(Mtrans, P).V3f(), - transformp_imath(P, Mtrans)); - std::cout << " P translated = " << simd::transformp(Mtrans, P) << "\n"; - OIIO_CHECK_EQUAL(simd::transformv(Mtrans, P).V3f(), P); - OIIO_CHECK_EQUAL(simd::transformp(Mrot, P).V3f(), - transformp_imath(P, Mrot)); - std::cout << " P rotated = " << simd::transformp(Mrot, P) << "\n"; - OIIO_CHECK_EQUAL(simd::transformvT(Mrot, P).V3f(), - transformv_imath(P, Mrot.transposed())); - std::cout << " P rotated by the transpose = " << simd::transformv(Mrot, P) - << "\n"; - OIIO_CHECK_EQUAL(matrix44(Mrot).transposed().M44f(), Mrot.transposed()); - std::cout << " Mrot transposed = " << matrix44(Mrot).transposed().M44f() - << "\n"; - - // Test m44 * v4, v4 * m44 - { - Imath::M44f M(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); - matrix44 m(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16); - Imath::V4f V(1,2,3,4); - vfloat4 v(1,2,3,4); - vfloat4 vm = v*m; - OIIO_CHECK_SIMD_EQUAL(vm, vfloat4(V*M)); - // vfloat4 mv = m*v; - // OIIO_CHECK_SIMD_EQUAL(mv, M*V); - benchmark2("V4 * M44 Imath", mul_vm_imath, V, M, 1); - // benchmark2("M44 * V4 Imath", mul_mv_imath, mx, v4x, 1); - benchmark2("M44 * V4 simd", mul_mv_simd, m, v, 1); - benchmark2("V4 * M44 simd", mul_vm_simd, v, m, 1); - } - - // Test ==, != - { - matrix44 mt(Mtrans), mr(Mrot); - OIIO_CHECK_EQUAL(mt, mt); - OIIO_CHECK_EQUAL(mt, Mtrans); - OIIO_CHECK_EQUAL(Mtrans, mt); - OIIO_CHECK_NE(mt, mr); - OIIO_CHECK_NE(mr, Mtrans); - OIIO_CHECK_NE(Mtrans, mr); - } - OIIO_CHECK_ASSERT( - mx_equal_thresh(matrix44(Mtrans.inverse()), matrix44(Mtrans).inverse(), - 1.0e-6f)); - OIIO_CHECK_ASSERT( - mx_equal_thresh(matrix44(Mrot.inverse()), matrix44(Mrot).inverse(), - 1.0e-6f)); - OIIO_CHECK_EQUAL( - matrix44(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), - Imath::M44f(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); - - Imath::V3f vx(2.51f, 1.0f, 1.0f); - Imath::M44f mx(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 10, 11, 12, 1); - benchmark2("transformp Imath", transformp_imath, vx, mx, 1); - benchmark2("transformp Imath with simd", transformp_imath_simd, vx, mx, 1); - benchmark2("transformp simd", transformp_simd, vfloat3(vx), mx, 1); - - benchmark("transpose m44", mat_transpose, mx, 1); - benchmark("transpose m44 with simd", mat_transpose_simd, mx, 1); - // Reduce the iterations of the ones below, if we can - iterations /= 2; - benchmark("m44 inverse Imath", inverse_imath, mx, 1); - // std::cout << "inv " << matrix44(inverse_imath(mx)) << "\n"; - benchmark("m44 inverse_simd", inverse_simd, matrix44(mx), 1); - // std::cout << "inv " << inverse_simd(mx) << "\n"; - benchmark("m44 inverse_simd native simd", inverse_simd, matrix44(mx), 1); - // std::cout << "inv " << inverse_simd(mx) << "\n"; - iterations *= 2; // put things the way they were -} - - - -int -main(int argc, char* argv[]) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - for (int i = 0; i < 16; ++i) { - dummy_float[i] = 1.0f; - dummy_int[i] = 1; - } - - getargs(argc, argv); - - std::string oiiosimd = OIIO::get_string_attribute("oiio:simd"); - std::string hwsimd = OIIO::get_string_attribute("hw:simd"); - std::cout << "OIIO SIMD support is: " << (oiiosimd.size() ? oiiosimd : "") - << "\n"; - std::cout << "Hardware SIMD support is: " << (hwsimd.size() ? hwsimd : "") - << "\n"; - std::cout << "\n"; - - Timer timer; - - vint4 dummy4(0); - vint8 dummy8(0); - benchmark("null benchmark 4", [](const vint4&) { return int(0); }, dummy4); - benchmark("null benchmark 8", [](const vint8&) { return int(0); }, dummy8); - - category_heading("vfloat4"); - test_loadstore(); - test_conversion_loadstore_float(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_comparisons(); - test_shuffle4(); - test_swizzle(); - test_blend(); - test_transpose4(); - test_vectorops_vfloat4(); - test_fused(); - test_mathfuncs(); - - category_heading("vfloat3"); - test_loadstore(); - test_conversion_loadstore_float(); - test_component_access(); - test_arithmetic(); - // Unnecessary to test these, they just use the vfloat4 ops. - // test_comparisons (); - // test_shuffle4 (); - // test_swizzle (); - // test_blend (); - // test_transpose4 (); - test_vectorops_vfloat3(); - test_fused(); - // test_mathfuncs(); - - category_heading("vfloat8"); - test_loadstore(); - test_conversion_loadstore_float(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_comparisons(); - test_shuffle8(); - test_blend(); - test_fused(); - test_mathfuncs(); - - category_heading("vfloat16"); - test_loadstore(); - test_conversion_loadstore_float(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_comparisons(); - test_shuffle16(); - test_blend(); - test_fused(); - test_mathfuncs(); - - category_heading("vint4"); - test_loadstore(); - test_conversion_loadstore_int(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_bitwise_int(); - test_comparisons(); - test_shuffle4(); - test_blend(); - test_vint_to_uint16s(); - test_vint_to_uint8s(); - test_shift(); - test_transpose4(); - - category_heading("vint8"); - test_loadstore(); - test_conversion_loadstore_int(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_bitwise_int(); - test_comparisons(); - test_shuffle8(); - test_blend(); - test_vint_to_uint16s(); - test_vint_to_uint8s(); - test_shift(); - - category_heading("vint16"); - test_loadstore(); - test_conversion_loadstore_int(); - test_masked_loadstore(); - test_gatherscatter(); - test_component_access(); - test_arithmetic(); - test_bitwise_int(); - test_comparisons(); - test_shuffle16(); - test_blend(); - test_vint_to_uint16s(); - test_vint_to_uint8s(); - test_shift(); - - category_heading("vbool4"); - test_shuffle4(); - test_component_access(); - test_bitwise_bool(); - - category_heading("vbool8"); - test_shuffle8(); - test_component_access(); - test_bitwise_bool(); - - category_heading("vbool16"); - // test_shuffle16 (); - test_component_access(); - test_bitwise_bool(); - - category_heading("Odds and ends"); - test_constants(); - test_special(); - test_metaprogramming(); - test_matrix(); - - std::cout << "\nTotal time: " << Strutil::timeintervalformat(timer()) - << "\n"; - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/span_test.cpp b/Sources/OpenImageIO/libutil/span_test.cpp deleted file mode 100644 index e1d1d9bd..00000000 --- a/Sources/OpenImageIO/libutil/span_test.cpp +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace OIIO; - - - -void -test_span() -{ - static float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0 }; - cspan a(A); - OIIO_CHECK_EQUAL(a.size(), 12); - OIIO_CHECK_EQUAL(std::size(a), size_t(12)); - OIIO_CHECK_EQUAL(std::ssize(a), int(12)); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); - - OIIO_CHECK_EQUAL(&a.front(), &a[0]); - OIIO_CHECK_EQUAL(&a.back(), &a[a.size() - 1]); - - OIIO_CHECK_EQUAL(a.begin(), &a[0]); - OIIO_CHECK_EQUAL(a.end(), &a[a.size()]); - OIIO_CHECK_EQUAL(a.cbegin(), &a[0]); - OIIO_CHECK_EQUAL(a.cend(), &a[a.size()]); - - span::const_iterator i = a.begin(); - OIIO_CHECK_EQUAL(*i, 0.0f); - ++i; - OIIO_CHECK_EQUAL(*i, 1.0f); - - // Test == and != - float v12[] = { 1, 2 }; - float v123[] = { 1, 2, 3 }; - float v124[] = { 1, 2, 4 }; - OIIO_CHECK_ASSERT(cspan(v123) == cspan(v123)); - OIIO_CHECK_ASSERT(false == (cspan(v123) != cspan(v123))); - OIIO_CHECK_ASSERT(cspan(v123) != cspan(v12)); - OIIO_CHECK_ASSERT(false == (cspan(v123) == cspan(v12))); - OIIO_CHECK_ASSERT(cspan(v123) != cspan(v124)); -} - - - -void -test_span_mutable() -{ - float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0 }; - span a(A); - OIIO_CHECK_EQUAL(a.size(), 12); - OIIO_CHECK_EQUAL(std::size(a), size_t(12)); - OIIO_CHECK_EQUAL(std::ssize(a), int(12)); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); - - OIIO_CHECK_EQUAL(&a.front(), &a[0]); - OIIO_CHECK_EQUAL(&a.back(), &a[a.size() - 1]); - - a[2] = 42.0f; - OIIO_CHECK_EQUAL(a[2], 42.0f); - // span::const_iterator i = a.begin(); - // OIIO_CHECK_EQUAL (*i, 0.0f); - // ++i; OIIO_CHECK_EQUAL (*i, 1.0f); -} - - - -void -test_span_initlist_called(cspan a) -{ - OIIO_CHECK_EQUAL(a.size(), 12); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); -} - - - -void -test_span_initlist() -{ - // Exercise the span syntax with initializer_list. - test_span_initlist_called({ 0.0f, 1.0f, 0.0f, 2.0f, 0.0f, 3.0f, 0.0f, 4.0f, - 0.0f, 5.0f, 0.0f, 0.0f }); -} - - - -void -test_span_vector() -{ - // Try the span syntax with a view of a std::vector - std::vector arr { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0 }; - - span a(arr); - OIIO_CHECK_EQUAL(a.size(), 12); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); -} - - - -void -test_span_stdarray() -{ - // Try the span syntax with a view of a std::vector - std::array arr { { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0 } }; - - span a(arr); - OIIO_CHECK_EQUAL(a.size(), 12); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); -} - - - -void -test_const_strided_ptr() -{ - static const float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; - - // Make sure it works with unit stride - strided_ptr a(A); - OIIO_CHECK_EQUAL(*a, 0.0f); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); - - // All the other tests are with stride of 2 elements - a = strided_ptr(&A[1], 2); - OIIO_CHECK_EQUAL(*a, 1.0f); - OIIO_CHECK_EQUAL(a[0], 1.0f); - OIIO_CHECK_EQUAL(a[1], 2.0f); - OIIO_CHECK_EQUAL(a[2], 3.0f); - OIIO_CHECK_EQUAL(a[3], 4.0f); - - ++a; - OIIO_CHECK_EQUAL(*a, 2.0f); - a++; - OIIO_CHECK_EQUAL(*a, 3.0f); - ++a; - OIIO_CHECK_EQUAL(*a, 4.0f); - --a; - OIIO_CHECK_EQUAL(*a, 3.0f); - a--; - OIIO_CHECK_EQUAL(*a, 2.0f); - a += 2; - OIIO_CHECK_EQUAL(*a, 4.0f); - a -= 2; - OIIO_CHECK_EQUAL(*a, 2.0f); - a = a + 2; - OIIO_CHECK_EQUAL(*a, 4.0f); - a = a - 2; - OIIO_CHECK_EQUAL(*a, 2.0f); -} - - - -void -test_strided_ptr() -{ - static float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; - - // Make sure it works with unit stride - strided_ptr a(A); - OIIO_CHECK_EQUAL(*a, 0.0f); - OIIO_CHECK_EQUAL(a[0], 0.0f); - OIIO_CHECK_EQUAL(a[1], 1.0f); - OIIO_CHECK_EQUAL(a[2], 0.0f); - OIIO_CHECK_EQUAL(a[3], 2.0f); - - // All the other tests are with stride of 2 elements - a = strided_ptr(&A[1], 2); - OIIO_CHECK_EQUAL(*a, 1.0f); - OIIO_CHECK_EQUAL(a[0], 1.0f); - OIIO_CHECK_EQUAL(a[1], 2.0f); - OIIO_CHECK_EQUAL(a[2], 3.0f); - OIIO_CHECK_EQUAL(a[3], 4.0f); - - ++a; - OIIO_CHECK_EQUAL(*a, 2.0f); - a++; - OIIO_CHECK_EQUAL(*a, 3.0f); - ++a; - OIIO_CHECK_EQUAL(*a, 4.0f); - --a; - OIIO_CHECK_EQUAL(*a, 3.0f); - a--; - OIIO_CHECK_EQUAL(*a, 2.0f); - a += 2; - OIIO_CHECK_EQUAL(*a, 4.0f); - a -= 2; - OIIO_CHECK_EQUAL(*a, 2.0f); - a = a + 2; - OIIO_CHECK_EQUAL(*a, 4.0f); - a = a - 2; - OIIO_CHECK_EQUAL(*a, 2.0f); - - *a = 14.0; - OIIO_CHECK_EQUAL(*a, 14.0f); -} - - - -void -test_span_strided() -{ - static const float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; - span_strided a(&A[1], 5, 2); - OIIO_CHECK_EQUAL(a.size(), 5); - OIIO_CHECK_EQUAL(a[0], 1.0f); - OIIO_CHECK_EQUAL(a[1], 2.0f); - OIIO_CHECK_EQUAL(a[2], 3.0f); - OIIO_CHECK_EQUAL(a[3], 4.0f); - // span_strided::const_iterator i = a.begin(); - // OIIO_CHECK_EQUAL (*i, 1.0f); - // ++i; OIIO_CHECK_EQUAL (*i, 2.0f); -} - - - -void -test_span_strided_mutable() -{ - static float A[] = { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5 }; - span_strided a(&A[1], 5, 2); - OIIO_CHECK_EQUAL(a.size(), 5); - OIIO_CHECK_EQUAL(a[0], 1.0f); - OIIO_CHECK_EQUAL(a[1], 2.0f); - OIIO_CHECK_EQUAL(a[2], 3.0f); - OIIO_CHECK_EQUAL(a[3], 4.0f); - // span_strided::iterator i = a.begin(); - // OIIO_CHECK_EQUAL (*i, 1.0f); - // ++i; OIIO_CHECK_EQUAL (*i, 2.0f); -} - - - -void -test_image_view() -{ - const int X = 4, Y = 3, C = 3, Z = 1; - static const float IMG[Z][Y][X][C] = { - // 4x3 2D image with 3 channels - { { { 0, 0, 0 }, { 1, 0, 1 }, { 2, 0, 2 }, { 3, 0, 3 } }, - { { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 3, 1, 7 } }, - { { 0, 2, 8 }, { 1, 2, 9 }, { 2, 2, 10 }, { 3, 2, 11 } } } - }; - - image_view I((const float*)IMG, 3, 4, 3); - for (int y = 0, i = 0; y < Y; ++y) { - for (int x = 0; x < X; ++x, ++i) { - OIIO_CHECK_EQUAL(I(x, y)[0], x); - OIIO_CHECK_EQUAL(I(x, y)[1], y); - OIIO_CHECK_EQUAL(I(x, y)[2], i); - } - } -} - - - -void -test_image_view_mutable() -{ - const int X = 4, Y = 3, C = 3, Z = 1; - static float IMG[Z][Y][X][C] = { - // 4x3 2D image with 3 channels - { { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, - { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }, - { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } } - }; - - image_view I((float*)IMG, 3, 4, 3); - for (int y = 0, i = 0; y < Y; ++y) { - for (int x = 0; x < X; ++x, ++i) { - I(x, y)[0] = x; - I(x, y)[1] = y; - I(x, y)[2] = i; - } - } - - for (int y = 0, i = 0; y < Y; ++y) { - for (int x = 0; x < X; ++x, ++i) { - OIIO_CHECK_EQUAL(I(x, y)[0], x); - OIIO_CHECK_EQUAL(I(x, y)[1], y); - OIIO_CHECK_EQUAL(I(x, y)[2], i); - } - } -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_span(); - test_span_mutable(); - test_span_initlist(); - test_span_vector(); - test_span_stdarray(); - test_const_strided_ptr(); - test_strided_ptr(); - test_span_strided(); - test_span_strided_mutable(); - test_image_view(); - test_image_view_mutable(); - - // array_view and span should be synonyms - OIIO_CHECK_ASSERT(( - std::is_same, OIIO::array_view>::value)); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/spin_rw_test.cpp b/Sources/OpenImageIO/libutil/spin_rw_test.cpp deleted file mode 100644 index 9b7c319b..00000000 --- a/Sources/OpenImageIO/libutil/spin_rw_test.cpp +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace OIIO; - -// Test spin_rw_mutex by creating a bunch of threads usually just check -// the accumulator value (requiring a read lock), but occasionally -// (1/100 of the time) increment the accumulator, requiring a write -// lock. If, at the end, the accumulated value is equal to -// iterations/read_to_write_ratio*threads, then the locks worked. - -static int read_write_ratio = 99; -static int iterations = 16000000; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; - -long long accum = 0; -spin_rw_mutex mymutex; - - - -static void -do_accum(int iterations) -{ - for (int i = 0; i < iterations; ++i) { - if ((i % (read_write_ratio + 1)) == read_write_ratio) { - spin_rw_write_lock lock(mymutex); - accum += 1; - } else { - spin_rw_read_lock lock(mymutex); - // meaningless test to force examination of the variable - if (accum < 0) - break; - } - } -} - - - -void -test_spin_rw(int numthreads, int iterations) -{ - accum = 0; - thread_group threads; - for (int i = 0; i < numthreads; ++i) { - threads.create_thread(do_accum, iterations); - } - if (verbose) - std::cout << "Created " << threads.size() << " threads\n"; - threads.join_all(); - OIIO_CHECK_EQUAL(accum, (((long long)iterations / (read_write_ratio + 1)) - * (long long)numthreads)); - if (verbose) - std::cout << "it " << iterations << ", r::w = " << read_write_ratio - << ", accum = " << accum << "\n"; -} - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("spin_rw_test\n" OIIO_INTRO_STRING) - .usage("spin_rw_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--rwratio %d", &read_write_ratio) - .help(Strutil::sprintf("Reader::writer ratio (default: %d)", read_write_ratio)); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -int -main(int argc, char* argv[]) -{ - getargs(argc, argv); - - std::cout << "hw threads = " << Sysutil::hardware_concurrency() << "\n"; - std::cout << "reader:writer ratio = " << read_write_ratio << ":1\n"; - std::cout << "threads\ttime (best of " << ntrials << ")\n"; - std::cout << "-------\t----------\n"; - - static int threadcounts[] = { 1, 2, 4, 8, 12, 16, 20, - 24, 28, 32, 64, 128, 1024, 1 << 30 }; - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = threadcounts[i]; - int its = iterations / nt; - - double range; - double t = time_trial(std::bind(test_spin_rw, nt, its), ntrials, - &range); - - Strutil::printf("%2d\t%s\t%5.1fs, range %.1f\t(%d iters/thread)\n", nt, - Strutil::timeintervalformat(t), t, range, its); - if (!wedge) - break; // don't loop if we're not wedging - } - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/spinlock_test.cpp b/Sources/OpenImageIO/libutil/spinlock_test.cpp deleted file mode 100644 index 211a5808..00000000 --- a/Sources/OpenImageIO/libutil/spinlock_test.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -using namespace OIIO; - -// Test spin locks by creating a bunch of threads that all increment the -// accumulator many times, protected by spin locks. If, at the end, the -// accumulated value is equal to iterations*threads, then the spin locks -// worked. - -static int iterations = 40000000; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; - -static spin_mutex print_mutex; // make the prints not clobber each other -long long accum = 0; -float faccum = 0; -spin_mutex mymutex; - - - -static void -time_lock_cycle() -{ - // Find out how long it takes - Benchmarker bench; - std::cout << "Cost of lock/unlock cycle under no contention:\n"; - spin_mutex sm; - std::mutex m; - std::recursive_mutex rm; - bench("spin_mutex", [&]() { - sm.lock(); - sm.unlock(); - }); - bench("std::mutex", [&]() { - m.lock(); - m.unlock(); - }); - bench("std::recursive_mutex", [&]() { - rm.lock(); - rm.unlock(); - }); -} - - - -static void -do_accum(int iterations) -{ - if (verbose) { - spin_lock lock(print_mutex); - std::cout << "thread " << std::this_thread::get_id() - << ", accum = " << accum << "\n"; - } -#if 1 - for (int i = 0; i < iterations; ++i) { - spin_lock lock(mymutex); - accum += 1; - } -#else - // Alternate one that mixes in some math to make longer lock hold time, - // and also more to do between locks. Interesting contrast in timings. - float last = 0.0f; - for (int i = 0; i < iterations; ++i) { - last = fmodf(sinf(last), 1.0f); - spin_lock lock(mymutex); - accum += 1; - faccum = fmod(sinf(faccum + last), 1.0f); - } -#endif -} - - - -static void -getargs(int argc, char* argv[]) -{ - ArgParse ap; - // clang-format off - ap.intro("spinlock_test\n" OIIO_INTRO_STRING) - .usage("spinlock_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -int -main(int argc, char* argv[]) -{ - getargs(argc, argv); - - std::cout << "hw threads = " << Sysutil::hardware_concurrency() << "\n"; - - time_lock_cycle(); - - std::cout << "\nTiming thread contention for spin_mutex...\n"; - if (wedge) - timed_thread_wedge(do_accum, numthreads, iterations, ntrials); - else - timed_thread_wedge(do_accum, numthreads, iterations, ntrials, - numthreads); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/strongparam_test.cpp b/Sources/OpenImageIO/libutil/strongparam_test.cpp deleted file mode 100644 index ea84b883..00000000 --- a/Sources/OpenImageIO/libutil/strongparam_test.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -using namespace OIIO; - -OIIO_STRONG_PARAM_TYPE(Meters, float); -OIIO_STRONG_PARAM_TYPE(Seconds, float); - -// Note: if you don't like using those macros, the following achieves roughly -// equivalent declarations: -// -// using Meters = StrongParam; -// using Seconds = StrongParam; - - -float -speed(Meters a, Seconds b) -{ - return a / b; -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - float s = speed(Meters(8.0f), Seconds(2.0f)); - OIIO_CHECK_EQUAL(s, 4.0f); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/strutil_test.cpp b/Sources/OpenImageIO/libutil/strutil_test.cpp deleted file mode 100644 index 0776acc9..00000000 --- a/Sources/OpenImageIO/libutil/strutil_test.cpp +++ /dev/null @@ -1,1715 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO -// clang-format off - -#include - -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - - - -void -test_format() -{ - std::cout << "testing format()/sprintf()" << std::endl; - - // Test formatting with Strutil::sprintf() - // --------------------------------------- - OIIO_CHECK_EQUAL(Strutil::sprintf("%d %f %g", int(3), 3.14f, 3.14f), - "3 3.140000 3.14"); - OIIO_CHECK_EQUAL(Strutil::sprintf("'%s' '%s'", "foo", std::string("foo")), - "'foo' 'foo'"); - OIIO_CHECK_EQUAL(Strutil::sprintf("'%3d' '%03d' '%-3d'", 3, 3, 3), - "' 3' '003' '3 '"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%+d%+d%+d", 3, -3, 0), "+3-3+0"); - OIIO_CHECK_EQUAL(Strutil::sprintf("foo"), "foo"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%%foo"), "%foo"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%d", int16_t(0xffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%u", uint16_t(0xffff)), "65535"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%d", int32_t(0xffffffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%u", uint32_t(0xffffffff)), "4294967295"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%d", int64_t(0xffffffffffffffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%u", uint64_t(0xffffffffffffffff)), "18446744073709551615"); - -#ifndef OIIO_HIDE_FORMAT - // spot check that Strutil::old::format() is sprintf: - OIIO_CHECK_EQUAL(Strutil::old::format("%d",1), "1"); -#endif - - // Test formatting with Strutil::fmt::format(), which uses the - // Python conventions: - OIIO_CHECK_EQUAL(Strutil::fmt::format("{} {:f} {}", int(3), 3.14f, 3.14f), - "3 3.140000 3.14"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("'{}' '{}'", "foo", std::string("foo")), - "'foo' 'foo'"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("'{:3d}' '{:03d}' '{:<3d}'", 3, 3, 3), - "' 3' '003' '3 '"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{:+d}{:+d}{:+d}", 3, -3, 0), "+3-3+0"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("foo"), "foo"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("%foo"), "%foo"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", short(0xffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", uint16_t(0xffff)), "65535"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", int32_t(0xffffffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", uint32_t(0xffffffff)), "4294967295"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", int64_t(0xffffffffffffffff)), "-1"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", uint64_t(0xffffffffffffffff)), "18446744073709551615"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{} {:f} {:g}", int(3), 3.14f, 3.14f), - "3 3.140000 3.14"); - -#ifndef OIIO_HIDE_FORMAT - // Check that Strutil::format is aliased the right way -# if OIIO_FORMAT_IS_FMT - OIIO_CHECK_EQUAL(Strutil::format("{}", 1), "1"); -# else - OIIO_CHECK_EQUAL(Strutil::format("%d", 1), "1"); -# endif -#endif - - Benchmarker bench; - bench.indent (2); - bench.units (Benchmarker::Unit::ns); - char buffer[256]; - bench ("std::snprintf(\"%g\")", [&](){ DoNotOptimize (std::snprintf(buffer,sizeof(buffer),"%g",123.45f)); }); - bench ("Strutil::sprintf(\"%g\")", [&](){ DoNotOptimize (Strutil::sprintf("%g",123.45f)); }); - bench ("Strutil::fmt::format(\"{:g}\")", [&](){ DoNotOptimize (Strutil::fmt::format("{:g}",123.45f)); }); - bench ("Strutil::to_string(float)", [&](){ DoNotOptimize (Strutil::to_string(123.45f)); }); - - bench ("std::snprintf(\"%d\")", [&](){ DoNotOptimize (std::snprintf(buffer,sizeof(buffer),"%d",123)); }); - bench ("Strutil::sprintf(\"%d\")", [&](){ DoNotOptimize (Strutil::sprintf("%g",123.0f)); }); - bench ("Strutil::fmt::format(\"{}\")", [&](){ DoNotOptimize (Strutil::fmt::format("{}",123)); }); - bench ("Strutil::to_string(int)", [&](){ DoNotOptimize (Strutil::to_string(123)); }); - - bench ("std::snprintf(\"%g %d %s %d %s %g\")", [&](){ - DoNotOptimize (std::snprintf(buffer,sizeof(buffer),"%g %d %s %d %s %g", 123.45f, 1234, "foobar", 42, "kablooey", 3.14159f)); - }); - bench ("Strutil::sprintf(\"%g %d %s %d %s %g\")", [&](){ - DoNotOptimize (Strutil::sprintf("%g %d %s %d %s %g", 123.45f, 1234, "foobar", 42, "kablooey", 3.14159f)); - }); - bench ("Strutil::fmt::format(\"{} {} {} {} {} {}\")", [&](){ - DoNotOptimize (Strutil::fmt::format("{} {} {} {} {} {}", 123.45f, 1234, "foobar", 42, "kablooey", 3.14159f)); - }); -} - - - -void -test_format_custom() -{ - std::cout << "testing format() custom formatters" << std::endl; - - simd::vfloat3 vf3iota = simd::vfloat3::Iota(1.5f); - Strutil::print("vfloat3 {{}} '{}'\n", vf3iota); - Strutil::print("vfloat3 {{:.3f}} '{:.3f}'\n", vf3iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vf3iota), - "X|1.5 2.5 3.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", vf3iota), - "X|1.500 2.500 3.500|Y"); - - simd::vfloat4 vf4iota = simd::vfloat4::Iota(1.5f); - Strutil::print("vfloat4 {{}} '{}'\n", vf4iota); - Strutil::print("vfloat4 {{:.3f}} '{:.3f}'\n", vf4iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vf4iota), - "X|1.5 2.5 3.5 4.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", vf4iota), - "X|1.500 2.500 3.500 4.500|Y"); - - simd::vfloat8 vf8iota = simd::vfloat8::Iota(1.5f); - Strutil::print("vfloat8 {{}} '{}'\n", vf8iota); - Strutil::print("vfloat8 {{:.3f}} '{:.3f}'\n", vf8iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vf8iota), - "X|1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", vf8iota), - "X|1.500 2.500 3.500 4.500 5.500 6.500 7.500 8.500|Y"); - - simd::vfloat16 vf16iota = simd::vfloat16::Iota(1.5f); - Strutil::print("vfloat16 {{}} '{}'\n", vf16iota); - Strutil::print("vfloat16 {{:.3f}} '{:.3f}'\n", vf16iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vf16iota), - "X|1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5 16.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", vf16iota), - "X|1.500 2.500 3.500 4.500 5.500 6.500 7.500 8.500 9.500 10.500 11.500 12.500 13.500 14.500 15.500 16.500|Y"); - - - simd::vint4 vi4iota = simd::vint4::Iota(1); - Strutil::print("vint4 {{}} '{}'\n", vi4iota); - Strutil::print("vint4 {{:03d}} '{:03d}'\n", vi4iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vi4iota), - "X|1 2 3 4|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:03d}|Y", vi4iota), - "X|001 002 003 004|Y"); - - simd::vint8 vi8iota = simd::vint8::Iota(1); - Strutil::print("vint8 {{}} '{}'\n", vi8iota); - Strutil::print("vint8 {{:03d}} '{:03d}'\n", vi8iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vi8iota), - "X|1 2 3 4 5 6 7 8|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:03d}|Y", vi8iota), - "X|001 002 003 004 005 006 007 008|Y"); - - simd::vint16 vi16iota = simd::vint16::Iota(1); - Strutil::print("vint16 {{}} '{}'\n", vi16iota); - Strutil::print("vint16 {{:03d}} '{:03d}'\n", vi16iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", vi16iota), - "X|1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:03d}|Y", vi16iota), - "X|001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016|Y"); - - simd::matrix44 m44iota(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); - Strutil::print("matrix44 {{}} '{}'\n", m44iota); - Strutil::print("matrix44 {{:.3f}} '{:.3f}'\n", m44iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", m44iota), - Strutil::fmt::format("{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}", - m44iota[0][0], m44iota[0][1], m44iota[0][2], m44iota[0][3], - m44iota[1][0], m44iota[1][1], m44iota[1][2], m44iota[1][3], - m44iota[2][0], m44iota[2][1], m44iota[2][2], m44iota[2][3], - m44iota[3][0], m44iota[3][1], m44iota[3][2], m44iota[3][3])); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", m44iota), - "X|0.000 1.000 2.000 3.000 4.000 5.000 6.000 7.000 8.000 9.000 10.000 11.000 12.000 13.000 14.000 15.000|Y"); - - Imath::V3f ivf3iota(1.5f, 2.5f, 3.5f); - Strutil::print("Imath::V3f {{}} '{}'\n", ivf3iota); - Strutil::print("Imath::V3f {{:.3f}} '{:.3f}'\n", ivf3iota); - Strutil::print("Imath::V3f {{:,.3f}} '{:,.3f}'\n", ivf3iota); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", ivf3iota), - "X|1.5 2.5 3.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", ivf3iota), - "X|1.500 2.500 3.500|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|({:,.3f})|Y", ivf3iota), - "X|(1.500, 2.500, 3.500)|Y"); - Strutil::print("\n"); - - // Test custom formatting of spans - float farray[] = { 1.5f, 2.5f, 3.5f, 4.5f }; - Strutil::print("cspan {{}} '{}'\n", cspan(farray)); - Strutil::print("cspan {{:.3f}} '{:.3f}'\n", cspan(farray)); - Strutil::print("cspan {{:,.3f}} '{:,.3f}'\n", cspan(farray)); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{}|Y", cspan(farray)), - "X|1.5 2.5 3.5 4.5|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|{:.3f}|Y", cspan(farray)), - "X|1.500 2.500 3.500 4.500|Y"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("X|({:,.3f})|Y", cspan(farray)), - "X|(1.500, 2.500, 3.500, 4.500)|Y"); -} - - - -void -test_memformat() -{ - OIIO_CHECK_EQUAL(Strutil::memformat(15), "15 B"); - OIIO_CHECK_EQUAL(Strutil::memformat(15LL * 1024), "15 KB"); - OIIO_CHECK_EQUAL(Strutil::memformat(15LL * 1024 * 1024), "15.0 MB"); - OIIO_CHECK_EQUAL(Strutil::memformat(15LL * 1024 * 1024 * 1024), "15.0 GB"); - OIIO_CHECK_EQUAL(Strutil::memformat(15LL * 1024 * 1024 + 200000), - "15.2 MB"); - OIIO_CHECK_EQUAL(Strutil::memformat(15LL * 1024 * 1024 + 200000, 3), - "15.191 MB"); -} - - - -void -test_timeintervalformat() -{ - OIIO_CHECK_EQUAL(Strutil::timeintervalformat(15.321), "15.3s"); - OIIO_CHECK_EQUAL(Strutil::timeintervalformat(150.321), "2m 30.3s"); - OIIO_CHECK_EQUAL(Strutil::timeintervalformat(15000.321), "4h 10m 0.3s"); - OIIO_CHECK_EQUAL(Strutil::timeintervalformat(150000.321), - "1d 17h 40m 0.3s"); - OIIO_CHECK_EQUAL(Strutil::timeintervalformat(150.321, 2), "2m 30.32s"); -} - - - -void -test_get_rest_arguments() -{ - bool ret; - std::map result; - std::string base; - std::string url = "someplace?arg1=value1&arg2=value2"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, true); - OIIO_CHECK_EQUAL(base, "someplace"); - OIIO_CHECK_EQUAL(result["arg1"], "value1"); - OIIO_CHECK_EQUAL(result["arg2"], "value2"); - OIIO_CHECK_EQUAL(result["arg3"], ""); - - result.clear(); - url = "?arg1=value1&arg2=value2"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, true); - OIIO_CHECK_EQUAL(base, ""); - OIIO_CHECK_EQUAL(result["arg1"], "value1"); - OIIO_CHECK_EQUAL(result["arg2"], "value2"); - - result.clear(); - url = "arg1=value1&arg2=value2"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, true); - OIIO_CHECK_EQUAL(base, "arg1=value1&arg2=value2"); - OIIO_CHECK_EQUAL(result["arg1"], ""); - OIIO_CHECK_EQUAL(result["arg2"], ""); - - result.clear(); - url = ""; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, true); - OIIO_CHECK_EQUAL(base, ""); - OIIO_CHECK_EQUAL(result["arg1"], ""); - OIIO_CHECK_EQUAL(result["arg2"], ""); - - result.clear(); - url = "sometextwithoutasense????&&&&&arg4=val1"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, false); - OIIO_CHECK_EQUAL(base, "sometextwithoutasense"); - OIIO_CHECK_EQUAL(result["arg1"], ""); - OIIO_CHECK_EQUAL(result["arg2"], ""); - OIIO_CHECK_EQUAL(result["arg4"], ""); - - result.clear(); - url = "atext?arg1value1&arg2value2"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, false); - OIIO_CHECK_EQUAL(base, "atext"); - OIIO_CHECK_EQUAL(result["arg1"], ""); - OIIO_CHECK_EQUAL(result["arg2"], ""); - - result.clear(); - url = "atext?arg1=value1&arg2value2"; - result["arg2"] = "somevalue"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, false); - OIIO_CHECK_EQUAL(base, "atext"); - OIIO_CHECK_EQUAL(result["arg1"], "value1"); - OIIO_CHECK_EQUAL(result["arg2"], "somevalue"); - - // Test windows long filename syntax - result.clear(); - url = "\\\\?\\UNC\\server\\foo?arg1=value1"; - ret = Strutil::get_rest_arguments(url, base, result); - OIIO_CHECK_EQUAL(ret, true); - OIIO_CHECK_EQUAL(base, "\\\\?\\UNC\\server\\foo"); - OIIO_CHECK_EQUAL(result["arg1"], "value1"); -} - - - -void -test_escape(string_view raw, string_view escaped) -{ - Strutil::print("escape '{}' <-> '{}'\n", raw, escaped); - OIIO_CHECK_EQUAL(Strutil::escape_chars(raw), escaped); - OIIO_CHECK_EQUAL(Strutil::unescape_chars(escaped), raw); -} - - - -void -test_escape_sequences() -{ - test_escape ("\\ \n \r \t \v \b \f \a", "\\\\ \\n \\r \\t \\v \\b \\f \\a"); - test_escape (" \"quoted\" ", " \\\"quoted\\\" "); - OIIO_CHECK_EQUAL(Strutil::unescape_chars("A\\023B"), "A\023B"); -} - - - -void -test_wordwrap() -{ - std::string words - = "Now is the time for all good men to come to the aid of their party."; - OIIO_CHECK_EQUAL(Strutil::wordwrap(words, 24), "Now is the time for all\n" - "good men to come to the\n" - "aid of their party."); - std::string densewords - = "Now is the,time,for,all,good,men,to,come to the aid of their party."; - OIIO_CHECK_EQUAL(Strutil::wordwrap(densewords, 24, 0, " ", ","), - "Now is the,time,for,all,\n" - "good,men,to,come to the\n" - "aid of their party."); -} - - - -void -test_hash() -{ - using namespace Strutil; - OIIO_CHECK_EQUAL(strhash("foo"), 6150913649986995171); - OIIO_CHECK_EQUAL(strhash(std::string("foo")), 6150913649986995171); - OIIO_CHECK_EQUAL(strhash(string_view("foo")), 6150913649986995171); - OIIO_CHECK_EQUAL(strhash(""), 0); // empty string hashes to 0 - // Check longer hash and ensure that it's really constexpr - constexpr size_t hash = Strutil::strhash("much longer string"); - OIIO_CHECK_EQUAL(hash, 16257490369375554819ULL); -} - - - -void -test_comparisons() -{ - OIIO_CHECK_EQUAL(Strutil::iequals("abc", "abc"), true); - OIIO_CHECK_EQUAL(Strutil::iequals("Abc", "aBc"), true); - OIIO_CHECK_EQUAL(Strutil::iequals("abc", "adc"), false); - OIIO_CHECK_EQUAL(Strutil::iequals("abc", "abcd"), false); - OIIO_CHECK_EQUAL(Strutil::iequals("abcd", "abc"), false); - OIIO_CHECK_EQUAL(Strutil::iequals("", "abc"), false); - OIIO_CHECK_EQUAL(Strutil::iequals("abc", ""), false); - OIIO_CHECK_EQUAL(Strutil::iequals("", ""), true); - - OIIO_CHECK_EQUAL(Strutil::starts_with("abcd", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::starts_with("aBcd", "Ab"), false); - OIIO_CHECK_EQUAL(Strutil::starts_with("abcd", "ba"), false); - OIIO_CHECK_EQUAL(Strutil::starts_with("abcd", "abcde"), false); - OIIO_CHECK_EQUAL(Strutil::starts_with("", "a"), false); - OIIO_CHECK_EQUAL(Strutil::starts_with("", ""), true); - OIIO_CHECK_EQUAL(Strutil::starts_with("abc", ""), true); - - OIIO_CHECK_EQUAL(Strutil::istarts_with("abcd", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::istarts_with("aBcd", "Ab"), true); - OIIO_CHECK_EQUAL(Strutil::istarts_with("abcd", "ba"), false); - OIIO_CHECK_EQUAL(Strutil::istarts_with("abcd", "abcde"), false); - OIIO_CHECK_EQUAL(Strutil::istarts_with("", "a"), false); - OIIO_CHECK_EQUAL(Strutil::istarts_with("", ""), true); - OIIO_CHECK_EQUAL(Strutil::istarts_with("abc", ""), true); - - OIIO_CHECK_EQUAL(Strutil::ends_with("abcd", "cd"), true); - OIIO_CHECK_EQUAL(Strutil::ends_with("aBCd", "cd"), false); - OIIO_CHECK_EQUAL(Strutil::ends_with("aBcd", "CD"), false); - OIIO_CHECK_EQUAL(Strutil::ends_with("abcd", "ba"), false); - OIIO_CHECK_EQUAL(Strutil::ends_with("abcd", "xabcd"), false); - OIIO_CHECK_EQUAL(Strutil::ends_with("", "a"), false); - OIIO_CHECK_EQUAL(Strutil::ends_with("", ""), true); - OIIO_CHECK_EQUAL(Strutil::ends_with("abc", ""), true); - - OIIO_CHECK_EQUAL(Strutil::iends_with("abcd", "cd"), true); - OIIO_CHECK_EQUAL(Strutil::iends_with("aBCd", "cd"), true); - OIIO_CHECK_EQUAL(Strutil::iends_with("aBcd", "CD"), true); - OIIO_CHECK_EQUAL(Strutil::iends_with("abcd", "ba"), false); - OIIO_CHECK_EQUAL(Strutil::iends_with("abcd", "xabcd"), false); - OIIO_CHECK_EQUAL(Strutil::iends_with("", "a"), false); - OIIO_CHECK_EQUAL(Strutil::iends_with("", ""), true); - OIIO_CHECK_EQUAL(Strutil::iends_with("abc", ""), true); - - OIIO_CHECK_EQUAL(Strutil::contains("abcde", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::contains("abcde", "bcd"), true); - OIIO_CHECK_EQUAL(Strutil::contains("abcde", "de"), true); - OIIO_CHECK_EQUAL(Strutil::contains("abcde", "cdx"), false); - OIIO_CHECK_EQUAL(Strutil::contains("abcde", ""), true); - OIIO_CHECK_EQUAL(Strutil::contains("", ""), false); - OIIO_CHECK_EQUAL(Strutil::contains("", "x"), false); - - OIIO_CHECK_EQUAL(Strutil::icontains("abcde", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::icontains("Abcde", "aB"), true); - OIIO_CHECK_EQUAL(Strutil::icontains("abcde", "bcd"), true); - OIIO_CHECK_EQUAL(Strutil::icontains("Abcde", "bCd"), true); - OIIO_CHECK_EQUAL(Strutil::icontains("abcDe", "dE"), true); - OIIO_CHECK_EQUAL(Strutil::icontains("abcde", "cdx"), false); - OIIO_CHECK_EQUAL(Strutil::icontains("abcde", ""), true); - OIIO_CHECK_EQUAL(Strutil::icontains("", ""), false); - OIIO_CHECK_EQUAL(Strutil::icontains("", "x"), false); - - OIIO_CHECK_EQUAL(Strutil::rcontains("abcde", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::rcontains("abcde", "bcd"), true); - OIIO_CHECK_EQUAL(Strutil::rcontains("abcde", "de"), true); - OIIO_CHECK_EQUAL(Strutil::rcontains("abcde", "cdx"), false); - OIIO_CHECK_EQUAL(Strutil::rcontains("abcde", ""), true); - OIIO_CHECK_EQUAL(Strutil::rcontains("", ""), false); - OIIO_CHECK_EQUAL(Strutil::rcontains("", "x"), false); - - OIIO_CHECK_EQUAL(Strutil::ircontains("abcde", "ab"), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("Abcde", "aB"), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("abcde", "bcd"), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("Abcde", "bCd"), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("abcDe", "dE"), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("abcde", "cdx"), false); - OIIO_CHECK_EQUAL(Strutil::ircontains("abcde", ""), true); - OIIO_CHECK_EQUAL(Strutil::ircontains("", ""), false); - OIIO_CHECK_EQUAL(Strutil::ircontains("", "x"), false); - - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", "xa"), true); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", "xe"), true); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", "xc"), true); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", "xyz"), false); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", "abcde"), true); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("", "abc"), false); - OIIO_CHECK_EQUAL(Strutil::contains_any_char("abcde", ""), false); - - OIIO_CHECK_EQUAL(Strutil::find("abcdeabcde", "bc"), 1); - OIIO_CHECK_EQUAL(Strutil::find("abcdeabcde", "BC"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::find("abcdeabcde", "ac"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::find("abcdeabcde", ""), 0); - OIIO_CHECK_EQUAL(Strutil::find("", "abc"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::find("", ""), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::rfind("abcdeabcde", "bc"), 6); - OIIO_CHECK_EQUAL(Strutil::rfind("abcdeabcde", "BC"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::rfind("abcdeabcde", "ac"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::rfind("abcdeabcde", ""), 10); - OIIO_CHECK_EQUAL(Strutil::rfind("", "abc"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::rfind("", ""), std::string::npos); - - OIIO_CHECK_EQUAL(Strutil::ifind("abcdeabcde", "bc"), 1); - OIIO_CHECK_EQUAL(Strutil::ifind("abcdeabcde", "BC"), 1); - OIIO_CHECK_EQUAL(Strutil::ifind("abcdeabcde", "ac"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::ifind("abcdeabcde", ""), 0); - OIIO_CHECK_EQUAL(Strutil::ifind("", "abc"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::ifind("", ""), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::irfind("abcdeabcde", "bc"), 6); - OIIO_CHECK_EQUAL(Strutil::irfind("abcdeabcde", "BC"), 6); - OIIO_CHECK_EQUAL(Strutil::irfind("abcdeabcde", "ac"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::irfind("abcdeabcde", ""), 10); - OIIO_CHECK_EQUAL(Strutil::irfind("", "abc"), std::string::npos); - OIIO_CHECK_EQUAL(Strutil::irfind("", ""), std::string::npos); - - Strutil::StringEqual eq; - Strutil::StringIEqual ieq; - Strutil::StringLess less; - Strutil::StringILess iless; - OIIO_CHECK_ASSERT(eq("abc", "abc")); - OIIO_CHECK_ASSERT(!eq("abc", "ABC")); - OIIO_CHECK_ASSERT(!eq("abc", "axc")); - OIIO_CHECK_ASSERT(ieq("abc", "abc")); - OIIO_CHECK_ASSERT(ieq("abc", "ABC")); - OIIO_CHECK_ASSERT(!ieq("abc", "axc")); - OIIO_CHECK_ASSERT(less("abc", "abd")); - OIIO_CHECK_ASSERT(!less("xbc", "abd")); - OIIO_CHECK_ASSERT(!less("abc", "ABD")); - OIIO_CHECK_ASSERT(iless("abc", "abd")); - OIIO_CHECK_ASSERT(!iless("xbc", "abd")); - OIIO_CHECK_ASSERT(iless("abc", "ABD")); - - Benchmarker bench; - bench.indent (2); - bench.units (Benchmarker::Unit::ns); - std::string abc = "abcdefghijklmnopqrstuvwxyz"; - std::string abcmore = "abcdefghijklmnopqrstuvwxyz1"; - std::string abcnope = "1abcdefghijklmnopqrstuvwxyz"; - std::string haystack = std::string("begin") + abc + "oiio" - + Strutil::repeat(abc, 10) + "123" + abc + "end"; - bench ("string== success", [&](){ DoNotOptimize(abc == abc); }); // NOSONAR - bench ("string== failure", [&](){ DoNotOptimize(abc == abcmore); }); - bench ("iequals success", [&](){ DoNotOptimize(Strutil::iequals(abc, abc)); }); - bench ("iless easy", [&](){ DoNotOptimize(Strutil::iless(abc, abcnope)); }); - bench ("iless hard", [&](){ DoNotOptimize(Strutil::iless(abc, abc)); }); - bench ("StringILess easy", [&](){ DoNotOptimize(iless(abc, abcnope)); }); - bench ("StringILess hard", [&](){ DoNotOptimize(iless(abc, abc)); }); - bench ("contains early small", [&](){ DoNotOptimize(Strutil::contains(abc, "def")); }); - bench ("contains early big", [&](){ DoNotOptimize(Strutil::contains(haystack, "oiio")); }); - bench ("contains late small", [&](){ DoNotOptimize(Strutil::contains(abc, "uvw")); }); - bench ("contains late big", [&](){ DoNotOptimize(Strutil::contains(haystack, "123")); }); - bench ("contains fail/small", [&](){ DoNotOptimize(Strutil::contains(abc, "dog")); }); - bench ("contains fail/big", [&](){ DoNotOptimize(Strutil::contains(haystack, "dog")); }); - bench ("rcontains early small", [&](){ DoNotOptimize(Strutil::rcontains(abc, "def")); }); - bench ("rcontains early big", [&](){ DoNotOptimize(Strutil::rcontains(haystack, "oiio")); }); - bench ("rcontains late small", [&](){ DoNotOptimize(Strutil::rcontains(abc, "uvw")); }); - bench ("rcontains late big", [&](){ DoNotOptimize(Strutil::rcontains(haystack, "123")); }); - bench ("rcontains fail/small", [&](){ DoNotOptimize(Strutil::rcontains(abc, "dog")); }); - bench ("rcontains fail/big", [&](){ DoNotOptimize(Strutil::rcontains(haystack, "dog")); }); - bench ("icontains early small", [&](){ DoNotOptimize(Strutil::icontains(abc, "def")); }); - bench ("icontains early big", [&](){ DoNotOptimize(Strutil::icontains(haystack, "oiio")); }); - bench ("icontains late small", [&](){ DoNotOptimize(Strutil::icontains(abc, "uvw")); }); - bench ("icontains late big", [&](){ DoNotOptimize(Strutil::icontains(haystack, "123")); }); - bench ("icontains fail/small", [&](){ DoNotOptimize(Strutil::icontains(abc, "dog")); }); - bench ("icontains fail/big", [&](){ DoNotOptimize(Strutil::icontains(haystack, "dog")); }); - - bench ("find early small", [&](){ DoNotOptimize(Strutil::find(abc, "def")); }); - bench ("find early big", [&](){ DoNotOptimize(Strutil::find(haystack, "oiio")); }); - bench ("find late small", [&](){ DoNotOptimize(Strutil::find(abc, "uvw")); }); - bench ("find late big", [&](){ DoNotOptimize(Strutil::find(haystack, "123")); }); - bench ("find fail/small", [&](){ DoNotOptimize(Strutil::find(abc, "dog")); }); - bench ("find fail/big", [&](){ DoNotOptimize(Strutil::find(haystack, "dog")); }); - bench ("rfind early small", [&](){ DoNotOptimize(Strutil::rfind(abc, "def")); }); - bench ("rfind early big", [&](){ DoNotOptimize(Strutil::rfind(haystack, "oiio")); }); - bench ("rfind late small", [&](){ DoNotOptimize(Strutil::rfind(abc, "uvw")); }); - bench ("rfind late big", [&](){ DoNotOptimize(Strutil::rfind(haystack, "123")); }); - bench ("rfind fail/small", [&](){ DoNotOptimize(Strutil::rfind(abc, "dog")); }); - bench ("rfind fail/big", [&](){ DoNotOptimize(Strutil::rfind(haystack, "dog")); }); - - bench ("ifind early small", [&](){ DoNotOptimize(Strutil::ifind(abc, "def")); }); - bench ("ifind early big", [&](){ DoNotOptimize(Strutil::ifind(haystack, "oiio")); }); - bench ("ifind late small", [&](){ DoNotOptimize(Strutil::ifind(abc, "uvw")); }); - bench ("ifind late big", [&](){ DoNotOptimize(Strutil::ifind(haystack, "123")); }); - bench ("ifind fail/small", [&](){ DoNotOptimize(Strutil::ifind(abc, "dog")); }); - bench ("ifind fail/big", [&](){ DoNotOptimize(Strutil::ifind(haystack, "dog")); }); - bench ("irfind early small", [&](){ DoNotOptimize(Strutil::irfind(abc, "def")); }); - bench ("irfind early big", [&](){ DoNotOptimize(Strutil::irfind(haystack, "oiio")); }); - bench ("irfind late small", [&](){ DoNotOptimize(Strutil::irfind(abc, "uvw")); }); - bench ("irfind late big", [&](){ DoNotOptimize(Strutil::irfind(haystack, "123")); }); - bench ("irfind fail/small", [&](){ DoNotOptimize(Strutil::irfind(abc, "dog")); }); - bench ("irfind fail/big", [&](){ DoNotOptimize(Strutil::irfind(haystack, "dog")); }); - - bench ("starts_with success", [&](){ DoNotOptimize(Strutil::starts_with(abc, "abc")); }); - bench ("starts_with fail", [&](){ DoNotOptimize(Strutil::starts_with(abc, "def")); }); - bench ("istarts_with success", [&](){ DoNotOptimize(Strutil::istarts_with(abc, "abc")); }); - bench ("istarts_with fail", [&](){ DoNotOptimize(Strutil::istarts_with(abc, "def")); }); - bench ("ends_with success", [&](){ DoNotOptimize(Strutil::ends_with(abc, "xyz")); }); - bench ("ends_with fail", [&](){ DoNotOptimize(Strutil::ends_with(abc, "def")); }); - bench ("iends_with success", [&](){ DoNotOptimize(Strutil::iends_with(abc, "xyz")); }); - bench ("iends_with fail", [&](){ DoNotOptimize(Strutil::iends_with(abc, "def")); }); -} - - - -void -test_case() -{ - std::string s; - s = "abcDEF,*1"; - Strutil::to_lower(s); - OIIO_CHECK_EQUAL(s, "abcdef,*1"); - s = "abcDEF,*1"; - Strutil::to_upper(s); - OIIO_CHECK_EQUAL(s, "ABCDEF,*1"); - - s = "abcDEF,*1"; - OIIO_CHECK_EQUAL(Strutil::lower(s), "abcdef,*1"); - OIIO_CHECK_EQUAL (s, "abcDEF,*1"); // make sure it's nondestructive - Strutil::to_upper(s); - OIIO_CHECK_EQUAL(Strutil::upper(s), "ABCDEF,*1"); - Strutil::to_upper(s); -} - - - -void -test_strip() -{ - OIIO_CHECK_EQUAL(Strutil::strip("abcdefbac", "abc"), "def"); - OIIO_CHECK_EQUAL(Strutil::strip("defghi", "abc"), "defghi"); - OIIO_CHECK_EQUAL(Strutil::strip(" \tHello, world\n"), "Hello, world"); - OIIO_CHECK_EQUAL(Strutil::strip(" \t"), ""); - OIIO_CHECK_EQUAL(Strutil::strip(""), ""); - - OIIO_CHECK_EQUAL(Strutil::lstrip("abcdefbac", "abc"), "defbac"); - OIIO_CHECK_EQUAL(Strutil::lstrip("defghi", "abc"), "defghi"); - OIIO_CHECK_EQUAL(Strutil::lstrip(" \tHello, world\n"), "Hello, world\n"); - OIIO_CHECK_EQUAL(Strutil::lstrip(" \t"), ""); - OIIO_CHECK_EQUAL(Strutil::lstrip(""), ""); - - OIIO_CHECK_EQUAL(Strutil::rstrip("abcdefbac", "abc"), "abcdef"); - OIIO_CHECK_EQUAL(Strutil::rstrip("defghi", "abc"), "defghi"); - OIIO_CHECK_EQUAL(Strutil::rstrip(" \tHello, world\n"), " \tHello, world"); - OIIO_CHECK_EQUAL(Strutil::rstrip(" \t"), ""); - OIIO_CHECK_EQUAL(Strutil::rstrip(""), ""); -} - - - -void -test_splits() -{ - std::string s("Now\nis the time!"); - { // test default -- split at whitespace - auto pieces = Strutil::splits(s); - OIIO_CHECK_EQUAL(pieces.size(), 4); - OIIO_CHECK_EQUAL(pieces[0], "Now"); - OIIO_CHECK_EQUAL(pieces[1], "is"); - OIIO_CHECK_EQUAL(pieces[2], "the"); - OIIO_CHECK_EQUAL(pieces[3], "time!"); - } - { // test custom split string - auto pieces = Strutil::splits(s, " t"); - OIIO_CHECK_EQUAL(pieces.size(), 3); - OIIO_CHECK_EQUAL(pieces[0], "Now\nis"); - OIIO_CHECK_EQUAL(pieces[1], "he "); - OIIO_CHECK_EQUAL(pieces[2], "ime!"); - } - { // test split of unfound separator - auto pieces = Strutil::splits(s, "xyz"); - OIIO_CHECK_EQUAL(pieces.size(), 1); - OIIO_CHECK_EQUAL(pieces[0], s); - } - { // test maxsplit - auto pieces = Strutil::splits(s, "", 2); - OIIO_CHECK_EQUAL(pieces.size(), 2); - OIIO_CHECK_EQUAL(pieces[0], "Now"); - OIIO_CHECK_EQUAL(pieces[1], "is the time!"); - } - { // test maxsplit with non-default sep - auto pieces = Strutil::splits(s, " ", 2); - OIIO_CHECK_EQUAL(pieces.size(), 2); - OIIO_CHECK_EQUAL(pieces[0], "Now\nis"); - OIIO_CHECK_EQUAL(pieces[1], "the time!"); - } - { // test split against a substring that is not present - auto pieces = Strutil::splits("blah", "!"); - OIIO_CHECK_EQUAL(pieces.size(), 1); - OIIO_CHECK_EQUAL(pieces[0], "blah"); - } - { // test splitting empty string - auto pieces = Strutil::splits("", ","); - OIIO_CHECK_EQUAL(pieces.size(), 0); - } - { // test splitting with empty pieces - auto pieces = Strutil::splits(",foo,,,bar,", ","); - OIIO_CHECK_EQUAL(pieces.size(), 6); - OIIO_CHECK_EQUAL(pieces[0], ""); - OIIO_CHECK_EQUAL(pieces[1], "foo"); - OIIO_CHECK_EQUAL(pieces[2], ""); - OIIO_CHECK_EQUAL(pieces[3], ""); - OIIO_CHECK_EQUAL(pieces[4], "bar"); - OIIO_CHECK_EQUAL(pieces[5], ""); - } -} - - - -void -test_splitsv() -{ - std::string s("Now\nis the time!"); - { // test default -- split at whitespace - auto pieces = Strutil::splitsv(s); - OIIO_CHECK_EQUAL(pieces.size(), 4); - OIIO_CHECK_EQUAL(pieces[0], "Now"); - OIIO_CHECK_EQUAL(pieces[1], "is"); - OIIO_CHECK_EQUAL(pieces[2], "the"); - OIIO_CHECK_EQUAL(pieces[3], "time!"); - } - { // test custom split string - auto pieces = Strutil::splitsv(s, " t"); - OIIO_CHECK_EQUAL(pieces.size(), 3); - OIIO_CHECK_EQUAL(pieces[0], "Now\nis"); - OIIO_CHECK_EQUAL(pieces[1], "he "); - OIIO_CHECK_EQUAL(pieces[2], "ime!"); - } - { // test split of unfound separator - auto pieces = Strutil::splitsv(s, "xyz"); - OIIO_CHECK_EQUAL(pieces.size(), 1); - OIIO_CHECK_EQUAL(pieces[0], s); - } - { // test maxsplit - auto pieces = Strutil::splitsv(s, "", 2); - OIIO_CHECK_EQUAL(pieces.size(), 2); - OIIO_CHECK_EQUAL(pieces[0], "Now"); - OIIO_CHECK_EQUAL(pieces[1], "is the time!"); - } - { // test maxsplit with non-default sep - auto pieces = Strutil::splitsv(s, " ", 2); - OIIO_CHECK_EQUAL(pieces.size(), 2); - OIIO_CHECK_EQUAL(pieces[0], "Now\nis"); - OIIO_CHECK_EQUAL(pieces[1], "the time!"); - } - { // test split against a substring that is not present - auto pieces = Strutil::splitsv("blah", "!"); - OIIO_CHECK_EQUAL(pieces.size(), 1); - OIIO_CHECK_EQUAL(pieces[0], "blah"); - } - { // test splitting empty string - auto pieces = Strutil::splitsv("", ","); - OIIO_CHECK_EQUAL(pieces.size(), 0); - } - { // test splitting with empty pieces - auto pieces = Strutil::splitsv(",foo,,,bar,", ","); - OIIO_CHECK_EQUAL(pieces.size(), 6); - OIIO_CHECK_EQUAL(pieces[0], ""); - OIIO_CHECK_EQUAL(pieces[1], "foo"); - OIIO_CHECK_EQUAL(pieces[2], ""); - OIIO_CHECK_EQUAL(pieces[3], ""); - OIIO_CHECK_EQUAL(pieces[4], "bar"); - OIIO_CHECK_EQUAL(pieces[5], ""); - } -} - - - -void -test_join() -{ - std::vector strvec { "Now", "is", "the", "time" }; - OIIO_CHECK_EQUAL(Strutil::join(strvec, ". "), "Now. is. the. time"); - - std::vector svvec { "Now", "is", "the", "time" }; - OIIO_CHECK_EQUAL(Strutil::join(svvec, "/"), "Now/is/the/time"); - - std::vector intvec { 3, 2, 1 }; - OIIO_CHECK_EQUAL(Strutil::join(intvec, " "), "3 2 1"); - - int intarr[] = { 4, 2 }; - OIIO_CHECK_EQUAL(Strutil::join(intarr, ","), "4,2"); - - // Test join's `len` parameter. - float farr[] = { 1, 2, 3.5, 4, 5 }; - OIIO_CHECK_EQUAL(Strutil::join(farr, ",", 3), "1,2,3.5"); - OIIO_CHECK_EQUAL(Strutil::join(farr, ",", 7), "1,2,3.5,4,5,0,0"); -} - - - -void -test_concat() -{ - std::cout << "Testing concat\n"; - OIIO_CHECK_EQUAL(Strutil::concat("foo", "bar"), "foobar"); - OIIO_CHECK_EQUAL(Strutil::concat("foo", ""), "foo"); - OIIO_CHECK_EQUAL(Strutil::concat("", "foo"), "foo"); - OIIO_CHECK_EQUAL(Strutil::concat("", ""), ""); - std::string longstring(Strutil::repeat("01234567890", 100)); - OIIO_CHECK_EQUAL(Strutil::concat(longstring, longstring), - Strutil::sprintf("%s%s", longstring, longstring)); - OIIO_CHECK_EQUAL(Strutil::concat(longstring, longstring), - Strutil::fmt::format("{}{}", longstring, longstring)); - - Benchmarker bench; - bench.indent (2); - bench.units (Benchmarker::Unit::ns); - std::string foostr("foo"), barstr("bar"); - bench ("concat literal short+short", [&](){ return DoNotOptimize(Strutil::concat("foo", "bar")); }); - bench ("concat literal long+short", [&](){ return DoNotOptimize(Strutil::concat(longstring, "bar")); }); - bench ("concat literal long+long", [&](){ return DoNotOptimize(Strutil::concat(longstring, longstring)); }); - bench ("format literal short+short", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", "foo", "bar")); }); - bench ("format literal long+short", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", longstring, "bar")); }); - bench ("format literal long+long", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", longstring, longstring)); }); - bench ("sprintf literal short+short", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", "foo", "bar")); }); - bench ("sprintf literal long+short", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", longstring, "bar")); }); - bench ("sprintf literal long+long", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", longstring, longstring)); }); - - bench ("concat str short+short", [&](){ return DoNotOptimize(Strutil::concat(foostr, barstr)); }); - bench ("concat str long+short", [&](){ return DoNotOptimize(Strutil::concat(longstring, barstr)); }); - bench ("concat str long+long", [&](){ return DoNotOptimize(Strutil::concat(longstring, longstring)); }); - bench ("format str short+short", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", foostr, barstr)); }); - bench ("format str long+short", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", longstring, barstr)); }); - bench ("format str long+long", [&](){ return DoNotOptimize(Strutil::fmt::format("{}{}", longstring, longstring)); }); - bench ("sprintf str short+short", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", foostr, barstr)); }); - bench ("sprintf str long+short", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", longstring, barstr)); }); - bench ("sprintf str long+long", [&](){ return DoNotOptimize(Strutil::sprintf("%s%s", longstring, longstring)); }); - bench ("std::string + literal short+short", [&](){ return DoNotOptimize(std::string("foo") + std::string("bar")); }); - bench ("std::string + literal long+short", [&](){ return DoNotOptimize(longstring + std::string("bar")); }); - bench ("std::string + literal long+long", [&](){ return DoNotOptimize(longstring + longstring); }); - bench ("std::string + str short+short", [&](){ return DoNotOptimize(foostr + barstr); }); - bench ("std::string + str long+short", [&](){ return DoNotOptimize(longstring + barstr); }); - bench ("std::string + str long+long", [&](){ return DoNotOptimize(longstring + longstring); }); -} - - - -void -test_repeat() -{ - std::cout << "Testing repeat\n"; - OIIO_CHECK_EQUAL(Strutil::repeat("foo", 3), "foofoofoo"); - OIIO_CHECK_EQUAL(Strutil::repeat("foo", 1), "foo"); - OIIO_CHECK_EQUAL(Strutil::repeat("foo", 0), ""); - OIIO_CHECK_EQUAL(Strutil::repeat("foo", -1), ""); - OIIO_CHECK_EQUAL(Strutil::repeat("0123456789", 100), - Strutil::repeat("01234567890123456789", 50)); -} - - - -void -test_replace() -{ - std::cout << "Testing replace\n"; - std::string pattern("Red rose, red rose, end."); - // Replace start - OIIO_CHECK_EQUAL(Strutil::replace(pattern, "Red", "foo"), - "foo rose, red rose, end."); - // Replace end - OIIO_CHECK_EQUAL(Strutil::replace(pattern, "end.", "foo"), - "Red rose, red rose, foo"); - // Pattern not found - OIIO_CHECK_EQUAL(Strutil::replace(pattern, "bar", "foo"), pattern); - // One replacement - OIIO_CHECK_EQUAL(Strutil::replace(pattern, "rose", "foo"), - "Red foo, red rose, end."); - // Global replacement - OIIO_CHECK_EQUAL(Strutil::replace(pattern, "rose", "foo", true), - "Red foo, red foo, end."); -} - - - -void -test_excise_string_after_head() -{ - std::cout << "Testing excise_string_after_head\n"; - std::string pattern = "Red rose, red rose, end."; - - // test non-match - { - std::string p = pattern; - auto m = Strutil::excise_string_after_head(p, "blue"); - OIIO_CHECK_EQUAL(p, pattern); - OIIO_CHECK_EQUAL(m, ""); - } - - // test match: head is "ro", match subsequent chars to the next space - { - std::string p = pattern; - auto m = Strutil::excise_string_after_head(p, "ro"); - OIIO_CHECK_EQUAL(p, "Red red rose, end."); - OIIO_CHECK_EQUAL(m, "se,"); - } -} - - - -void -test_numeric_conversion() -{ - std::cout << "Testing string_is, string_from conversions\n"; - size_t pos; - - OIIO_CHECK_EQUAL(Strutil::string_is_int("142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_int("-142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_int("+142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_int("142.0"), false); - OIIO_CHECK_EQUAL(Strutil::string_is_int(""), false); - OIIO_CHECK_EQUAL(Strutil::string_is_int(" "), false); - OIIO_CHECK_EQUAL(Strutil::string_is_int("foo"), false); - OIIO_CHECK_EQUAL(Strutil::string_is_int("142x"), false); - OIIO_CHECK_EQUAL(Strutil::string_is_int(" 142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_int("142 "), true); - OIIO_CHECK_EQUAL(Strutil::string_is_int("x142"), false); - - OIIO_CHECK_EQUAL(Strutil::string_is_float("142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_float("142.0"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_float(""), false); - OIIO_CHECK_EQUAL(Strutil::string_is_float(" "), false); - OIIO_CHECK_EQUAL(Strutil::string_is_float("foo"), false); - OIIO_CHECK_EQUAL(Strutil::string_is_float("142x"), false); - OIIO_CHECK_EQUAL(Strutil::string_is_float(" 142"), true); - OIIO_CHECK_EQUAL(Strutil::string_is_float(" 142 "), true); - OIIO_CHECK_EQUAL(Strutil::string_is_float(" 142.0 "), true); - OIIO_CHECK_EQUAL(Strutil::string_is_float("x142"), false); - - // Note: we don't test string_is<> separately because it's just - // implemented directly as calls to string_is_{int,float}. - - OIIO_CHECK_EQUAL(Strutil::stoi("hi"), 0); - OIIO_CHECK_EQUAL(Strutil::stoi(" "), 0); - OIIO_CHECK_EQUAL(Strutil::stoi("123"), 123); - OIIO_CHECK_EQUAL(Strutil::stoi("-123"), -123); - OIIO_CHECK_EQUAL(Strutil::stoi("+123"), 123); - OIIO_CHECK_EQUAL(Strutil::stoi(" 123 "), 123); - OIIO_CHECK_EQUAL(Strutil::stoi("123.45"), 123); - OIIO_CHECK_EQUAL(Strutil::stoi("12345678901234567890"), - std::numeric_limits::max()); - OIIO_CHECK_EQUAL(Strutil::stoi("-12345678901234567890"), - std::numeric_limits::min()); - OIIO_CHECK_EQUAL(Strutil::stoi("0x100", nullptr, 16), 256); // hex - - OIIO_CHECK_EQUAL(Strutil::stoui("hi"), 0); - OIIO_CHECK_EQUAL(Strutil::stoui(" "), 0); - OIIO_CHECK_EQUAL(Strutil::stoui("123"), 123); - OIIO_CHECK_EQUAL(Strutil::stoui("+123"), 123); - OIIO_CHECK_EQUAL(Strutil::stoui(" 123 "), 123); - OIIO_CHECK_EQUAL(Strutil::stoui("123.45"), 123); - // bigger than fits in an int, to be sure we're really using uint: - OIIO_CHECK_EQUAL(Strutil::stoui("3221225472"), 3221225472UL); - - OIIO_CHECK_EQUAL(Strutil::stoi("hi", &pos), 0); - OIIO_CHECK_EQUAL(pos, 0); - OIIO_CHECK_EQUAL(Strutil::stoi(" ", &pos), 0); - OIIO_CHECK_EQUAL(pos, 0); - OIIO_CHECK_EQUAL(Strutil::stoi("123", &pos), 123); - OIIO_CHECK_EQUAL(pos, 3); - OIIO_CHECK_EQUAL(Strutil::stoi("-123", &pos), -123); - OIIO_CHECK_EQUAL(pos, 4); - OIIO_CHECK_EQUAL(Strutil::stoi(" 123 ", &pos), 123); - OIIO_CHECK_EQUAL(pos, 4); - OIIO_CHECK_EQUAL(Strutil::stoi("123.45", &pos), 123); - OIIO_CHECK_EQUAL(pos, 3); - -#if 0 - // Make sure it's correct for EVERY value. This takes too long to do as - // part of unit tests, but I assure you that I did it once to confirm. - for (int64_t i = std::numeric_limits::min(); i <= std::numeric_limits::max(); ++i) - OIIO_CHECK_EQUAL (Strutil::stoi(Strutil::sprintf("%d",i)), i); -#endif - - OIIO_CHECK_EQUAL(Strutil::stoui("hi"), unsigned(0)); - OIIO_CHECK_EQUAL(Strutil::stoui(" "), unsigned(0)); - OIIO_CHECK_EQUAL(Strutil::stoui("123"), unsigned(123)); - OIIO_CHECK_EQUAL(Strutil::stoui("-123"), unsigned(-123)); - OIIO_CHECK_EQUAL(Strutil::stoui(" 123 "), unsigned(123)); - OIIO_CHECK_EQUAL(Strutil::stoui("123.45"), unsigned(123)); - - OIIO_CHECK_EQUAL(Strutil::stof("hi"), 0.0f); - OIIO_CHECK_EQUAL(Strutil::stof(" "), 0.0f); - OIIO_CHECK_EQUAL(Strutil::stof("123"), 123.0f); - OIIO_CHECK_EQUAL(Strutil::stof("-123"), -123.0f); - OIIO_CHECK_EQUAL(Strutil::stof("123.45"), 123.45f); - OIIO_CHECK_EQUAL(Strutil::stof("123.45xyz"), 123.45f); - OIIO_CHECK_EQUAL(Strutil::stof(" 123.45 "), 123.45f); - OIIO_CHECK_EQUAL(Strutil::stof("123.45+12"), 123.45f); - OIIO_CHECK_EQUAL(Strutil::stof("1.2345e+2"), 123.45f); - - OIIO_CHECK_EQUAL(Strutil::stof("hi", &pos), 0.0f); - OIIO_CHECK_EQUAL(pos, 0); - OIIO_CHECK_EQUAL(Strutil::stof(" ", &pos), 0.0f); - OIIO_CHECK_EQUAL(pos, 0); - OIIO_CHECK_EQUAL(Strutil::stof("123", &pos), 123.0f); - OIIO_CHECK_EQUAL(pos, 3); - OIIO_CHECK_EQUAL(Strutil::stof("-123", &pos), -123.0f); - OIIO_CHECK_EQUAL(pos, 4); - OIIO_CHECK_EQUAL(Strutil::stof("123.45", &pos), 123.45f); - OIIO_CHECK_EQUAL(pos, 6); - OIIO_CHECK_EQUAL(Strutil::stof("123.45xyz", &pos), 123.45f); - OIIO_CHECK_EQUAL(pos, 6); - OIIO_CHECK_EQUAL(Strutil::stof(" 123.45 ", &pos), 123.45f); - OIIO_CHECK_EQUAL(pos, 7); - OIIO_CHECK_EQUAL(Strutil::stof("123.45+12", &pos), 123.45f); - OIIO_CHECK_EQUAL(pos, 6); - OIIO_CHECK_EQUAL(Strutil::stof("1.2345e2", &pos), 123.45f); - OIIO_CHECK_EQUAL(pos, 8); - // stress case! - OIIO_CHECK_EQUAL (Strutil::stof("100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001E-200"), 1.0f); - OIIO_CHECK_EQUAL (Strutil::stof("0.00000000000000000001"), 1.0e-20f); - - OIIO_CHECK_EQUAL(Strutil::strtod("314.25"), 314.25); - OIIO_CHECK_EQUAL(Strutil::strtod("hi"), 0.0); - - pos = 100; - OIIO_CHECK_EQUAL(Strutil::stod(string_view("314.25"), &pos), 314.25); - OIIO_CHECK_EQUAL(pos, 6); - pos = 100; - OIIO_CHECK_EQUAL(Strutil::stod("hi", &pos), 0.0); - OIIO_CHECK_EQUAL(pos, 0); - pos = 100; - OIIO_CHECK_EQUAL(Strutil::stod("", &pos), 0.0); - OIIO_CHECK_EQUAL(pos, 0); - pos = 100; - OIIO_CHECK_EQUAL(Strutil::stod(nullptr, &pos), 0.0); - OIIO_CHECK_EQUAL(pos, 0); - - // Note: we don't test from_strings<> separately because it's just - // implemented directly as calls to stoi, stoui, stof. - - Benchmarker bench; - bench.indent (2); - bench.units (Benchmarker::Unit::ns); - const char* numcstr = "123.45"; - std::string numstring (numcstr); - bench ("get default locale", [](){ std::locale loc; DoNotOptimize (loc); }); - bench ("ref classic locale", [](){ DoNotOptimize (std::locale::classic()); }); - bench ("std atoi", [&](){ DoNotOptimize(atoi(numcstr));}); // NOLINT(cert-err34-c) - bench ("Strutil::stoi(string) ", [&](){ return DoNotOptimize(Strutil::stoi(numstring)); }); - bench ("Strutil::stoi(char*) ", [&](){ return DoNotOptimize(Strutil::stoi(numcstr)); }); - bench ("Strutil::stoui(char*) ", [&](){ return DoNotOptimize(Strutil::stoui(numcstr)); }); - bench ("std atof", [&](){ DoNotOptimize(atof(numcstr));}); // NOLINT(cert-err34-c) - bench ("std strtod", [&](){ DoNotOptimize(::strtod(numcstr, nullptr));}); - bench ("Strutil::from_string", [&](){ DoNotOptimize(Strutil::from_string(numstring));}); - bench ("Strutil::stof(string) - locale-independent", [&](){ return DoNotOptimize(Strutil::stof(numstring)); }); - bench ("Strutil::stof(char*) - locale-independent", [&](){ return DoNotOptimize(Strutil::stof(numcstr)); }); - bench ("Strutil::stof(string_view) - locale-independent", [&](){ return DoNotOptimize(Strutil::stof(string_view(numstring))); }); - bench ("locale switch (to classic)", [&](){ std::locale::global (std::locale::classic()); }); -} - - - -void -test_to_string() -{ - std::cout << "Testing to_string\n"; - OIIO_CHECK_EQUAL(Strutil::to_string(3.14f), "3.14"); - OIIO_CHECK_EQUAL(Strutil::to_string(42), "42"); - OIIO_CHECK_EQUAL(Strutil::to_string("hi"), "hi"); - OIIO_CHECK_EQUAL(Strutil::to_string(std::string("hello")), "hello"); - OIIO_CHECK_EQUAL(Strutil::to_string(string_view("hey")), "hey"); - OIIO_CHECK_EQUAL(Strutil::to_string(ustring("yo")), "yo"); -} - - - -void -test_extract() -{ - std::cout << "Testing extract_from_list_string\n"; - std::vector vals; - int n; - - vals.clear(); - vals.resize(3, -1); - n = Strutil::extract_from_list_string(vals, "1"); - OIIO_CHECK_EQUAL(vals, std::vector({ 1, 1, 1 })); - OIIO_CHECK_EQUAL(n, 1); - - vals.clear(); - vals.resize(3, -1); - n = Strutil::extract_from_list_string(vals, "1,3,5"); - OIIO_CHECK_EQUAL(vals, std::vector({ 1, 3, 5 })); - OIIO_CHECK_EQUAL(n, 3); - - vals.clear(); - vals.resize(3, -1); - n = Strutil::extract_from_list_string(vals, "1,,5"); - OIIO_CHECK_EQUAL(vals, std::vector({ 1, -1, 5 })); - OIIO_CHECK_EQUAL(n, 3); - - vals.clear(); - vals.resize(3, -1); - n = Strutil::extract_from_list_string(vals, "abc"); - OIIO_CHECK_EQUAL(vals, std::vector({ 0, 0, 0 })); - OIIO_CHECK_EQUAL(n, 1); - - vals.clear(); - vals.resize(3, -1); - n = Strutil::extract_from_list_string(vals, ""); - OIIO_CHECK_EQUAL(vals, std::vector({ -1, -1, -1 })); - OIIO_CHECK_EQUAL(n, 0); - - vals.clear(); - n = Strutil::extract_from_list_string(vals, "1,3,5"); - OIIO_CHECK_EQUAL(vals, std::vector({ 1, 3, 5 })); - OIIO_CHECK_EQUAL(n, 3); - - // Make sure that the vector-returning version works - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("1", 3, -1.0f), - std::vector({ 1, 1, 1 })); - OIIO_CHECK_EQUAL( - Strutil::extract_from_list_string("1,3,5", 3, -1.0f), - std::vector({ 1, 3, 5 })); - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("1,,5", 3, -1.0f), - std::vector({ 1, -1, 5 })); - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("abc", 3, -1.0f), - std::vector({ 0, 0, 0 })); - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("", 3, -1.0f), - std::vector({ -1, -1, -1 })); - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("1,3,5"), - std::vector({ 1, 3, 5 })); - OIIO_CHECK_EQUAL(Strutil::extract_from_list_string("1,3,5,7"), - std::vector({ 1, 3, 5, 7 })); -} - - - -void -test_safe_strcpy() -{ - std::cout << "Testing safe_strcpy\n"; - { // test in-bounds copy - char result[4] = { '0', '1', '2', '3' }; - Strutil::safe_strcpy(result, "A", 3); - OIIO_CHECK_EQUAL(result[0], 'A'); - OIIO_CHECK_EQUAL(result[1], 0); - OIIO_CHECK_EQUAL(result[2], 0); - OIIO_CHECK_EQUAL(result[3], '3'); - } - { // test over-bounds copy - char result[4] = { '0', '1', '2', '3' }; - Strutil::safe_strcpy(result, "ABC", 3); - OIIO_CHECK_EQUAL(result[0], 'A'); - OIIO_CHECK_EQUAL(result[1], 'B'); - OIIO_CHECK_EQUAL(result[2], 0); - OIIO_CHECK_EQUAL(result[3], '3'); - } - { // test empty string copy - char result[4] = { '0', '1', '2', '3' }; - Strutil::safe_strcpy(result, "", 3); - OIIO_CHECK_EQUAL(result[0], 0); - OIIO_CHECK_EQUAL(result[1], 0); - OIIO_CHECK_EQUAL(result[2], 0); - OIIO_CHECK_EQUAL(result[3], '3'); - } - { // test NULL case - char result[4] = { '0', '1', '2', '3' }; - Strutil::safe_strcpy(result, NULL, 3); - OIIO_CHECK_EQUAL(result[0], 0); - OIIO_CHECK_EQUAL(result[1], 0); - OIIO_CHECK_EQUAL(result[2], 0); - OIIO_CHECK_EQUAL(result[3], '3'); - } -} - - - -void -test_safe_strcat() -{ - std::cout << "Testing safe_strcat\n"; - const size_t len = 8; - { // test in-bounds copy - char result[len + 1] = { 100, 101, 102, 103, 104, 105, 106, 107, 108 }; - Strutil::safe_strcpy(result, "123", len); - Strutil::safe_strcat(result, "ABC", len); - OIIO_CHECK_EQUAL(std::string(result), "123ABC"); - OIIO_CHECK_EQUAL(result[6], 0); - OIIO_CHECK_EQUAL(result[7], 0); - OIIO_CHECK_EQUAL(result[8], 108); - } - { // test over-bounds copy - char result[len + 1] = { 100, 101, 102, 103, 104, 105, 106, 107, 108 }; - Strutil::safe_strcpy(result, "123", len); - Strutil::safe_strcat(result, "ABCDEF", len); - OIIO_CHECK_EQUAL(std::string(result), "123ABCD"); - OIIO_CHECK_EQUAL(result[7], 0); - OIIO_CHECK_EQUAL(result[8], 108); - } - { // test empty string copy - char result[len + 1] = { 100, 101, 102, 103, 104, 105, 106, 107, 108 }; - Strutil::safe_strcpy(result, "123", len); - Strutil::safe_strcat(result, "", len); - OIIO_CHECK_EQUAL(std::string(result), "123"); - OIIO_CHECK_EQUAL(result[3], 0); - OIIO_CHECK_EQUAL(result[4], 0); - OIIO_CHECK_EQUAL(result[5], 0); - OIIO_CHECK_EQUAL(result[6], 0); - OIIO_CHECK_EQUAL(result[7], 0); - OIIO_CHECK_EQUAL(result[8], 108); - } - { // test NULL case - char result[len + 1] = { 100, 101, 102, 103, 104, 105, 106, 107, 108 }; - Strutil::safe_strcpy(result, "123", len); - Strutil::safe_strcat(result, nullptr, len); - OIIO_CHECK_EQUAL(std::string(result), "123"); - OIIO_CHECK_EQUAL(result[3], 0); - OIIO_CHECK_EQUAL(result[4], 0); - OIIO_CHECK_EQUAL(result[5], 0); - OIIO_CHECK_EQUAL(result[6], 0); - OIIO_CHECK_EQUAL(result[7], 0); - OIIO_CHECK_EQUAL(result[8], 108); - } -} - - - -// test safe_strlen and closely related safe_string_view, safe_string -void -test_safe_strlen() -{ - char a[] = "012"; // expected - char b[] = "012" "\0" "456789"; // nul embedded in the string - char c[] = "0123456789001234567890"; // long string - char d[] = ""; // empty string - - Strutil::print("Testing safe_strlen\n"); - OIIO_CHECK_EQUAL(Strutil::safe_strlen(a, 10), 3); - OIIO_CHECK_EQUAL(Strutil::safe_strlen(b, 10), 3); - OIIO_CHECK_EQUAL(Strutil::safe_strlen(c, 10), 10); - OIIO_CHECK_EQUAL(Strutil::safe_strlen(d, 10), 0); - - std::cout << "Testing safe_string_view\n"; - OIIO_CHECK_EQUAL(Strutil::safe_string_view(a, 10), string_view("012")); - OIIO_CHECK_EQUAL(Strutil::safe_string_view(b, 10), string_view("012")); - OIIO_CHECK_EQUAL(Strutil::safe_string_view(c, 10), string_view("0123456789")); - OIIO_CHECK_EQUAL(Strutil::safe_string_view(d, 10), string_view("")); - - std::cout << "Testing safe_string\n"; - OIIO_CHECK_EQUAL(Strutil::safe_string(a, 10), std::string("012")); - OIIO_CHECK_EQUAL(Strutil::safe_string(b, 10), std::string("012")); - OIIO_CHECK_EQUAL(Strutil::safe_string(c, 10), std::string("0123456789")); - OIIO_CHECK_EQUAL(Strutil::safe_string(d, 10), std::string("")); -} - - - -// test some of the trickier methods in string_view. -void -test_string_view() -{ - std::cout << "Testing string_view methods\n"; - const char* cstr = "0123401234"; - std::string s(cstr); - string_view sr(s); - - OIIO_CHECK_EQUAL(string_view(), ""); // Default ctr should be empty - OIIO_CHECK_EQUAL(string_view(cstr), cstr); // Test ctr from char* - OIIO_CHECK_EQUAL(string_view(s), cstr); // test ctr from std::string - OIIO_CHECK_EQUAL(sr, cstr); // These better be the same - -#ifdef OIIO_STD_STRING_VIEW_AVAILABLE - { - std::cout << " Testing OIIO::string_view <-> std::string_view\n"; - std::string_view ssv = sr; - OIIO::string_view osv = ssv; - OIIO_CHECK_EQUAL(osv, sr); - } -#endif - -#ifdef OIIO_EXPERIMENTAL_STRING_VIEW_AVAILABLE - { - std::cout << " Testing OIIO::string_view <-> std::experimental::string_view\n"; - std::experimental::string_view ssv = sr; - OIIO::string_view osv = ssv; - OIIO_CHECK_EQUAL(osv, sr); - } -#endif - - OIIO_CHECK_EQUAL(sr.substr(0), sr); // whole string - OIIO_CHECK_EQUAL(sr.substr(2), "23401234"); // nonzero pos, default n - OIIO_CHECK_EQUAL(sr.substr(2, 3), "234"); // true substrng - OIIO_CHECK_EQUAL(sr.substr(string_view::npos, 3), ""); // npos start - OIIO_CHECK_EQUAL(sr.substr(3, 0), ""); // zero length - OIIO_CHECK_EQUAL(sr.substr(10, 3), ""); // start at end - OIIO_CHECK_EQUAL(sr.substr(18, 3), ""); // start past end - OIIO_CHECK_EQUAL(sr.substr(4, 18), "401234"); // end too big - - OIIO_CHECK_EQUAL(sr.find("123"), s.find("123")); - OIIO_CHECK_EQUAL(sr.find("123"), 1); - OIIO_CHECK_EQUAL(sr.find("143"), string_view::npos); - OIIO_CHECK_EQUAL(sr.find("123", 4), s.find("123", 4)); - OIIO_CHECK_EQUAL(sr.find("123", 4), 6); - OIIO_CHECK_EQUAL(sr.find("143", 4), string_view::npos); - OIIO_CHECK_EQUAL(sr.find(""), s.find("")); - OIIO_CHECK_EQUAL(sr.find(""), 0); - OIIO_CHECK_EQUAL(string_view("").find(""), string_view::npos); - - OIIO_CHECK_EQUAL(sr.find('1'), s.find('1')); - OIIO_CHECK_EQUAL(sr.find('1'), 1); - OIIO_CHECK_EQUAL(sr.find('5'), string_view::npos); - OIIO_CHECK_EQUAL(sr.find('1', 4), s.find('1', 4)); - OIIO_CHECK_EQUAL(sr.find('1', 4), 6); - OIIO_CHECK_EQUAL(sr.find('5', 4), string_view::npos); - - OIIO_CHECK_EQUAL(sr.rfind("123"), s.rfind("123")); - OIIO_CHECK_EQUAL(sr.rfind("123"), 6); - OIIO_CHECK_EQUAL(sr.rfind("1234"), 6); - OIIO_CHECK_EQUAL(sr.rfind("143"), string_view::npos); - OIIO_CHECK_EQUAL(sr.rfind("123", 5), s.rfind("123", 5)); - OIIO_CHECK_EQUAL(sr.rfind("123", 5), 1); - OIIO_CHECK_EQUAL(sr.rfind("123", 4), 1); - OIIO_CHECK_EQUAL(sr.rfind("143", 5), string_view::npos); - OIIO_CHECK_EQUAL(sr.rfind("012", 4), 0); - OIIO_CHECK_EQUAL(sr.rfind(""), s.rfind("")); - OIIO_CHECK_EQUAL(sr.rfind(""), 10); - OIIO_CHECK_EQUAL(string_view("").rfind(""), string_view::npos); - - OIIO_CHECK_EQUAL(sr.rfind('1'), s.rfind('1')); - OIIO_CHECK_EQUAL(sr.rfind('1'), 6); - OIIO_CHECK_EQUAL(sr.rfind('5'), string_view::npos); - OIIO_CHECK_EQUAL(sr.rfind('1', 4), s.rfind('1', 4)); - OIIO_CHECK_EQUAL(sr.rfind('1', 4), 1); - OIIO_CHECK_EQUAL(sr.rfind('5', 4), string_view::npos); - - OIIO_CHECK_EQUAL(sr.find_first_of('2'), 2); - OIIO_CHECK_EQUAL(sr.find_first_of("23"), 2); - OIIO_CHECK_EQUAL(sr.find_first_of("xyz"), string_view::npos); - OIIO_CHECK_EQUAL(sr.find_first_of('2', 5), 7); - OIIO_CHECK_EQUAL(sr.find_first_of("23", 5), 7); - - OIIO_CHECK_EQUAL(sr.find_last_of('2'), 7); - OIIO_CHECK_EQUAL(sr.find_last_of("23"), 8); - OIIO_CHECK_EQUAL(sr.find_last_of("xyz"), string_view::npos); - OIIO_CHECK_EQUAL(sr.find_last_of('2', 5), 2); - OIIO_CHECK_EQUAL(sr.find_last_of("23", 5), 3); - - OIIO_CHECK_EQUAL(sr.find_first_not_of('0'), 1); - OIIO_CHECK_EQUAL(sr.find_first_not_of("012"), 3); - OIIO_CHECK_EQUAL(sr.find_first_not_of('0', 5), 6); - OIIO_CHECK_EQUAL(sr.find_first_not_of("012", 5), 8); - OIIO_CHECK_EQUAL(sr.find_first_of("xyz"), string_view::npos); - - OIIO_CHECK_EQUAL(sr.find_last_not_of('4'), 8); - OIIO_CHECK_EQUAL(sr.find_last_not_of("234"), 6); - OIIO_CHECK_EQUAL(sr.find_last_not_of('4', 5), 3); - OIIO_CHECK_EQUAL(sr.find_last_not_of("234", 5), 1); - OIIO_CHECK_EQUAL(sr.find_last_not_of("xyz"), 9); - OIIO_CHECK_EQUAL(sr.find_last_not_of("01234"), string_view::npos); - - // Just force template expansion of wchar_t variety to make sure it's - // not horribly broken. - wstring_view wsv; - OIIO_CHECK_ASSERT(wsv == wsv); - - // Test the freestanding OIIO::c_str() function - OIIO_CHECK_EQUAL(OIIO::c_str(""), std::string()); - OIIO_CHECK_EQUAL(OIIO::c_str(cstr), cstr); - OIIO_CHECK_EQUAL(OIIO::c_str(s), s); - OIIO_CHECK_EQUAL(OIIO::c_str(ustring(cstr)), ustring(cstr)); - OIIO_CHECK_EQUAL(OIIO::c_str(sr), sr); - OIIO_CHECK_EQUAL(OIIO::c_str(string_view(sr.data(), 2)), std::string("01")); - Strutil::print("addr cstr={:p}, s={:p}, ustring={:p}, sr={:p}, c_str(sr)={:p}\n", - (void*)cstr, (void*)s.c_str(), (void*)ustring(cstr).c_str(), (void*)sr.data(), - (void*)c_str(sr)); -} - - - -void test_parse () -{ - using namespace Strutil; - std::cout << "Testing parse functions\n"; - string_view s; - s = ""; skip_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = " "; skip_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = "foo"; skip_whitespace(s); OIIO_CHECK_EQUAL (s, "foo"); - s = "\tfoo\t"; skip_whitespace(s); OIIO_CHECK_EQUAL (s, "foo\t"); - s = " foo "; skip_whitespace(s); OIIO_CHECK_EQUAL (s, "foo "); - - s = ""; remove_trailing_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = " "; remove_trailing_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = "foo"; remove_trailing_whitespace(s); OIIO_CHECK_EQUAL (s, "foo"); - s = "\tfoo\t"; remove_trailing_whitespace(s); OIIO_CHECK_EQUAL (s, "\tfoo"); - s = " foo "; remove_trailing_whitespace(s); OIIO_CHECK_EQUAL (s, " foo"); - - s = ""; trim_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = " "; trim_whitespace(s); OIIO_CHECK_EQUAL (s, ""); - s = "foo"; trim_whitespace(s); OIIO_CHECK_EQUAL (s, "foo"); - s = "\tfoo\t"; trim_whitespace(s); OIIO_CHECK_EQUAL (s, "foo"); - s = " foo "; trim_whitespace(s); OIIO_CHECK_EQUAL (s, "foo"); - - OIIO_CHECK_EQUAL(trimmed_whitespace(""), ""); - OIIO_CHECK_EQUAL(trimmed_whitespace(" "), ""); - OIIO_CHECK_EQUAL(trimmed_whitespace("foo"), "foo"); - OIIO_CHECK_EQUAL(trimmed_whitespace("\tfoo\t"), "foo"); - OIIO_CHECK_EQUAL(trimmed_whitespace(" foo "), "foo"); - - s = "abc"; OIIO_CHECK_ASSERT (! parse_char (s, 'd') && s == "abc"); - - s = "abc"; OIIO_CHECK_ASSERT (parse_char (s, 'a', true, false) && s == "abc"); - s = "abc"; OIIO_CHECK_ASSERT (parse_char (s, 'a') && s == "bc"); - - s = "abc"; OIIO_CHECK_ASSERT (parse_until_char (s, 'c', false) && s == "abc"); - s = "abc"; OIIO_CHECK_ASSERT (parse_until_char (s, 'c') && s == "c"); - s = "abc"; OIIO_CHECK_ASSERT (! parse_until_char (s, 'd') && s == ""); - - s = "abcdef"; - OIIO_CHECK_ASSERT (! parse_prefix (s, "def", false) && s == "abcdef"); - OIIO_CHECK_ASSERT (parse_prefix (s, "abc", false) && s == "abcdef"); - OIIO_CHECK_ASSERT (parse_prefix (s, "abc") && s == "def"); - - int i = 0; - s = "abc"; OIIO_CHECK_ASSERT (! parse_int (s, i) && s == "abc"); - s = " 143 abc"; OIIO_CHECK_ASSERT (parse_int (s, i) && i == 143 && s == " abc"); - s = " 143 abc"; OIIO_CHECK_ASSERT (parse_int (s, i, false) && i == 143 && s == " 143 abc"); - - float f = 0; - s = "abc"; OIIO_CHECK_ASSERT (! parse_float (s, f) && s == "abc"); - s = " 42.1 abc"; OIIO_CHECK_ASSERT (parse_float (s, f) && f == 42.1f && s == " abc"); - s = " 42.1 abc"; OIIO_CHECK_ASSERT (parse_float (s, f, false) && f == 42.1f && s == " 42.1 abc"); - - { - string_view sv; - float xyz[3] = { 0, 0, 0 }; - sv = "xxx 1 2 3 4 5 6"; - OIIO_CHECK_ASSERT(parse_values(sv, "xxx", xyz, "", "4") - && xyz[0] == 1 && xyz[1] == 2 && xyz[2] == 3 - && sv == " 5 6"); - sv = "xxx 1 2 3 4 5 6"; - OIIO_CHECK_ASSERT(!parse_values(sv, "", xyz)); - sv = "xxx 1 2 3 4 5 6"; - OIIO_CHECK_ASSERT(!parse_values(sv, "xxx", xyz, ",")); - sv = "xxx 1, 2.5,3, 4, 5,6"; - OIIO_CHECK_ASSERT(parse_values(sv, "xxx", xyz, ",") - && xyz[0] == 1 && xyz[1] == 2.5 && xyz[2] == 3 - && sv == ", 4, 5,6"); - } - - string_view ss; - s = "foo bar"; - OIIO_CHECK_ASSERT (parse_string (s, ss) && ss == "foo" && s == " bar"); - s = "\"foo bar\" baz"; - OIIO_CHECK_ASSERT (parse_string (s, ss) && ss == "foo bar" && s == " baz"); - s = "\"foo bar\" baz"; - OIIO_CHECK_ASSERT (parse_string (s, ss, false) && ss == "foo bar" && s == "\"foo bar\" baz"); - s = "\"foo bar\" baz"; - parse_string (s, ss, true, KeepQuotes); - OIIO_CHECK_EQUAL (ss, "\"foo bar\""); - OIIO_CHECK_EQUAL (s, " baz"); - s = "\"foo bar\" baz"; - parse_string (s, ss, true, DeleteQuotes); - OIIO_CHECK_EQUAL (ss, "foo bar"); - OIIO_CHECK_EQUAL (s, " baz"); - s = "'foo bar' baz"; - - s = "\"foo \\\"bar\\\" baz\" blort"; - parse_string (s, ss, true, DeleteQuotes); - OIIO_CHECK_EQUAL (ss, "foo \\\"bar\\\" baz"); - OIIO_CHECK_EQUAL (s, " blort"); - s = "\"foo \\\"bar\\\" baz\" blort"; - parse_string (s, ss, true, KeepQuotes); - OIIO_CHECK_EQUAL (ss, "\"foo \\\"bar\\\" baz\""); - OIIO_CHECK_EQUAL (s, " blort"); - - s = "'foo bar' baz"; - parse_string (s, ss, true, KeepQuotes); - OIIO_CHECK_EQUAL (ss, "'foo bar'"); - OIIO_CHECK_EQUAL (s, " baz"); - s = "'foo bar' baz"; - parse_string (s, ss, true, DeleteQuotes); - OIIO_CHECK_EQUAL (ss, "foo bar"); - OIIO_CHECK_EQUAL (s, " baz"); - - s = " foo bar"; ss = parse_word (s); - OIIO_CHECK_ASSERT (ss == "foo" && s == " bar"); - s = " 14 foo bar"; ss = parse_word (s); - OIIO_CHECK_ASSERT (ss.size() == 0 && s == " 14 foo bar"); - s = "foo14 bar"; ss = parse_word (s); - OIIO_CHECK_ASSERT (ss == "foo" && s == "14 bar"); - s = " foo bar"; ss = parse_word (s, false); - OIIO_CHECK_ASSERT (ss == "foo" && s == " foo bar"); - - s = " foo bar"; ss = parse_identifier (s); - OIIO_CHECK_ASSERT (ss == "foo" && s == " bar"); - s = " 14 foo bar"; ss = parse_identifier (s); - OIIO_CHECK_ASSERT (ss.size() == 0 && s == " 14 foo bar"); - s = " foo_14 bar"; ss = parse_identifier (s); - OIIO_CHECK_ASSERT (ss == "foo_14" && s == " bar"); - s = " foo_14 bar"; ss = parse_identifier (s, false); - OIIO_CHECK_ASSERT (ss == "foo_14" && s == " foo_14 bar"); - s = "fl$orp 14"; ss = parse_identifier (s); - OIIO_CHECK_ASSERT (ss == "fl" && s == "$orp 14"); - s = "fl$orp 14"; ss = parse_identifier (s, "$:", true); - OIIO_CHECK_ASSERT (ss == "fl$orp" && s == " 14"); - - bool b; - s = " foo bar"; b = parse_identifier_if (s, "bar"); - OIIO_CHECK_ASSERT (b == false && s == " foo bar"); - s = " foo bar"; b = parse_identifier_if (s, "foo"); - OIIO_CHECK_ASSERT (b == true && s == " bar"); - s = " foo_14 bar"; b = parse_identifier_if (s, "foo"); - OIIO_CHECK_ASSERT (b == false && s == " foo_14 bar"); - s = " foo_14 bar"; b = parse_identifier_if (s, "foo_14"); - OIIO_CHECK_ASSERT (b == true && s == " bar"); - - s = "foo;bar blow"; ss = parse_until (s, ";"); - OIIO_CHECK_ASSERT (ss == "foo" && s == ";bar blow"); - s = "foo;bar blow"; ss = parse_until (s, "\t "); - OIIO_CHECK_ASSERT (ss == "foo;bar" && s == " blow"); - s = "foo;bar blow"; ss = parse_until (s, "/"); - OIIO_CHECK_ASSERT (ss == "foo;bar blow" && s == ""); - - s = "foo;bar blow"; ss = parse_while (s, "of"); - OIIO_CHECK_ASSERT (ss == "foo" && s == ";bar blow"); - s = "foo;bar blow"; ss = parse_while (s, "abc"); - OIIO_CHECK_ASSERT (ss == "" && s == "foo;bar blow"); - - s = "first line\nsecond line"; - ss = parse_line(s, false); - OIIO_CHECK_ASSERT (ss == "first line\n" && s == "first line\nsecond line"); - ss = parse_line(s); - OIIO_CHECK_ASSERT (ss == "first line\n" && s == "second line"); - ss = parse_line(s); - OIIO_CHECK_ASSERT (ss == "second line" && s == ""); - - s = "[a([b]c)]x]"; ss = parse_nested (s); - OIIO_CHECK_EQUAL (ss, "[a([b]c)]"); OIIO_CHECK_EQUAL (s, "x]"); - s = "[a([b]c)]x]"; ss = parse_nested (s, false); // no eating - OIIO_CHECK_EQUAL (ss, "[a([b]c)]"); OIIO_CHECK_EQUAL (s, "[a([b]c)]x]"); - s = "([a([b]c)])x]"; ss = parse_nested (s); - OIIO_CHECK_EQUAL (ss, "([a([b]c)])"); OIIO_CHECK_EQUAL (s, "x]"); - s = "blah[a([b]c)]x]"; ss = parse_nested (s); - OIIO_CHECK_EQUAL (ss, ""); OIIO_CHECK_EQUAL (s, "blah[a([b]c)]x]"); - s = ""; ss = parse_nested (s); - OIIO_CHECK_EQUAL (ss, ""); OIIO_CHECK_EQUAL (s, ""); - s = "(blah"; ss = parse_nested (s); - OIIO_CHECK_EQUAL (ss, ""); OIIO_CHECK_EQUAL (s, "(blah"); -} - - - -void -test_locale() -{ - std::cout << "Testing float conversion + locale\n"; - std::locale oldloc - = std::locale::global(std::locale::classic()); // save original locale - try { - // Just in case we're on a system that can't do this? - std::locale::global(std::locale("fr_FR.UTF-8")); - const char* numcstr = "123.45"; - std::string numstring(numcstr); - std::cout << "safe float convert (C locale) " << numcstr << " = " - << Strutil::stof(numcstr) << "\n"; - OIIO_CHECK_EQUAL_APPROX(Strutil::stof(numcstr), 123.45f); - std::cout << "unsafe float convert (default locale) " << numcstr << " = " - << atof(numcstr) << "\n"; // NOLINT(cert-err34-c) - OIIO_CHECK_EQUAL_APPROX(atof(numcstr), 123.0f); // NOLINT(cert-err34-c) - - // Verify that Strutil::sprintf does the right thing, even when in a - // comma-based locale. - OIIO_CHECK_EQUAL(Strutil::sprintf("%g", 123.45f), "123.45"); - OIIO_CHECK_EQUAL(Strutil::sprintf("%d", 12345), "12345"); -#if 0 - // Verify that Strutil::fmt::format does the right thing, even when in a - // comma-based locale. - // FIXME: currently broken! Re-enable after {fmt} fixes its ability - // to format floating point numbers locale-independently. - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", 123.45f), "123.45"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{:.3f}", 123.45f), "123.450"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{:g}", 123.45f), "123.45"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", 12345), "12345"); - // Verify that fmt::format does use locale when {:n} - OIIO_CHECK_EQUAL(Strutil::fmt::format("{:g}", 123.45f), "123,45"); - OIIO_CHECK_EQUAL(Strutil::fmt::format("{:n}", 12345), "12,345"); -#endif - std::locale::global(oldloc); // restore - } catch (...) { - } -} - - - -void -test_float_formatting() -{ - // For every possible float value, test that printf("%.9g"), which - // we are sure preserves full precision as text, exactly matches - // Strutil::sprintf("%.9g") and also matches stream output with - // precision(9). VERY EXPENSIVE! Takes tens of minutes to run. - // Don't do this unless you really need to test it. - for (unsigned long long i = 0; i <= (unsigned long long)0xffffffff; ++i) { - unsigned int i32 = (unsigned int)i; - float* f = (float*)&i32; - std::ostringstream sstream; - sstream.precision(9); - sstream << *f; - char buffer[64]; - std::snprintf(buffer, sizeof(buffer), "%.9g", *f); - std::string tiny = Strutil::sprintf("%.9g", *f); - if (sstream.str() != tiny || tiny != buffer) - Strutil::printf( - "%x stream '%s' printf '%s' Strutil::sprintf '%s'\n", i32, - sstream.str(), buffer, tiny); - if ((i32 & 0xfffffff) == 0xfffffff) { - Strutil::printf("%x\n", i32); - fflush(stdout); - } - } -} - - - -template -void -test_string_compare_function_impl() -{ - S foo("foo"); - // Test same string - OIIO_CHECK_EQUAL(foo.compare(T("foo")), 0); - // Test different string of same length - OIIO_CHECK_GE(foo.compare(T("bar")), 0); - OIIO_CHECK_GE(foo.compare(T("fon")), 0); - OIIO_CHECK_LE(foo.compare(T("fop")), 0); - // Test against shorter - OIIO_CHECK_GE(foo.compare(T("a")), 0); - OIIO_CHECK_GE(foo.compare(T("fo")), 0); // common sub, ing - OIIO_CHECK_LE(foo.compare(T("foobar")), 0); // common substring - OIIO_CHECK_GE(foo.compare(T("bart")), 0); - // Test against empty string - OIIO_CHECK_GE(foo.compare(""), 0); -} - - -void -test_string_compare_function() -{ - test_string_compare_function_impl(); - test_string_compare_function_impl(); - test_string_compare_function_impl(); - test_string_compare_function_impl(); - - test_string_compare_function_impl(); - test_string_compare_function_impl(); - test_string_compare_function_impl(); - test_string_compare_function_impl(); -} - - - -void -test_datetime() -{ - using namespace Strutil; - int y = -1, m = -1, d = -1, h = -1, min = -1, s = -1; - - y = -1, m = -1, d = -1, h = -1, min = -1, s = -1; - OIIO_CHECK_ASSERT(scan_datetime("2020-05-01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(y == 2020 && m == 5 && d == 1 && h == 12 && min == 34 && s == 21); - - y = -1, m = -1, d = -1, h = -1, min = -1, s = -1; - OIIO_CHECK_ASSERT(scan_datetime("2020/05/01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(y == 2020 && m == 5 && d == 1 && h == 12 && min == 34 && s == 21); - - y = -1, m = -1, d = -1, h = -1, min = -1, s = -1; - OIIO_CHECK_ASSERT(scan_datetime("2020:05:01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(y == 2020 && m == 5 && d == 1 && h == 12 && min == 34 && s == 21); - - y = -1, m = -1, d = -1, h = -1, min = -1, s = -1; - OIIO_CHECK_ASSERT(scan_datetime("2020:05:01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(y == 2020 && m == 5 && d == 1 && h == 12 && min == 34 && s == 21); - - // No time - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:01", y, m, d, h, min, s)); - // Out of range values - OIIO_CHECK_ASSERT(!scan_datetime("2020:00:01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:13:01 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:00 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:32 12:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:01 24:34:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:01 24:60:21", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:01 12:34:60", y, m, d, h, min, s)); - OIIO_CHECK_ASSERT(!scan_datetime("2020:05:01 12:34:-1", y, m, d, h, min, s)); -} - - - -void -test_edit_distance() -{ - using namespace Strutil; - print("test_edit_distance\n"); - OIIO_CHECK_EQUAL(edit_distance("", ""), 0); - OIIO_CHECK_EQUAL(edit_distance("", "abc"), 3); - OIIO_CHECK_EQUAL(edit_distance("abcd", ""), 4); - OIIO_CHECK_EQUAL(edit_distance("abc", "abc"), 0); - OIIO_CHECK_EQUAL(edit_distance("abc", "ab"), 1); - OIIO_CHECK_EQUAL(edit_distance("abc", "abcde"), 2); - OIIO_CHECK_EQUAL(edit_distance("abc", "abd"), 1); - OIIO_CHECK_EQUAL(edit_distance("sitting", "kitten"), 3); -} - - - -void -test_base64_encode() -{ - OIIO_CHECK_EQUAL(Strutil::base64_encode("foo123,()"), "Zm9vMTIzLCgp"); -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - test_format(); - test_format_custom(); - test_memformat(); - test_timeintervalformat(); - test_get_rest_arguments(); - test_escape_sequences(); - test_wordwrap(); - test_hash(); - test_comparisons(); - test_case(); - test_strip(); - test_splits(); - test_splitsv(); - test_join(); - test_concat(); - test_repeat(); - test_replace(); - test_excise_string_after_head(); - test_numeric_conversion(); - test_to_string(); - test_extract(); - test_safe_strcpy(); - test_safe_strcat(); - test_safe_strlen(); - test_string_view(); - test_parse(); - test_locale(); - // test_float_formatting (); - test_string_compare_function(); - test_datetime(); - test_edit_distance(); - test_base64_encode(); - - Strutil::debug("debug message\n"); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/thread_test.cpp b/Sources/OpenImageIO/libutil/thread_test.cpp deleted file mode 100644 index 8f7474b8..00000000 --- a/Sources/OpenImageIO/libutil/thread_test.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace OIIO; - -static int iterations = 100000; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; -static int threadcounts[] = { 1, 2, 4, 8, 12, 16, 20, - 24, 28, 32, 64, 128, 1024, 1 << 30 }; - - - -static void -getargs(int argc, char* argv[]) -{ - // clang-format off - ArgParse ap; - ap.intro("thread_test\n" OIIO_INTRO_STRING) - .usage("thread_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - // clang-format on - - ap.parse(argc, (const char**)argv); -} - - - -void -do_nothing(int /*thread_id*/) -{ -} - - - -void -time_thread_group() -{ - std::cout << "\nTiming how long it takes to start/end thread_group:\n"; - std::cout << "threads\ttime (best of " << ntrials << ")\n"; - std::cout << "-------\t----------\n"; - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = wedge ? threadcounts[i] : numthreads; - int its = iterations / nt; - - // make a lambda function that spawns a bunch of threads, calls a - // trivial function, then waits for them to finish and tears down - // the group. - auto func = [=]() { - thread_group g; - for (int i = 0; i < nt; ++i) - g.create_thread(do_nothing, i); - g.join_all(); - }; - - double range; - double t = time_trial(func, ntrials, its, &range); - - Strutil::printf("%2d\t%5.1f launch %8.1f threads/sec\n", nt, t, - (nt * its) / t); - if (!wedge) - break; // don't loop if we're not wedging - } -} - - - -void -time_thread_pool() -{ - std::cout << "\nTiming how long it takes to launch from thread_pool:\n"; - std::cout << "threads\ttime (best of " << ntrials << ")\n"; - std::cout << "-------\t----------\n"; - thread_pool* pool(default_thread_pool()); - for (int i = 0; threadcounts[i] <= numthreads; ++i) { - int nt = wedge ? threadcounts[i] : numthreads; - pool->resize(nt); - int its = iterations / nt; - - // make a lambda function that spawns a bunch of threads, calls a - // trivial function, then waits for them to finish and tears down - // the group. - auto func = [=]() { - task_set taskset(pool); - for (int i = 0; i < nt; ++i) { - taskset.push(pool->push(do_nothing)); - } - taskset.wait(); - }; - - double range; - double t = time_trial(func, ntrials, its, &range); - - std::cout << Strutil::sprintf("%2d\t%5.1f launch %8.1f threads/sec\n", - nt, t, (nt * its) / t); - if (!wedge) - break; // don't loop if we're not wedging - } - - Benchmarker bench; - bench("std::this_thread::get_id()", - [=]() { DoNotOptimize(std::this_thread::get_id()); }); - std::thread::id threadid = std::this_thread::get_id(); - bench("register/deregister pool worker", [=]() { - pool->register_worker(threadid); - pool->deregister_worker(threadid); - }); -} - - - -int -main(int argc, char** argv) -{ -#if !defined(NDEBUG) || defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // For the sake of test time, reduce the default iterations for DEBUG, - // CI, and code coverage builds. Explicit use of --iters or --trials - // will override this, since it comes before the getargs() call. - iterations /= 10; - ntrials = 1; -#endif - - getargs(argc, argv); - - std::cout << "hw threads = " << Sysutil::hardware_concurrency() << "\n"; - - time_thread_group(); - time_thread_pool(); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/timer_test.cpp b/Sources/OpenImageIO/libutil/timer_test.cpp deleted file mode 100644 index 74a3a5af..00000000 --- a/Sources/OpenImageIO/libutil/timer_test.cpp +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -using namespace OIIO; - - - -int -main(int argc, char** argv) -{ - ArgParse ap; - // clang-format off - ap.intro("timer_test\n" OIIO_INTRO_STRING) - .usage("timer_test [options]"); - // clang-format on - - ap.parse(argc, (const char**)argv); - - // First, just compute and print how expensive a Timer begin/end is, - // in cycles per second. - { - Timer timer; - int n = 10000000; - int zeroes = 0; - Timer::ticks_t biggest = 0; - for (int i = 0; i < n; ++i) { - Timer t; - Timer::ticks_t ticks = t.ticks(); // force getting the time - if (!ticks) - ++zeroes; - if (ticks > biggest) - biggest = ticks; - } - std::cout << "Timer begin/end cost is " << double(n) / timer() - << " /sec\n"; - std::cout << "Out of " << n << " queries, " << zeroes - << " had no time\n"; - std::cout << "Longest was " << Timer::seconds(biggest) << " s.\n"; - } - - const int interval = 100000; // 1/10 sec - double eps = 0.01; // slop we allow in our timings - double epsrel = 0.1; // Allow an additional 10% relative error -#ifdef __APPLE__ - eps = 0.03; - // On some Apple OSX systems (especially >= 10.10 Yosemite), a feature - // called "timer coalescing" causes sleep/wake events to merge in order - // to produce longer idle periods for the CPU to go into a lower power - // state. This tends to make usleep() less reliable in its timing. - // - // One (permanent) fix is to disable timer coalescing with this command: - // $ sudo sysctl -w kern.timer.coalescing_enabled=0 - // But you want better power use, so instead we just increase the timing - // tolereance on Apple to make this test pass. -# if defined(OIIO_CI) || defined(OIIO_CODE_COVERAGE) - // It seems especially bad on CI runs, so give extra time slop. - eps = 1.0; -# endif -#elif defined(OIIO_CI) - // Also on GitHub Actions CI, timing seems a little imprecise. Give it - // some extra room to avoid spurious CI failures on this test. - eps = 0.25; -#endif - - // Verify that Timer(false) doesn't start - Timer all(Timer::StartNow); - Timer selective(Timer::DontStartNow); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.0, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.1, eps, epsrel); - - // Make sure start/stop work - selective.start(); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.2, eps, epsrel); - selective.stop(); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.3, eps, epsrel); - std::cout << "Checkpoint: All " << all() << " selective " << selective() - << "\n"; - - // Test reset() -- should set selective to 0 and turn it off - selective.reset(); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.0, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.4, eps, epsrel); - selective.start(); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.5, eps, epsrel); - - // Test lap() - double lap = selective.lap(); // lap=.1, select.time_since_start - OIIO_CHECK_EQUAL_THRESH_REL(lap, 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(selective.time_since_start(), 0.0, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.5, eps, epsrel); - Sysutil::usleep(interval); - OIIO_CHECK_EQUAL_THRESH_REL(selective(), 0.2, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(selective.time_since_start(), 0.1, eps, epsrel); - OIIO_CHECK_EQUAL_THRESH_REL(all(), 0.6, eps, epsrel); - std::cout << "Checkpoint2: All " << all() << " selective " << selective() - << "\n"; - - // Test add_ticks/add_seconds - { - Timer t(false); - Sysutil::usleep(100000); - OIIO_CHECK_EQUAL(t.ticking(), false); - t.add_ticks(100); - OIIO_CHECK_EQUAL(t.ticks(), 100); - t.add_ticks(100); - t.reset(); - t.add_seconds(1.0); - OIIO_CHECK_EQUAL_THRESH(t(), 1.0, 1.0e-6); - } - - // Test Benchmarker - Benchmarker bench; - bench("string ctr", [&]() { std::string x("foo"); }); - bench("usleep(1000)", [&]() { Sysutil::usleep(1000); }); - - float val = 0.5; - clobber(val); - simd::vfloat4 val4 = val; - clobber(val4); - - bench("add", [&]() { DoNotOptimize(val + 1.5); }); - bench("cos", [&]() { DoNotOptimize(std::cos(val)); }); - bench("acos", [&]() { DoNotOptimize(std::acos(val)); }); - bench("fast_acos", [&]() { DoNotOptimize(OIIO::fast_acos(val)); }); - - bench("sqrt", [&]() { DoNotOptimize(std::sqrt(val)); }); - bench.work(4); - bench("simd sqrt", [&]() { DoNotOptimize(sqrt(val4)); }); - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/type_traits_test.cpp b/Sources/OpenImageIO/libutil/type_traits_test.cpp deleted file mode 100644 index 2b80ce92..00000000 --- a/Sources/OpenImageIO/libutil/type_traits_test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -#include -#include -#include - - -using namespace OIIO; -using OIIO::Strutil::print; - - -struct test { - std::string size() { return ""; } -}; - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - print("type_traits test\n"); - - // Test has_size_method - { - // std::string has a size() method - OIIO_CHECK_EQUAL(has_size_method::value, true); - // int does not have a size() method - OIIO_CHECK_EQUAL(has_size_method::value, false); - // struct test has a size method, but it returns a non-integral type - OIIO_CHECK_EQUAL(has_size_method::value, false); - } - - // Test has_subscript - { - // std::string has operator[] - OIIO_CHECK_EQUAL(has_subscript::value, true); - // int does not have operator[] - OIIO_CHECK_EQUAL(has_subscript::value, false); - // struct test does not have operator[] - OIIO_CHECK_EQUAL(has_subscript::value, false); - } - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/typedesc_test.cpp b/Sources/OpenImageIO/libutil/typedesc_test.cpp deleted file mode 100644 index cc4d4797..00000000 --- a/Sources/OpenImageIO/libutil/typedesc_test.cpp +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include - -#include - -#if OIIO_USING_IMATH >= 3 -# include -#else -# include -#endif -#include -#include - -#include -#include -#include - - -using namespace OIIO; - - -struct notype { -}; - - - -// Several tests for a TypeDesc type. The template parameter `Ctype` is how -// we store the data in C++. `textrep` is the textual representation, -// like "float". `constructed` is the TypeDesc we are testing, constructed -// (like `TypeDesc(TypeDesc::FLOAT)`). `named` is the pre-constructed alias, -// if there is one (like `TypeFloat`). `value` is data in C++ holding that -// type, and `valuerep` is what `value` is expected to look like when -// rendered as a string. -template -void -test_type(string_view textrep, TypeDesc constructed, - TypeDesc named = TypeUnknown, const CType& value = CType(), - string_view valuerep = "") -{ - Strutil::print("Testing {}\n", textrep); - - // Make sure constructing by name from string matches the TypeDesc where - // it was constructed in C++. - OIIO_CHECK_EQUAL(constructed, TypeDesc(textrep)); - - // Make sure that the pre-constructed alias (if passed) matches the - // fully constructed type. - if (named != TypeUnknown) - OIIO_CHECK_EQUAL(constructed, named); - - // Make sure the size() matches the size of the equivalent C++ data. - OIIO_CHECK_EQUAL(constructed.size(), sizeof(value)); - - // Verify that rendering the sample data `value` as a string matches - // what we expect. - { - tostring_formatting fm; - fm.aggregate_sep = ", "; - fm.array_sep = ", "; - std::string s = tostring(constructed, &value, fm); - if (valuerep.size()) { - OIIO_CHECK_EQUAL(s, valuerep); - Strutil::print(" {}\n", s); - } - } - - { - tostring_formatting fm(tostring_formatting::STDFORMAT); - fm.aggregate_sep = ", "; - fm.array_sep = ", "; -#if FMT_VERSION < 70100 - fm.float_fmt = "{:g}"; -#endif - std::string s = tostring(constructed, &value, fm); - if (valuerep.size()) { - OIIO_CHECK_EQUAL(s, valuerep); - Strutil::print(" {}\n", s); - } - } -} - - - -int -main(int /*argc*/, char* /*argv*/[]) -{ - std::cout << "TypeDesc size = " << sizeof(TypeDesc) << "\n"; - // We expect a TypeDesc to be the same size as a 64 bit int - OIIO_CHECK_EQUAL(sizeof(TypeDesc), sizeof(uint64_t)); - - test_type("float", TypeDesc(TypeDesc::FLOAT), TypeFloat, 1.5f, - "1.5"); - test_type("half", TypeDesc(TypeDesc::HALF), TypeHalf, half(1.5f), - "1.5"); - test_type("double", TypeDesc(TypeDesc::DOUBLE), TypeUnknown, 1.5, - "1.5"); - test_type("int", TypeDesc(TypeDesc::INT), TypeInt, 1, "1"); - test_type("uint", TypeDesc(TypeDesc::UINT), TypeUInt, 1, "1"); - test_type("int", TypeDesc(TypeDesc::INT), TypeInt, 1, "1"); - test_type("uint", TypeDesc(TypeDesc::UINT), TypeUInt, 1, "1"); - test_type("int64", TypeDesc(TypeDesc::INT64), TypeInt64, 1, "1"); - test_type("uint64", TypeDesc(TypeDesc::UINT64), TypeUInt64, 1, - "1"); - test_type("int16", TypeDesc(TypeDesc::INT16), TypeInt16, 1, "1"); - test_type("uint16", TypeDesc(TypeDesc::UINT16), TypeUInt16, 1, - "1"); - test_type("int8", TypeDesc(TypeDesc::INT8), TypeInt8, 1, "1"); - test_type("uint8", TypeDesc(TypeDesc::UINT8), TypeUInt8, 1, "1"); - - // test_type<>("", TypeDesc(TypeDesc::UNKNOWN)); - test_type("color", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::COLOR), - TypeColor, Imath::Color3f(0.0f), "(0, 0, 0)"); - test_type("point", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::POINT), - TypePoint, Imath::V3f(0.0f), "(0, 0, 0)"); - test_type("vector", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::VECTOR), - TypeVector, Imath::V3f(0.0f), "(0, 0, 0)"); - test_type("normal", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::NORMAL), - TypeNormal, Imath::V3f(0.0f), "(0, 0, 0)"); - test_type("matrix33", - TypeDesc(TypeDesc::FLOAT, TypeDesc::MATRIX33), - TypeMatrix33, {}); - test_type("matrix", - TypeDesc(TypeDesc::FLOAT, TypeDesc::MATRIX44), - TypeMatrix44, {}); - test_type("float2", TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2), - TypeFloat2, {}); - test_type("vector2", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, - TypeDesc::VECTOR), - TypeVector2, {}); - test_type("float4", TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC4), - TypeFloat4, {}); - test_type("string", TypeDesc(TypeDesc::STRING), TypeString, - "hello", "hello"); - test_type("ustringhash", TypeDesc(TypeDesc::USTRINGHASH), - TypeUstringhash, ustringhash("hello"), "hello"); - int i2[2] = { 1, 2 }; - test_type("rational", - TypeDesc(TypeDesc::INT, TypeDesc::VEC2, - TypeDesc::RATIONAL), - TypeRational, i2, "1/2"); - test_type("box2", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, - TypeDesc::BOX, 2), - TypeBox2); - test_type("box3", - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::BOX, 2), - TypeBox3); - test_type("box2f", // synonym for box2 - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, - TypeDesc::BOX, 2), - TypeBox2); - test_type("box3f", // synonym for box3 - TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC3, - TypeDesc::BOX, 2), - TypeBox3); - test_type("box2i", - TypeDesc(TypeDesc::INT, TypeDesc::VEC2, - TypeDesc::BOX, 2), - TypeBox2i); - test_type("box3i", - TypeDesc(TypeDesc::INT, TypeDesc::VEC3, - TypeDesc::BOX, 2), - TypeBox3i); - Imf::TimeCode tc; - test_type("timecode", - TypeDesc(TypeDesc::UINT, TypeDesc::SCALAR, - TypeDesc::TIMECODE, 2), - TypeTimeCode, tc); - Imf::KeyCode kc; - test_type("keycode", - TypeDesc(TypeDesc::INT, TypeDesc::SCALAR, - TypeDesc::KEYCODE, 7), - TypeKeyCode, kc); - test_type("pointer", TypeDesc(TypeDesc::PTR), TypePointer, - (void*)(1), "0x1"); - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/libutil/ustring_test.cpp b/Sources/OpenImageIO/libutil/ustring_test.cpp deleted file mode 100644 index 0a7f4eb8..00000000 --- a/Sources/OpenImageIO/libutil/ustring_test.cpp +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright Contributors to the OpenImageIO project. -// SPDX-License-Identifier: Apache-2.0 -// https://github.com/AcademySoftwareFoundation/OpenImageIO - - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if FMT_VERSION >= 90000 -# include -#endif - - -using namespace OIIO; - -// Test ustring's internal locks by creating a bunch of strings in many -// threads simultaneously. Hopefully something will crash if the -// internal table is not being locked properly. - -static int iterations = 1000000; -static int numthreads = 16; -static int ntrials = 1; -static bool verbose = false; -static bool wedge = false; -static int collide = 1; // Millions -static std::vector> strings; - - -static void -getargs(int argc, char* argv[]) -{ - // clang-format off - ArgParse ap; - ap.intro("ustring_test\n" OIIO_INTRO_STRING) - .usage("ustring_test [options]"); - - ap.arg("-v", &verbose) - .help("Verbose mode"); - ap.arg("--threads %d", &numthreads) - .help(Strutil::sprintf("Number of threads (default: %d)", numthreads)); - ap.arg("--iters %d", &iterations) - .help(Strutil::sprintf("Number of iterations (default: %d)", iterations)); - ap.arg("--trials %d", &ntrials) - .help("Number of trials"); - ap.arg("--wedge", &wedge) - .help("Do a wedge test"); - ap.arg("--collide %d", &collide) - .help("Strings (x 1M) to create to make hash collisions"); - // clang-format on - - ap.parse(argc, (const char**)argv); - - const int nhw_threads = Sysutil::hardware_concurrency(); - std::cout << "hw threads = " << nhw_threads << "\n"; - - // user wants to max out the number of threads - if (numthreads <= 0) - numthreads = nhw_threads; -} - - -void -test_ustring() -{ - ustring foo("foo"), bar("bar"), empty(""), uninit; - ustring foobarbaz("foobarbaz"); - - // Size of a ustring is just a pointer - OIIO_CHECK_EQUAL(sizeof(ustring), sizeof(const char*)); - - // Test constructors - OIIO_CHECK_ASSERT(uninit.c_str() == nullptr); - OIIO_CHECK_EQUAL(foo, ustring(string_view("foo"))); - OIIO_CHECK_EQUAL(foo, ustring(std::string("foo"))); - OIIO_CHECK_EQUAL(ustring("hoobarfoo123", 6, 3), ustring("foo")); - OIIO_CHECK_EQUAL(ustring("hoobarfoo123", 3), ustring("hoo")); - OIIO_CHECK_EQUAL(ustring(3, 'x'), ustring("xxx")); - OIIO_CHECK_EQUAL(ustring(foo), foo); - OIIO_CHECK_EQUAL(ustring(foo, 2, 1), ustring("o")); - - // Conversion to char*, string_view, string - OIIO_CHECK_ASSERT(!strcmp(foo.c_str(), "foo")); - OIIO_CHECK_EQUAL(foo.string(), "foo"); - OIIO_CHECK_EQUAL(string_view(foo), "foo"); - OIIO_CHECK_EQUAL(std::string(foo), "foo"); - - // assignment, clear - ustring foo2; - foo2 = foo; - OIIO_CHECK_EQUAL(foo2, foo); - foo2.clear(); - OIIO_CHECK_EQUAL(foo2, uninit); - - // length/size, empty - OIIO_CHECK_EQUAL(foo.length(), 3); - OIIO_CHECK_EQUAL(foo.size(), 3); - OIIO_CHECK_EQUAL(empty.size(), 0); - OIIO_CHECK_EQUAL(uninit.size(), 0); - OIIO_CHECK_ASSERT(empty.empty()); - OIIO_CHECK_ASSERT(uninit.empty()); - OIIO_CHECK_ASSERT(!foo.empty()); - - // Characters - OIIO_CHECK_EQUAL(foo[0], 'f'); - OIIO_CHECK_EQUAL(bar[1], 'a'); - - // copy - char buf[10]; - foo.copy(buf, sizeof(buf) - 1); - OIIO_CHECK_ASSERT(!strcmp(buf, "foo")); - ustring("foobarbaz").copy(buf, 4, 3); - OIIO_CHECK_ASSERT(!strcmp(buf, "barb")); - - // substr - OIIO_CHECK_ASSERT(foobarbaz.substr(3, 4) == ustring("barb")); - - // find - OIIO_CHECK_ASSERT(foobarbaz.find("ba") == 3); - OIIO_CHECK_ASSERT(foobarbaz.find("ba", 4) == 6); - OIIO_CHECK_ASSERT(foobarbaz.rfind("ba") == 6); - OIIO_CHECK_ASSERT(foobarbaz.rfind("ba") == 6); - // FIXME: there are lots of find_* permutations to test, but I'm lazy - - // concat - OIIO_CHECK_EQUAL(ustring::concat(foo, bar), "foobar"); - OIIO_CHECK_EQUAL(ustring::concat(foo, "bar"), "foobar"); - OIIO_CHECK_EQUAL(ustring::concat(foo, ""), "foo"); - OIIO_CHECK_EQUAL(ustring::concat("", foo), "foo"); - ustring longstring(Strutil::repeat("01234567890", 100)); - OIIO_CHECK_EQUAL(ustring::concat(longstring, longstring), - ustring::fmtformat("{}{}", longstring, longstring)); - - // from_hash - OIIO_CHECK_EQUAL(ustring::from_hash(foo.hash()), foo); - OIIO_CHECK_EQUAL(empty.hash(), 0); - OIIO_CHECK_EQUAL(ustring().hash(), 0); - - // make_unique, is_unique, from_unique - const char* foostr = foo.c_str(); - OIIO_CHECK_EQUAL(ustring::make_unique("foo"), foostr); - OIIO_CHECK_EQUAL(ustring::make_unique(string_view()), ustring()); - OIIO_CHECK_EQUAL(ustring::is_unique(foostr), true); - OIIO_CHECK_EQUAL(ustring::is_unique("foo"), false); - OIIO_CHECK_EQUAL(ustring::from_unique(foostr), foo); - - // std::hash - OIIO_CHECK_EQUAL(std::hash {}(foo), foo.hash()); - - // string literals - auto whichtype = "foo"_us; - OIIO_CHECK_EQUAL(whichtype, ustring("foo")); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT(!(std::is_same::value)); -} - - - -void -test_ustringhash() -{ - // Two ustrings - ustring foo("foo"), bar("bar"); - OIIO_CHECK_EQUAL(sizeof(ustringhash), sizeof(size_t)); - - // Make two ustringhash's from strings - ustringhash hfoo("foo"), hbar("bar"); - OIIO_CHECK_EQUAL(hfoo.hash(), foo.hash()); - OIIO_CHECK_EQUAL(hbar.hash(), bar.hash()); - OIIO_CHECK_NE(hfoo.hash(), hbar.hash()); - - // Check copy construction, assignment, ==, != - ustringhash hfoo_copy(hfoo); - OIIO_CHECK_EQUAL(hfoo_copy, hfoo); - OIIO_CHECK_NE(hfoo, hbar); - ustringhash hfoo_copy2; - hfoo_copy2 = hfoo; - OIIO_CHECK_EQUAL(hfoo_copy2, hfoo); - - // Assignment from a ustring - ustringhash hfoo_from_foo = foo; - OIIO_CHECK_EQUAL(hfoo_from_foo, hfoo); - - // Ask a ustring for its ustringhash - OIIO_CHECK_EQUAL(hfoo, foo.uhash()); - - // ustring constructed from a ustringhash - OIIO_CHECK_EQUAL(hfoo_from_foo, foo); - - // string_view and string from ustringhash - string_view foo_sv = hfoo; - OIIO_CHECK_EQUAL(foo_sv, "foo"); - OIIO_CHECK_EQUAL(std::string(foo_sv), "foo"); - - // clear and empty() - OIIO_CHECK_ASSERT(!hfoo_copy2.empty()); - hfoo_copy2.clear(); - OIIO_CHECK_ASSERT(hfoo_copy2.empty()); - - // Can we get to the characters? - OIIO_CHECK_EQUAL(hfoo.c_str(), foo.c_str()); - OIIO_CHECK_EQUAL(hfoo.length(), foo.length()); - OIIO_CHECK_EQUAL(hfoo.size(), foo.size()); - - // Check ==, != with strings, and with ustring's - OIIO_CHECK_EQUAL(hfoo, "foo"); - OIIO_CHECK_NE(hbar, "foo"); - // OIIO_CHECK_EQUAL(hfoo, std::string("foo")); - // OIIO_CHECK_NE(hbar, std::string("foo")); - OIIO_CHECK_EQUAL(hfoo, foo); - OIIO_CHECK_NE(hbar, foo); - - // Conversion to string - OIIO_CHECK_EQUAL(Strutil::to_string(hfoo), "foo"); - - // from_hash - OIIO_CHECK_EQUAL(ustringhash::from_hash(hfoo.hash()), hfoo); - OIIO_CHECK_EQUAL(ustringhash("").hash(), 0); - OIIO_CHECK_EQUAL(ustringhash().hash(), 0); - - // std::hash - OIIO_CHECK_EQUAL(std::hash {}(hfoo), hfoo.hash()); - - // formatting string - OIIO_CHECK_EQUAL(Strutil::fmt::format("{}", hfoo), "foo"); - - // string literals - auto whichtype = "foo"_ush; - OIIO_CHECK_EQUAL(whichtype, ustringhash("foo")); - OIIO_CHECK_ASSERT((std::is_same::value)); - OIIO_CHECK_ASSERT(!(std::is_same::value)); -} - - - -static void -create_lotso_ustrings(int iterations) -{ - OIIO_DASSERT(size_t(iterations) <= strings.size()); - if (verbose) - Strutil::print("thread {}\n", std::this_thread::get_id()); - size_t h = 0; - for (int i = 0; i < iterations; ++i) { - ustring s(strings[i].data()); - h += s.hash(); - } - if (verbose) - Strutil::printf("checksum %08x\n", unsigned(h)); -} - - - -void -benchmark_threaded_ustring_creation() -{ - // prepare the strings we will turn into ustrings to avoid - // including snprintf in the benchmark - strings.resize(wedge ? iterations : iterations / numthreads); - int i = 0; - for (auto& s : strings) - snprintf(s.data(), s.size(), "%d", i++); - - if (wedge) { - timed_thread_wedge(create_lotso_ustrings, numthreads, iterations, - ntrials); - } else { - timed_thread_wedge(create_lotso_ustrings, numthreads, iterations, - ntrials, - numthreads /* just this one thread count */); - } - OIIO_CHECK_ASSERT(true); // If we make it here without crashing, pass -} - - - -void -verify_no_collisions() -{ - // Try to force a hash collision - parallel_for(int64_t(0), int64_t(1000000LL * int64_t(collide)), - [](int64_t i) { ustring u = ustring::fmtformat("{:x}", i); }); - std::vector collisions; - size_t ncollisions = ustring::hash_collisions(&collisions); - OIIO_CHECK_ASSERT(ncollisions == 0); - if (ncollisions) { - Strutil::print(" Hash collisions: {}\n", ncollisions); - for (auto c : collisions) - Strutil::print(" \"{}\" (orig {:08x} rehashed {:08x})\n", c, - Strutil::strhash(c), c.hash()); - } -} - - - -int -main(int argc, char* argv[]) -{ - getargs(argc, argv); - - test_ustring(); - test_ustringhash(); - verify_no_collisions(); - benchmark_threaded_ustring_creation(); - verify_no_collisions(); - - std::cout << "\n" << ustring::getstats(true) << "\n"; - - return unit_test_failures; -} diff --git a/Sources/OpenImageIO/maketx/maketx.cpp b/Sources/OpenImageIO/maketx/maketx.cpp index 2ea9ea74..a1fd4a0c 100644 --- a/Sources/OpenImageIO/maketx/maketx.cpp +++ b/Sources/OpenImageIO/maketx/maketx.cpp @@ -496,47 +496,47 @@ getargs(int argc, char* argv[], ImageSpec& configspec) -int -main(int argc, char* argv[]) -{ - Timer alltimer; - - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - // Globally force classic "C" locale, and turn off all formatting - // internationalization, for the entire maketx application. - std::locale::global(std::locale::classic()); - - ImageSpec configspec; - Filesystem::convert_native_arguments(argc, (const char**)argv); - getargs(argc, argv, configspec); - - OIIO::attribute("threads", nthreads); - - // N.B. This will apply to the default IC that any ImageBuf's get. - ImageCache* ic = ImageCache::create(); // get the shared one - ic->attribute("forcefloat", 1); // Force float upon read - ic->attribute("max_memory_MB", 1024.0); // 1 GB cache - - ImageBufAlgo::MakeTextureMode mode = ImageBufAlgo::MakeTxTexture; - if (shadowmode) - mode = ImageBufAlgo::MakeTxShadow; - if (envlatlmode) - mode = ImageBufAlgo::MakeTxEnvLatl; - if (lightprobemode) - mode = ImageBufAlgo::MakeTxEnvLatlFromLightProbe; - if (bumpslopesmode) - mode = ImageBufAlgo::MakeTxBumpWithSlopes; - - bool ok = ImageBufAlgo::make_texture(mode, filenames[0], outputfilename, - configspec, &std::cout); - if (!ok) - std::cout << "make_texture ERROR: " << OIIO::geterror() << "\n"; - if (runstats) - std::cout << "\n" << ic->getstats(); - - shutdown(); - return ok ? 0 : EXIT_FAILURE; -} +// int +// main(int argc, char* argv[]) +// { +// Timer alltimer; + +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// // Globally force classic "C" locale, and turn off all formatting +// // internationalization, for the entire maketx application. +// std::locale::global(std::locale::classic()); + +// ImageSpec configspec; +// Filesystem::convert_native_arguments(argc, (const char**)argv); +// getargs(argc, argv, configspec); + +// OIIO::attribute("threads", nthreads); + +// // N.B. This will apply to the default IC that any ImageBuf's get. +// ImageCache* ic = ImageCache::create(); // get the shared one +// ic->attribute("forcefloat", 1); // Force float upon read +// ic->attribute("max_memory_MB", 1024.0); // 1 GB cache + +// ImageBufAlgo::MakeTextureMode mode = ImageBufAlgo::MakeTxTexture; +// if (shadowmode) +// mode = ImageBufAlgo::MakeTxShadow; +// if (envlatlmode) +// mode = ImageBufAlgo::MakeTxEnvLatl; +// if (lightprobemode) +// mode = ImageBufAlgo::MakeTxEnvLatlFromLightProbe; +// if (bumpslopesmode) +// mode = ImageBufAlgo::MakeTxBumpWithSlopes; + +// bool ok = ImageBufAlgo::make_texture(mode, filenames[0], outputfilename, +// configspec, &std::cout); +// if (!ok) +// std::cout << "make_texture ERROR: " << OIIO::geterror() << "\n"; +// if (runstats) +// std::cout << "\n" << ic->getstats(); + +// shutdown(); +// return ok ? 0 : EXIT_FAILURE; +// } diff --git a/Sources/OpenImageIO/oiiotool/oiiotool.cpp b/Sources/OpenImageIO/oiiotool/oiiotool.cpp index 49559c69..e26c7e1b 100644 --- a/Sources/OpenImageIO/oiiotool/oiiotool.cpp +++ b/Sources/OpenImageIO/oiiotool/oiiotool.cpp @@ -7348,128 +7348,128 @@ handle_sequence(Oiiotool& ot, int argc, const char** argv) -int -main(int argc, char* argv[]) -{ -#if OIIO_SIMD_SSE && !OIIO_F16C_ENABLED - // We've found old versions of libopenjpeg (either by itself, or - // pulled in by ffmpeg libraries that link against it) that upon its - // dso load will turn on the cpu mode that causes floating point - // denormals get crushed to 0.0 in certain ops, and leave it that - // way! This can give us the wrong results for the particular - // sequence of SSE intrinsics we use to convert half->float for exr - // files containing pixels with denorm values. Can't fix everywhere, - // but at least for oiiotool we know it's safe to just fix the flag - // for our app. We only need to do this if using sse instructions and - // the f16c hardware half<->float ops are not enabled. This does not - // seem to be a problem in libopenjpeg > 1.5. - simd::set_denorms_zero_mode(false); -#endif - { - // DEBUG -- this checks some problematic half->float values if the - // denorms zero mode is not set correctly. Leave this fragment in - // case we ever need to check it again. - // using namespace OIIO::simd; - const unsigned short bad[] = { 59, 12928, 2146, 32805 }; - const half* h = (half*)bad; - simd::vfloat4 vf(h); - if (vf[0] == 0.0f || *h != vf[0]) - Strutil::print(stderr, - "Bad half conversion, code {} {} -> {} " - "(suspect badly set DENORMS_ZERO_MODE)\n", - bad[0], float(h[0]), vf[0]); - } - - // Helpful for debugging to make sure that any crashes dump a stack - // trace. - Sysutil::setup_crash_stacktrace("stdout"); - - // Globally force classic "C" locale, and turn off all formatting - // internationalization, for the entire oiiotool application. - std::locale::global(std::locale::classic()); - - Oiiotool ot; - - ot.imagecache = ImageCache::create(); - OIIO_DASSERT(ot.imagecache); - ot.imagecache->attribute("forcefloat", 1); - ot.imagecache->attribute("max_memory_MB", float(ot.cachesize)); - ot.imagecache->attribute("autotile", ot.autotile); - ot.imagecache->attribute("autoscanline", int(ot.autotile ? 1 : 0)); - - Filesystem::convert_native_arguments(argc, (const char**)argv); - if (handle_sequence(ot, argc, (const char**)argv)) { - // Deal with sequence - - } else { - // Not a sequence - ot.getargs(argc, argv); - if (!ot.ap.aborted()) { - ot.process_pending(); - if (ot.pending_callback()) - ot.warning(ot.pending_callback_name(), - "pending command never executed"); - if (!ot.control_stack.empty()) - ot.warningfmt(ot.control_stack.top().command, "unterminated {}", - ot.control_stack.top().command); - } - } - - if (!ot.printinfo && !ot.printstats && !ot.dumpdata && !ot.dryrun - && !ot.printed_info && !ot.ap.aborted()) { - if (ot.curimg && !ot.curimg->was_output() - && (ot.curimg->metadata_modified() || ot.curimg->pixels_modified())) - ot.warning( - "", - "modified images without outputting them. Did you forget -o?"); - else if (ot.num_outputs == 0) - ot.warning("", "oiiotool produced no output. Did you forget -o?"); - } - - if (ot.runstats) { - double total_time = ot.total_runtime(); - double unaccounted = total_time; - print("\n"); - print("Threads: {}\n", OIIO::get_int_attribute("threads")); - print("oiiotool runtime statistics:\n"); - print(" Total time: {}\n", Strutil::timeintervalformat(total_time, 2)); - for (auto& func : ot.function_times) { - double t = func.second; - if (t > 0.0) { - Strutil::print(" {:<12} : {:5.2f}\n", func.first, t); - unaccounted -= t; - } - } - if (unaccounted > 0.0) - Strutil::print(" {:<12} : {:5.2f}\n", "unaccounted", - unaccounted); - ot.check_peak_memory(); - print(" Peak memory: {}\n", Strutil::memformat(ot.peak_memory)); - print(" Current memory: {}\n", - Strutil::memformat(Sysutil::memory_used())); - { - int64_t current = 0, peak = 0; - OIIO::getattribute("IB_local_mem_current", TypeInt64, ¤t); - OIIO::getattribute("IB_local_mem_peak", TypeInt64, &peak); - print("\nImageBuf local memory: current {}, peak {}\n", - Strutil::memformat(current), Strutil::memformat(peak)); - float opentime = OIIO::get_float_attribute("IB_total_open_time"); - float readtime = OIIO::get_float_attribute( - "IB_total_image_read_time"); - print("ImageBuf direct read time: {}, open time {}\n", - Strutil::timeintervalformat(readtime, 2), - Strutil::timeintervalformat(opentime, 2)); - } - print("\n{}\n", ot.imagecache->getstats(2)); - } - - // Release references of images that might hold onto a shared - // image cache. Otherwise they would get released at static destruction - // time, at which point due to undefined destruction order the shared - // cache might be already gone. - ot.curimg = nullptr; - ot.image_stack.clear(); - ot.image_labels.clear(); - shutdown(); - return ot.return_value; -} +// int +// main(int argc, char* argv[]) +// { +// #if OIIO_SIMD_SSE && !OIIO_F16C_ENABLED +// // We've found old versions of libopenjpeg (either by itself, or +// // pulled in by ffmpeg libraries that link against it) that upon its +// // dso load will turn on the cpu mode that causes floating point +// // denormals get crushed to 0.0 in certain ops, and leave it that +// // way! This can give us the wrong results for the particular +// // sequence of SSE intrinsics we use to convert half->float for exr +// // files containing pixels with denorm values. Can't fix everywhere, +// // but at least for oiiotool we know it's safe to just fix the flag +// // for our app. We only need to do this if using sse instructions and +// // the f16c hardware half<->float ops are not enabled. This does not +// // seem to be a problem in libopenjpeg > 1.5. +// simd::set_denorms_zero_mode(false); +// #endif +// { +// // DEBUG -- this checks some problematic half->float values if the +// // denorms zero mode is not set correctly. Leave this fragment in +// // case we ever need to check it again. +// // using namespace OIIO::simd; +// const unsigned short bad[] = { 59, 12928, 2146, 32805 }; +// const half* h = (half*)bad; +// simd::vfloat4 vf(h); +// if (vf[0] == 0.0f || *h != vf[0]) +// Strutil::print(stderr, +// "Bad half conversion, code {} {} -> {} " +// "(suspect badly set DENORMS_ZERO_MODE)\n", +// bad[0], float(h[0]), vf[0]); +// } + +// // Helpful for debugging to make sure that any crashes dump a stack +// // trace. +// Sysutil::setup_crash_stacktrace("stdout"); + +// // Globally force classic "C" locale, and turn off all formatting +// // internationalization, for the entire oiiotool application. +// std::locale::global(std::locale::classic()); + +// Oiiotool ot; + +// ot.imagecache = ImageCache::create(); +// OIIO_DASSERT(ot.imagecache); +// ot.imagecache->attribute("forcefloat", 1); +// ot.imagecache->attribute("max_memory_MB", float(ot.cachesize)); +// ot.imagecache->attribute("autotile", ot.autotile); +// ot.imagecache->attribute("autoscanline", int(ot.autotile ? 1 : 0)); + +// Filesystem::convert_native_arguments(argc, (const char**)argv); +// if (handle_sequence(ot, argc, (const char**)argv)) { +// // Deal with sequence + +// } else { +// // Not a sequence +// ot.getargs(argc, argv); +// if (!ot.ap.aborted()) { +// ot.process_pending(); +// if (ot.pending_callback()) +// ot.warning(ot.pending_callback_name(), +// "pending command never executed"); +// if (!ot.control_stack.empty()) +// ot.warningfmt(ot.control_stack.top().command, "unterminated {}", +// ot.control_stack.top().command); +// } +// } + +// if (!ot.printinfo && !ot.printstats && !ot.dumpdata && !ot.dryrun +// && !ot.printed_info && !ot.ap.aborted()) { +// if (ot.curimg && !ot.curimg->was_output() +// && (ot.curimg->metadata_modified() || ot.curimg->pixels_modified())) +// ot.warning( +// "", +// "modified images without outputting them. Did you forget -o?"); +// else if (ot.num_outputs == 0) +// ot.warning("", "oiiotool produced no output. Did you forget -o?"); +// } + +// if (ot.runstats) { +// double total_time = ot.total_runtime(); +// double unaccounted = total_time; +// print("\n"); +// print("Threads: {}\n", OIIO::get_int_attribute("threads")); +// print("oiiotool runtime statistics:\n"); +// print(" Total time: {}\n", Strutil::timeintervalformat(total_time, 2)); +// for (auto& func : ot.function_times) { +// double t = func.second; +// if (t > 0.0) { +// Strutil::print(" {:<12} : {:5.2f}\n", func.first, t); +// unaccounted -= t; +// } +// } +// if (unaccounted > 0.0) +// Strutil::print(" {:<12} : {:5.2f}\n", "unaccounted", +// unaccounted); +// ot.check_peak_memory(); +// print(" Peak memory: {}\n", Strutil::memformat(ot.peak_memory)); +// print(" Current memory: {}\n", +// Strutil::memformat(Sysutil::memory_used())); +// { +// int64_t current = 0, peak = 0; +// OIIO::getattribute("IB_local_mem_current", TypeInt64, ¤t); +// OIIO::getattribute("IB_local_mem_peak", TypeInt64, &peak); +// print("\nImageBuf local memory: current {}, peak {}\n", +// Strutil::memformat(current), Strutil::memformat(peak)); +// float opentime = OIIO::get_float_attribute("IB_total_open_time"); +// float readtime = OIIO::get_float_attribute( +// "IB_total_image_read_time"); +// print("ImageBuf direct read time: {}, open time {}\n", +// Strutil::timeintervalformat(readtime, 2), +// Strutil::timeintervalformat(opentime, 2)); +// } +// print("\n{}\n", ot.imagecache->getstats(2)); +// } + +// // Release references of images that might hold onto a shared +// // image cache. Otherwise they would get released at static destruction +// // time, at which point due to undefined destruction order the shared +// // cache might be already gone. +// ot.curimg = nullptr; +// ot.image_stack.clear(); +// ot.image_labels.clear(); +// shutdown(); +// return ot.return_value; +// } diff --git a/Sources/OpenImageIO/testtex/testtex.cpp b/Sources/OpenImageIO/testtex/testtex.cpp index 33e569ab..9bd4e9c1 100644 --- a/Sources/OpenImageIO/testtex/testtex.cpp +++ b/Sources/OpenImageIO/testtex/testtex.cpp @@ -1775,264 +1775,264 @@ make_test_files() -int -main(int argc, const char* argv[]) -{ - Filesystem::convert_native_arguments(argc, argv); - getargs(argc, argv); - - // environment variable TESTTEX_BATCH can force batch mode - string_view testtex_batch = Sysutil::getenv("TESTTEX_BATCH"); - if (testtex_batch.size()) - batch = Strutil::from_string(testtex_batch); - - OIIO::attribute("threads", nthreads); - - texsys = TextureSystem::create(); - Strutil::sync::print("Created texture system\n"); - if (texoptions.size()) - texsys->attribute("options", texoptions); - texsys->attribute("autotile", autotile); - texsys->attribute("automip", (int)automip); - texsys->attribute("deduplicate", (int)dedup); - if (cachesize >= 0) - texsys->attribute("max_memory_MB", cachesize); - else - texsys->getattribute("max_memory_MB", TypeFloat, &cachesize); - if (maxfiles >= 0) - texsys->attribute("max_open_files", maxfiles); - if (searchpath.length()) - texsys->attribute("searchpath", searchpath); - if (nountiled) - texsys->attribute("accept_untiled", 0); - if (nounmipped) - texsys->attribute("accept_unmipped", 0); - texsys->attribute("gray_to_rgb", gray_to_rgb); - texsys->attribute("flip_t", flip_t); - texsys->attribute("stochastic", stochastic); - texcolortransform_id - = std::max(0, texsys->get_colortransform_id(ustring(texcolorspace), - ustring("scene_linear"))); - if (texcolortransform_id > 0) - print("Treating texture as if it is in colorspace {}\n", texcolorspace); - - if (test_construction) { - Timer t; - for (int i = 0; i < 1000000000; ++i) { - TextureOpt opt; - dummyptr = &opt; // This forces the optimizer to keep the loop - } - Strutil::print("TextureOpt construction: {} ns\n", t()); - TextureOpt canonical, copy; - t.reset(); - t.start(); - for (int i = 0; i < 1000000000; ++i) { - copy = canonical; - dummyptr = © // This forces the optimizer to keep the loop - } - Strutil::print("TextureOpt copy: {} ns\n", t()); - } - - if (maketest_template.size() - && Strutil::contains(maketest_template, "")) - udim_tests = true; - - if (num_test_files > 0) { - make_test_files(); - } - - if (testicwrite && filenames.size()) { - test_icwrite(testicwrite); - } - - if (test_getimagespec) { - ImageSpec spec; - for (int i = 0; i < iters; ++i) { - texsys->get_imagespec(filenames[0], 0, spec); - } - iters = 0; - } - - if (gtiname.size()) { - const char* attrib = nullptr; - bool result = texsys->get_texture_info(filenames[0], 0, - ustring(gtiname), TypeString, - &attrib); - if (result) - Strutil::print("Image \"{}\" attrib \"{}\" = \"{}\"\n", - filenames[0], gtiname, attrib); - else - Strutil::print("Image \"{}\" attrib \"{}\" -> not found\n", - filenames[0], gtiname, attrib); - } - - if (test_gettexels) { - test_getimagespec_gettexels(filenames[0]); - iters = 0; - } - - if (testhash) { - TextureSystem::unit_test_hash(); - } - - Imath::M33f scale; - scale.scale(Imath::V2f(0.3, 0.3)); - Imath::M33f rot; - rot.rotate(radians(25.0f)); - Imath::M33f trans; - trans.translate(Imath::V2f(0.75f, 0.25f)); - Imath::M33f persp(2, 0, 0, 0, 0.8, -0.55, 0, 0, 1); - xform = persp * rot * trans * scale; - xform.invert(); - - for (auto f : filenames) { - texture_handles.emplace_back(texsys->get_texture_handle(f)); - // Strutil::print("tex {} -> {:p}\n", f, (void*)texture_handles.back()); - } - - if (threadtimes) { - // If the --iters flag was used, do that number of iterations total - // (divided among the threads). If not supplied (iters will be 1), - // then use a large constant *per thread*. - const int iterations = iters > 1 ? iters : 2000000; - Strutil::print("Workload: {}\n", workload_names[threadtimes]); - Strutil::print("texture cache size = {} MB\n", cachesize); - Strutil::print("hw threads = {}\n", Sysutil::hardware_concurrency()); - Strutil::print("times are best of {} trials\n\n", ntrials); - Strutil::print("threads time (s) speedup efficiency\n"); - Strutil::print("-------- -------- --------- ----------\n"); - - if (nthreads == 0) - nthreads = Sysutil::hardware_concurrency(); - static int threadcounts[] = { 1, 2, 4, 8, 12, 16, - 24, 32, 64, 128, 1024, 1 << 30 }; - float single_thread_time = 0.0f; - for (int i = 0; threadcounts[i] <= nthreads; ++i) { - if (threadcounts[i] < minthreads) - continue; - int nt = wedge ? threadcounts[i] : nthreads; - int its = iters > 1 ? (std::max(1, iters / nt)) : iterations; - int tries = nt <= 2 ? std::min(lowtrials, ntrials) : ntrials; - double range; - float t = (float)time_trial(std::bind(launch_tex_threads, nt, its), - tries, &range); - if (single_thread_time == 0.0f) - single_thread_time = t * nt; - float speedup = single_thread_time / t; - float efficiency = speedup / nt; - Strutil::print( - "{:3} {:8.2f} {:6.1f}x {:6.1f}% range {:.2f}\t({} iters/thread)\n", - nt, t, speedup, efficiency * 100.0f, range, its); - fflush(stdout); - if (!wedge) - break; // don't loop if we're not wedging - } - Strutil::print("\n"); - } else if (iters > 0 && filenames.size()) { - ustring filename(filenames[0]); - if (do_gettextureinfo) - test_gettextureinfo(filenames[0]); - const char* texturetype = "Plain Texture"; - texsys->get_texture_info(filename, 0, ustring("texturetype"), - TypeDesc::STRING, &texturetype); - Timer timer; - if (!strcmp(texturetype, "Plain Texture")) { - if (batch) { - if (nowarp) - test_plain_texture_batch(map_default); - else if (tube) - test_plain_texture_batch(map_tube); - else if (filtertest) - test_plain_texture_batch(map_filtertest); - else - test_plain_texture_batch(map_warp); - - } else { - if (nowarp) - test_plain_texture(map_default); - else if (tube) - test_plain_texture(map_tube); - else if (filtertest) - test_plain_texture(map_filtertest); - else - test_plain_texture(map_warp); - } - } - if (!strcmp(texturetype, "Volume Texture")) { - if (batch) { - test_texture3d_batch(filename, map_default_3D); - } else { - test_texture3d(filename, map_default_3D); - } - } - if (!strcmp(texturetype, "Shadow")) { - test_shadow(filename); - } - if (!strcmp(texturetype, "Environment")) { - if (batch) { - test_environment_batch(filename, map_env_latlong); - } else { - test_environment(filename, map_env_latlong); - } - } - test_getimagespec_gettexels(filename); - if (runstats || verbose) - Strutil::print("Time: {}\n", Strutil::timeintervalformat(timer())); - } - - if (test_statquery) { - Strutil::print("Testing statistics queries:\n"); - int total_files = 0; - texsys->getattribute("total_files", total_files); - Strutil::print(" Total files: {}\n", total_files); - std::vector all_filenames(total_files); - Strutil::print("{}\n", TypeDesc(TypeDesc::STRING, total_files)); - texsys->getattribute("all_filenames", - TypeDesc(TypeDesc::STRING, total_files), - &all_filenames[0]); - for (int i = 0; i < total_files; ++i) { - int timesopened = 0; - int64_t bytesread = 0; - float iotime = 0.0f; - int64_t data_size = 0, file_size = 0; - texsys->get_texture_info(all_filenames[i], 0, - ustring("stat:timesopened"), TypeDesc::INT, - ×opened); - texsys->get_texture_info(all_filenames[i], 0, - ustring("stat:bytesread"), TypeDesc::INT64, - &bytesread); - texsys->get_texture_info(all_filenames[i], 0, - ustring("stat:iotime"), TypeDesc::FLOAT, - &iotime); - texsys->get_texture_info(all_filenames[i], 0, - ustring("stat:image_size"), - TypeDesc::INT64, &data_size); - texsys->get_texture_info(all_filenames[i], 0, - ustring("stat:file_size"), TypeDesc::INT64, - &file_size); - Strutil::print( - " {}: {} opens={}, read={}, time={}, data={}, file={}\n", i, - all_filenames[i], timesopened, Strutil::memformat(bytesread), - Strutil::timeintervalformat(iotime, 2), - Strutil::memformat(data_size), Strutil::memformat(file_size)); - } - } - - if (runstats || verbose) { - Strutil::print("Memory use: {}\n", - Strutil::memformat(Sysutil::memory_used(true))); - Strutil::print("{}\n", texsys->getstats(verbose ? 2 : 1)); - } - TextureSystem::destroy(texsys); - - if (verbose) - Strutil::print("\nustrings: {}\n\n", ustring::getstats(false)); - - // Delete any temporary files we created - for (auto&& f : filenames_to_delete) { - std::string err; - Filesystem::remove(f, err); - } - shutdown(); - return 0; -} +// int +// main(int argc, const char* argv[]) +// { +// Filesystem::convert_native_arguments(argc, argv); +// getargs(argc, argv); + +// // environment variable TESTTEX_BATCH can force batch mode +// string_view testtex_batch = Sysutil::getenv("TESTTEX_BATCH"); +// if (testtex_batch.size()) +// batch = Strutil::from_string(testtex_batch); + +// OIIO::attribute("threads", nthreads); + +// texsys = TextureSystem::create(); +// Strutil::sync::print("Created texture system\n"); +// if (texoptions.size()) +// texsys->attribute("options", texoptions); +// texsys->attribute("autotile", autotile); +// texsys->attribute("automip", (int)automip); +// texsys->attribute("deduplicate", (int)dedup); +// if (cachesize >= 0) +// texsys->attribute("max_memory_MB", cachesize); +// else +// texsys->getattribute("max_memory_MB", TypeFloat, &cachesize); +// if (maxfiles >= 0) +// texsys->attribute("max_open_files", maxfiles); +// if (searchpath.length()) +// texsys->attribute("searchpath", searchpath); +// if (nountiled) +// texsys->attribute("accept_untiled", 0); +// if (nounmipped) +// texsys->attribute("accept_unmipped", 0); +// texsys->attribute("gray_to_rgb", gray_to_rgb); +// texsys->attribute("flip_t", flip_t); +// texsys->attribute("stochastic", stochastic); +// texcolortransform_id +// = std::max(0, texsys->get_colortransform_id(ustring(texcolorspace), +// ustring("scene_linear"))); +// if (texcolortransform_id > 0) +// print("Treating texture as if it is in colorspace {}\n", texcolorspace); + +// if (test_construction) { +// Timer t; +// for (int i = 0; i < 1000000000; ++i) { +// TextureOpt opt; +// dummyptr = &opt; // This forces the optimizer to keep the loop +// } +// Strutil::print("TextureOpt construction: {} ns\n", t()); +// TextureOpt canonical, copy; +// t.reset(); +// t.start(); +// for (int i = 0; i < 1000000000; ++i) { +// copy = canonical; +// dummyptr = © // This forces the optimizer to keep the loop +// } +// Strutil::print("TextureOpt copy: {} ns\n", t()); +// } + +// if (maketest_template.size() +// && Strutil::contains(maketest_template, "")) +// udim_tests = true; + +// if (num_test_files > 0) { +// make_test_files(); +// } + +// if (testicwrite && filenames.size()) { +// test_icwrite(testicwrite); +// } + +// if (test_getimagespec) { +// ImageSpec spec; +// for (int i = 0; i < iters; ++i) { +// texsys->get_imagespec(filenames[0], 0, spec); +// } +// iters = 0; +// } + +// if (gtiname.size()) { +// const char* attrib = nullptr; +// bool result = texsys->get_texture_info(filenames[0], 0, +// ustring(gtiname), TypeString, +// &attrib); +// if (result) +// Strutil::print("Image \"{}\" attrib \"{}\" = \"{}\"\n", +// filenames[0], gtiname, attrib); +// else +// Strutil::print("Image \"{}\" attrib \"{}\" -> not found\n", +// filenames[0], gtiname, attrib); +// } + +// if (test_gettexels) { +// test_getimagespec_gettexels(filenames[0]); +// iters = 0; +// } + +// if (testhash) { +// TextureSystem::unit_test_hash(); +// } + +// Imath::M33f scale; +// scale.scale(Imath::V2f(0.3, 0.3)); +// Imath::M33f rot; +// rot.rotate(radians(25.0f)); +// Imath::M33f trans; +// trans.translate(Imath::V2f(0.75f, 0.25f)); +// Imath::M33f persp(2, 0, 0, 0, 0.8, -0.55, 0, 0, 1); +// xform = persp * rot * trans * scale; +// xform.invert(); + +// for (auto f : filenames) { +// texture_handles.emplace_back(texsys->get_texture_handle(f)); +// // Strutil::print("tex {} -> {:p}\n", f, (void*)texture_handles.back()); +// } + +// if (threadtimes) { +// // If the --iters flag was used, do that number of iterations total +// // (divided among the threads). If not supplied (iters will be 1), +// // then use a large constant *per thread*. +// const int iterations = iters > 1 ? iters : 2000000; +// Strutil::print("Workload: {}\n", workload_names[threadtimes]); +// Strutil::print("texture cache size = {} MB\n", cachesize); +// Strutil::print("hw threads = {}\n", Sysutil::hardware_concurrency()); +// Strutil::print("times are best of {} trials\n\n", ntrials); +// Strutil::print("threads time (s) speedup efficiency\n"); +// Strutil::print("-------- -------- --------- ----------\n"); + +// if (nthreads == 0) +// nthreads = Sysutil::hardware_concurrency(); +// static int threadcounts[] = { 1, 2, 4, 8, 12, 16, +// 24, 32, 64, 128, 1024, 1 << 30 }; +// float single_thread_time = 0.0f; +// for (int i = 0; threadcounts[i] <= nthreads; ++i) { +// if (threadcounts[i] < minthreads) +// continue; +// int nt = wedge ? threadcounts[i] : nthreads; +// int its = iters > 1 ? (std::max(1, iters / nt)) : iterations; +// int tries = nt <= 2 ? std::min(lowtrials, ntrials) : ntrials; +// double range; +// float t = (float)time_trial(std::bind(launch_tex_threads, nt, its), +// tries, &range); +// if (single_thread_time == 0.0f) +// single_thread_time = t * nt; +// float speedup = single_thread_time / t; +// float efficiency = speedup / nt; +// Strutil::print( +// "{:3} {:8.2f} {:6.1f}x {:6.1f}% range {:.2f}\t({} iters/thread)\n", +// nt, t, speedup, efficiency * 100.0f, range, its); +// fflush(stdout); +// if (!wedge) +// break; // don't loop if we're not wedging +// } +// Strutil::print("\n"); +// } else if (iters > 0 && filenames.size()) { +// ustring filename(filenames[0]); +// if (do_gettextureinfo) +// test_gettextureinfo(filenames[0]); +// const char* texturetype = "Plain Texture"; +// texsys->get_texture_info(filename, 0, ustring("texturetype"), +// TypeDesc::STRING, &texturetype); +// Timer timer; +// if (!strcmp(texturetype, "Plain Texture")) { +// if (batch) { +// if (nowarp) +// test_plain_texture_batch(map_default); +// else if (tube) +// test_plain_texture_batch(map_tube); +// else if (filtertest) +// test_plain_texture_batch(map_filtertest); +// else +// test_plain_texture_batch(map_warp); + +// } else { +// if (nowarp) +// test_plain_texture(map_default); +// else if (tube) +// test_plain_texture(map_tube); +// else if (filtertest) +// test_plain_texture(map_filtertest); +// else +// test_plain_texture(map_warp); +// } +// } +// if (!strcmp(texturetype, "Volume Texture")) { +// if (batch) { +// test_texture3d_batch(filename, map_default_3D); +// } else { +// test_texture3d(filename, map_default_3D); +// } +// } +// if (!strcmp(texturetype, "Shadow")) { +// test_shadow(filename); +// } +// if (!strcmp(texturetype, "Environment")) { +// if (batch) { +// test_environment_batch(filename, map_env_latlong); +// } else { +// test_environment(filename, map_env_latlong); +// } +// } +// test_getimagespec_gettexels(filename); +// if (runstats || verbose) +// Strutil::print("Time: {}\n", Strutil::timeintervalformat(timer())); +// } + +// if (test_statquery) { +// Strutil::print("Testing statistics queries:\n"); +// int total_files = 0; +// texsys->getattribute("total_files", total_files); +// Strutil::print(" Total files: {}\n", total_files); +// std::vector all_filenames(total_files); +// Strutil::print("{}\n", TypeDesc(TypeDesc::STRING, total_files)); +// texsys->getattribute("all_filenames", +// TypeDesc(TypeDesc::STRING, total_files), +// &all_filenames[0]); +// for (int i = 0; i < total_files; ++i) { +// int timesopened = 0; +// int64_t bytesread = 0; +// float iotime = 0.0f; +// int64_t data_size = 0, file_size = 0; +// texsys->get_texture_info(all_filenames[i], 0, +// ustring("stat:timesopened"), TypeDesc::INT, +// ×opened); +// texsys->get_texture_info(all_filenames[i], 0, +// ustring("stat:bytesread"), TypeDesc::INT64, +// &bytesread); +// texsys->get_texture_info(all_filenames[i], 0, +// ustring("stat:iotime"), TypeDesc::FLOAT, +// &iotime); +// texsys->get_texture_info(all_filenames[i], 0, +// ustring("stat:image_size"), +// TypeDesc::INT64, &data_size); +// texsys->get_texture_info(all_filenames[i], 0, +// ustring("stat:file_size"), TypeDesc::INT64, +// &file_size); +// Strutil::print( +// " {}: {} opens={}, read={}, time={}, data={}, file={}\n", i, +// all_filenames[i], timesopened, Strutil::memformat(bytesread), +// Strutil::timeintervalformat(iotime, 2), +// Strutil::memformat(data_size), Strutil::memformat(file_size)); +// } +// } + +// if (runstats || verbose) { +// Strutil::print("Memory use: {}\n", +// Strutil::memformat(Sysutil::memory_used(true))); +// Strutil::print("{}\n", texsys->getstats(verbose ? 2 : 1)); +// } +// TextureSystem::destroy(texsys); + +// if (verbose) +// Strutil::print("\nustrings: {}\n\n", ustring::getstats(false)); + +// // Delete any temporary files we created +// for (auto&& f : filenames_to_delete) { +// std::string err; +// Filesystem::remove(f, err); +// } +// shutdown(); +// return 0; +// } diff --git a/Sources/Ptex/PtexHalfTableGen.cpp b/Sources/Ptex/PtexHalfTableGen.cpp index aae1e481..eb4a3780 100644 --- a/Sources/Ptex/PtexHalfTableGen.cpp +++ b/Sources/Ptex/PtexHalfTableGen.cpp @@ -43,30 +43,30 @@ static bool PtexHalfInit(uint32_t* h2fTable, uint16_t* f2hTable) } -int main() -{ - FILE* fp = fopen("PtexHalfTables.h", "w"); - if (!fp) { - perror("Can't write PtexHalfTable.h"); - return 1; - } - uint32_t h2fTable[65536]; - uint16_t f2hTable[512]; - PtexHalfInit(h2fTable, f2hTable); - fprintf(fp, "PTEXAPI uint32_t PtexHalf::h2fTable[65536] = {"); - for (int i = 0; i < 65536; i++) { - if (i % 8 == 0) fprintf(fp, "\n"); - fprintf(fp, " 0x%08x", h2fTable[i]); - if (i != 65535) fprintf(fp, ","); - } - fprintf(fp, "\n};\n"); - fprintf(fp, "PTEXAPI uint16_t PtexHalf::f2hTable[512] = {"); - for (int i = 0; i < 512; i++) { - if (i % 8 == 0) fprintf(fp, "\n"); - fprintf(fp, " 0x%04x", f2hTable[i]); - if (i != 511) fprintf(fp, ","); - } - fprintf(fp, "\n};\n"); - fclose(fp); - return 0; -} +// int main() +// { +// FILE* fp = fopen("PtexHalfTables.h", "w"); +// if (!fp) { +// perror("Can't write PtexHalfTable.h"); +// return 1; +// } +// uint32_t h2fTable[65536]; +// uint16_t f2hTable[512]; +// PtexHalfInit(h2fTable, f2hTable); +// fprintf(fp, "PTEXAPI uint32_t PtexHalf::h2fTable[65536] = {"); +// for (int i = 0; i < 65536; i++) { +// if (i % 8 == 0) fprintf(fp, "\n"); +// fprintf(fp, " 0x%08x", h2fTable[i]); +// if (i != 65535) fprintf(fp, ","); +// } +// fprintf(fp, "\n};\n"); +// fprintf(fp, "PTEXAPI uint16_t PtexHalf::f2hTable[512] = {"); +// for (int i = 0; i < 512; i++) { +// if (i % 8 == 0) fprintf(fp, "\n"); +// fprintf(fp, " 0x%04x", f2hTable[i]); +// if (i != 511) fprintf(fp, ","); +// } +// fprintf(fp, "\n};\n"); +// fclose(fp); +// return 0; +// } diff --git a/Sources/Raw/postprocessing/postprocessing_ph.cpp b/Sources/Raw/postprocessing/postprocessing_ph.cpp deleted file mode 100644 index 170866e7..00000000 --- a/Sources/Raw/postprocessing/postprocessing_ph.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* -*- C++ -*- - * Copyright 2019-2021 LibRaw LLC (info@libraw.org) - * - Placeholder functions to build LibRaw w/o postprocessing tools - - LibRaw is free software; you can redistribute it and/or modify - it under the terms of the one of two licenses as you choose: - -1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 - (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - -2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - (See file LICENSE.CDDL provided in LibRaw distribution archive for details). - - */ - -#include "../internal/libraw_cxx_defs.h" - -int LibRaw::dcraw_process(void) { return LIBRAW_NOT_IMPLEMENTED; } - -void LibRaw::fuji_rotate() {} -void LibRaw::convert_to_rgb_loop(float /*out_cam*/[3][4]) {} -libraw_processed_image_t *LibRaw::dcraw_make_mem_image(int *) { return NULL; } -libraw_processed_image_t *LibRaw::dcraw_make_mem_thumb(int *) { return NULL; } -void LibRaw::lin_interpolate_loop(int * /*code*/, int /*size*/) {} -void LibRaw::scale_colors_loop(float /*scale_mul*/[4]) {} diff --git a/Sources/Raw/preprocessing/preprocessing_ph.cpp b/Sources/Raw/preprocessing/preprocessing_ph.cpp deleted file mode 100644 index 916ece76..00000000 --- a/Sources/Raw/preprocessing/preprocessing_ph.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* -*- C++ -*- - * Copyright 2019-2021 LibRaw LLC (info@libraw.org) - * - Placeholder functions to build LibRaw w/o postprocessing - and preprocessing calls - - LibRaw is free software; you can redistribute it and/or modify - it under the terms of the one of two licenses as you choose: - -1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 - (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - -2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - (See file LICENSE.CDDL provided in LibRaw distribution archive for details). - - */ - -#include "../internal/libraw_cxx_defs.h" - -void LibRaw::copy_fuji_uncropped(unsigned short /*cblack*/[4], - unsigned short * /*dmaxp*/) {} -void LibRaw::copy_bayer(unsigned short /*cblack*/[4], - unsigned short * /*dmaxp*/) {} -void LibRaw::raw2image_start() {} diff --git a/Sources/Raw/write/write_ph.cpp b/Sources/Raw/write/write_ph.cpp deleted file mode 100644 index f82a1bc8..00000000 --- a/Sources/Raw/write/write_ph.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- C++ -*- - * Copyright 2019-2021 LibRaw LLC (info@libraw.org) - * - Placeholder functions to build LibRaw w/o postprocessing - and preprocessing calls - - LibRaw is free software; you can redistribute it and/or modify - it under the terms of the one of two licenses as you choose: - -1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 - (See file LICENSE.LGPL provided in LibRaw distribution archive for details). - -2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 - (See file LICENSE.CDDL provided in LibRaw distribution archive for details). - - */ - -#include "../internal/dcraw_defs.h" -int LibRaw::flip_index(int row, int col) { - if (flip & 4) - SWAP(row, col); - if (flip & 2) - row = iheight - 1 - row; - if (flip & 1) - col = iwidth - 1 - col; - return row * iwidth + col; -} - -void LibRaw::write_ppm_tiff() {} -void LibRaw::jpeg_thumb_writer(FILE *tfp, char *t_humb, int t_humb_length) {} -#if 0 -void LibRaw::ppm_thumb(){} -void LibRaw::jpeg_thumb(){} -void LibRaw::rollei_thumb(){} -void LibRaw::ppm16_thumb(){} -void LibRaw::layer_thumb(){} -#endif \ No newline at end of file diff --git a/Sources/OneTBB/tbbmalloc/CMakeLists.txt b/Sources/TBBMalloc/CMakeLists.txt similarity index 100% rename from Sources/OneTBB/tbbmalloc/CMakeLists.txt rename to Sources/TBBMalloc/CMakeLists.txt diff --git a/Sources/OneTBB/tbbmalloc/Customize.h b/Sources/TBBMalloc/Customize.h similarity index 83% rename from Sources/OneTBB/tbbmalloc/Customize.h rename to Sources/TBBMalloc/Customize.h index 3b2d59e0..27024b1b 100644 --- a/Sources/OneTBB/tbbmalloc/Customize.h +++ b/Sources/TBBMalloc/Customize.h @@ -70,7 +70,7 @@ inline void do_yield() { #define USE_DEFAULT_MEMORY_MAPPING 1 // To support malloc replacement -#include "../tbbmalloc_proxy/proxy.h" +#include "proxy.h" #if MALLOC_UNIXLIKE_OVERLOAD_ENABLED #define malloc_proxy __TBB_malloc_proxy @@ -94,31 +94,31 @@ namespace tbb { namespace detail { namespace d1 { // already defined in "oneapi/tbb/profiling.h" above?? - // enum notify_type {prepare=0, cancel, acquired, releasing}; + enum notify_type {prepare=0, cancel, acquired, releasing}; #if TBB_USE_PROFILING_TOOLS // already defined in "oneapi/tbb/profiling.h" above?? - // inline void call_itt_notify(notify_type t, void *ptr) { - // // unreferenced formal parameter warning - // detail::suppress_unused_warning(ptr); - // switch ( t ) { - // case prepare: - // MALLOC_ITT_SYNC_PREPARE( ptr ); - // break; - // case cancel: - // MALLOC_ITT_SYNC_CANCEL( ptr ); - // break; - // case acquired: - // MALLOC_ITT_SYNC_ACQUIRED( ptr ); - // break; - // case releasing: - // MALLOC_ITT_SYNC_RELEASING( ptr ); - // break; - // } - // } + inline void call_itt_notify(notify_type t, void *ptr) { + // unreferenced formal parameter warning + detail::suppress_unused_warning(ptr); + switch ( t ) { + case prepare: + MALLOC_ITT_SYNC_PREPARE( ptr ); + break; + case cancel: + MALLOC_ITT_SYNC_CANCEL( ptr ); + break; + case acquired: + MALLOC_ITT_SYNC_ACQUIRED( ptr ); + break; + case releasing: + MALLOC_ITT_SYNC_RELEASING( ptr ); + break; + } + } #else // already defined in "oneapi/tbb/profiling.h" above?? - // inline void call_itt_notify(notify_type /*t*/, void * /*ptr*/) {} + inline void call_itt_notify(notify_type /*t*/, void * /*ptr*/) {} #endif // TBB_USE_PROFILING_TOOLS } // namespace d1 diff --git a/Sources/OneTBB/tbbmalloc/MapMemory.h b/Sources/TBBMalloc/MapMemory.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/MapMemory.h rename to Sources/TBBMalloc/MapMemory.h diff --git a/Sources/OneTBB/tbbmalloc/Statistics.h b/Sources/TBBMalloc/Statistics.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/Statistics.h rename to Sources/TBBMalloc/Statistics.h diff --git a/Sources/OneTBB/tbbmalloc/Synchronize.h b/Sources/TBBMalloc/Synchronize.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/Synchronize.h rename to Sources/TBBMalloc/Synchronize.h diff --git a/Sources/OneTBB/tbbmalloc/TypeDefinitions.h b/Sources/TBBMalloc/TypeDefinitions.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/TypeDefinitions.h rename to Sources/TBBMalloc/TypeDefinitions.h diff --git a/Sources/OneTBB/tbbmalloc/backend.cpp b/Sources/TBBMalloc/backend.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc/backend.cpp rename to Sources/TBBMalloc/backend.cpp diff --git a/Sources/OneTBB/tbbmalloc/backend.h b/Sources/TBBMalloc/backend.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/backend.h rename to Sources/TBBMalloc/backend.h diff --git a/Sources/OneTBB/tbbmalloc/backref.cpp b/Sources/TBBMalloc/backref.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc/backref.cpp rename to Sources/TBBMalloc/backref.cpp diff --git a/Sources/OneTBB/tbbmalloc/def/lin32-tbbmalloc.def b/Sources/TBBMalloc/def/lin32-tbbmalloc.def similarity index 100% rename from Sources/OneTBB/tbbmalloc/def/lin32-tbbmalloc.def rename to Sources/TBBMalloc/def/lin32-tbbmalloc.def diff --git a/Sources/OneTBB/tbbmalloc/def/lin64-tbbmalloc.def b/Sources/TBBMalloc/def/lin64-tbbmalloc.def similarity index 100% rename from Sources/OneTBB/tbbmalloc/def/lin64-tbbmalloc.def rename to Sources/TBBMalloc/def/lin64-tbbmalloc.def diff --git a/Sources/OneTBB/tbbmalloc/def/mac64-tbbmalloc.def b/Sources/TBBMalloc/def/mac64-tbbmalloc.def similarity index 100% rename from Sources/OneTBB/tbbmalloc/def/mac64-tbbmalloc.def rename to Sources/TBBMalloc/def/mac64-tbbmalloc.def diff --git a/Sources/OneTBB/tbbmalloc/def/win32-tbbmalloc.def b/Sources/TBBMalloc/def/win32-tbbmalloc.def similarity index 100% rename from Sources/OneTBB/tbbmalloc/def/win32-tbbmalloc.def rename to Sources/TBBMalloc/def/win32-tbbmalloc.def diff --git a/Sources/OneTBB/tbbmalloc/def/win64-tbbmalloc.def b/Sources/TBBMalloc/def/win64-tbbmalloc.def similarity index 100% rename from Sources/OneTBB/tbbmalloc/def/win64-tbbmalloc.def rename to Sources/TBBMalloc/def/win64-tbbmalloc.def diff --git a/Sources/OneTBB/tbbmalloc/frontend.cpp b/Sources/TBBMalloc/frontend.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc/frontend.cpp rename to Sources/TBBMalloc/frontend.cpp diff --git a/Sources/OneTBB/tbbmalloc/large_objects.cpp b/Sources/TBBMalloc/large_objects.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc/large_objects.cpp rename to Sources/TBBMalloc/large_objects.cpp diff --git a/Sources/OneTBB/tbbmalloc/large_objects.h b/Sources/TBBMalloc/large_objects.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/large_objects.h rename to Sources/TBBMalloc/large_objects.h diff --git a/Sources/OneTBB/tbbmalloc/shared_utils.h b/Sources/TBBMalloc/shared_utils.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/shared_utils.h rename to Sources/TBBMalloc/shared_utils.h diff --git a/Sources/OneTBB/tbbmalloc/tbbmalloc.cpp b/Sources/TBBMalloc/tbbmalloc.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc/tbbmalloc.cpp rename to Sources/TBBMalloc/tbbmalloc.cpp diff --git a/Sources/OneTBB/tbbmalloc/tbbmalloc.rc b/Sources/TBBMalloc/tbbmalloc.rc similarity index 100% rename from Sources/OneTBB/tbbmalloc/tbbmalloc.rc rename to Sources/TBBMalloc/tbbmalloc.rc diff --git a/Sources/OneTBB/tbbmalloc/tbbmalloc_internal.h b/Sources/TBBMalloc/tbbmalloc_internal.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/tbbmalloc_internal.h rename to Sources/TBBMalloc/tbbmalloc_internal.h diff --git a/Sources/OneTBB/tbbmalloc/tbbmalloc_internal_api.h b/Sources/TBBMalloc/tbbmalloc_internal_api.h similarity index 100% rename from Sources/OneTBB/tbbmalloc/tbbmalloc_internal_api.h rename to Sources/TBBMalloc/tbbmalloc_internal_api.h diff --git a/Sources/OneTBB/tbbmalloc_proxy/CMakeLists.txt b/Sources/TBBMallocProxy/CMakeLists.txt similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/CMakeLists.txt rename to Sources/TBBMallocProxy/CMakeLists.txt diff --git a/Sources/OneTBB/tbbmalloc_proxy/def/lin32-proxy.def b/Sources/TBBMallocProxy/def/lin32-proxy.def similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/def/lin32-proxy.def rename to Sources/TBBMallocProxy/def/lin32-proxy.def diff --git a/Sources/OneTBB/tbbmalloc_proxy/def/lin64-proxy.def b/Sources/TBBMallocProxy/def/lin64-proxy.def similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/def/lin64-proxy.def rename to Sources/TBBMallocProxy/def/lin64-proxy.def diff --git a/Sources/OneTBB/tbbmalloc_proxy/function_replacement.cpp b/Sources/TBBMallocProxy/function_replacement.cpp similarity index 99% rename from Sources/OneTBB/tbbmalloc_proxy/function_replacement.cpp rename to Sources/TBBMallocProxy/function_replacement.cpp index ad05354f..6891821a 100644 --- a/Sources/OneTBB/tbbmalloc_proxy/function_replacement.cpp +++ b/Sources/TBBMallocProxy/function_replacement.cpp @@ -14,11 +14,13 @@ limitations under the License. */ +#if defined(_WIN32) + #include "oneapi/tbb/detail/_config.h" #include "oneapi/tbb/detail/_assert.h" #include "../tbb/assert_impl.h" -#if !__TBB_WIN8UI_SUPPORT && defined(_WIN32) +#if !__TBB_WIN8UI_SUPPORT #ifndef _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE 1 @@ -580,3 +582,5 @@ extern "C" __declspec(dllexport) int TBB_malloc_replacement_log(char *** functio } #endif /* !__TBB_WIN8UI_SUPPORT && defined(_WIN32) */ + +#endif /* _WIN32 */ \ No newline at end of file diff --git a/Sources/OneTBB/tbbmalloc_proxy/function_replacement.h b/Sources/TBBMallocProxy/function_replacement.h similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/function_replacement.h rename to Sources/TBBMallocProxy/function_replacement.h diff --git a/Sources/OneTBB/tbbmalloc_proxy/proxy.cpp b/Sources/TBBMallocProxy/proxy.cpp similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/proxy.cpp rename to Sources/TBBMallocProxy/proxy.cpp diff --git a/Sources/OneTBB/tbbmalloc_proxy/proxy.h b/Sources/TBBMallocProxy/proxy.h similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/proxy.h rename to Sources/TBBMallocProxy/proxy.h diff --git a/Sources/OneTBB/tbbmalloc_proxy/proxy_overload_osx.h b/Sources/TBBMallocProxy/proxy_overload_osx.h similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/proxy_overload_osx.h rename to Sources/TBBMallocProxy/proxy_overload_osx.h diff --git a/Sources/OneTBB/tbbmalloc_proxy/tbbmalloc_proxy.rc b/Sources/TBBMallocProxy/tbbmalloc_proxy.rc similarity index 100% rename from Sources/OneTBB/tbbmalloc_proxy/tbbmalloc_proxy.rc rename to Sources/TBBMallocProxy/tbbmalloc_proxy.rc diff --git a/Sources/TIFF/mkspans.c b/Sources/TIFF/mkspans.c index 24c63ab7..21112825 100644 --- a/Sources/TIFF/mkspans.c +++ b/Sources/TIFF/mkspans.c @@ -51,26 +51,26 @@ unsigned char runs[256]; printf("\n};\n"); } -main() -{ - unsigned char runs[2][256]; +// main() +// { +// unsigned char runs[2][256]; - memset(runs[0], 0, 256 * sizeof(char)); - memset(runs[1], 0, 256 * sizeof(char)); - { - register int run, runlen, i; - runlen = 1; - for (run = 0x80; run != 0xff; run = (run >> 1) | 0x80) - { - for (i = run - 1; i >= 0; i--) - { - runs[1][run | i] = runlen; - runs[0][(~(run | i)) & 0xff] = runlen; - } - runlen++; - } - runs[1][0xff] = runs[0][0] = 8; - } - dumparray("bruns", runs[0]); - dumparray("wruns", runs[1]); -} +// memset(runs[0], 0, 256 * sizeof(char)); +// memset(runs[1], 0, 256 * sizeof(char)); +// { +// register int run, runlen, i; +// runlen = 1; +// for (run = 0x80; run != 0xff; run = (run >> 1) | 0x80) +// { +// for (i = run - 1; i >= 0; i--) +// { +// runs[1][run | i] = runlen; +// runs[0][(~(run | i)) & 0xff] = runlen; +// } +// runlen++; +// } +// runs[1][0xff] = runs[0][0] = 8; +// } +// dumparray("bruns", runs[0]); +// dumparray("wruns", runs[1]); +// } diff --git a/Sources/TIFF/tif_jpeg.c b/Sources/TIFF/tif_jpeg.c index 250144f2..37405b39 100644 --- a/Sources/TIFF/tif_jpeg.c +++ b/Sources/TIFF/tif_jpeg.c @@ -144,11 +144,12 @@ typedef unsigned char boolean; #define TIFF_JSAMPIMAGE J12SAMPIMAGE #define TIFF_JSAMPROW J12SAMPROW #else -#define BITS_IN_JSAMPLE 8 -#define TIFF_JSAMPLE JSAMPLE -#define TIFF_JSAMPARRAY JSAMPARRAY -#define TIFF_JSAMPIMAGE JSAMPIMAGE -#define TIFF_JSAMPROW JSAMPROW +// j16XXX hack until I clean up TurboJPEG. +#define BITS_IN_JSAMPLE 12 +#define TIFF_JSAMPLE J12SAMPLE +#define TIFF_JSAMPARRAY J12SAMPARRAY +#define TIFF_JSAMPIMAGE J12SAMPIMAGE +#define TIFF_JSAMPROW J12SAMPROW #endif #else #define TIFF_JSAMPLE JSAMPLE diff --git a/Sources/TIFF/tif_ojpeg.c b/Sources/TIFF/tif_ojpeg.c index ea572091..a3aa367a 100644 --- a/Sources/TIFF/tif_ojpeg.c +++ b/Sources/TIFF/tif_ojpeg.c @@ -2713,7 +2713,8 @@ static int jpeg_read_scanlines_encap(OJPEGState *sp, return 0; else { - jpeg_read_scanlines(cinfo, scanlines, max_lines); + // j16XXX hack until I clean up TurboJPEG. + jpeg12_read_scanlines(cinfo, scanlines, max_lines); return 1; } } @@ -2728,7 +2729,8 @@ static int jpeg_read_raw_data_encap(OJPEGState *sp, return 0; else { - jpeg_read_raw_data(cinfo, data, max_lines); + // j16XXX hack until I clean up TurboJPEG. + jpeg12_read_raw_data(cinfo, data, max_lines); return 1; } } diff --git a/Sources/TurboJPEG/cdjpeg.h b/Sources/TurboJPEG/cdjpeg.h index 471b9a3f..f8902e2d 100644 --- a/Sources/TurboJPEG/cdjpeg.h +++ b/Sources/TurboJPEG/cdjpeg.h @@ -110,28 +110,37 @@ typedef struct cdjpeg_progress_mgr *cd_progress_ptr; /* Module selection routines for I/O modules. */ - +#ifdef BMP_SUPPORTED EXTERN(cjpeg_source_ptr) jinit_read_bmp(j_compress_ptr cinfo, boolean use_inversion_array); EXTERN(djpeg_dest_ptr) jinit_write_bmp(j_decompress_ptr cinfo, boolean is_os2, boolean use_inversion_array); +#endif /* BMP_SUPPORTED */ +#ifdef GIF_SUPPORTED EXTERN(cjpeg_source_ptr) jinit_read_gif(j_compress_ptr cinfo); EXTERN(cjpeg_source_ptr) j12init_read_gif(j_compress_ptr cinfo); +#endif /* GIF_SUPPORTED */ #ifdef C_LOSSLESS_SUPPORTED -EXTERN(cjpeg_source_ptr) j16init_read_gif(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(cjpeg_source_ptr) j16init_read_gif(j_compress_ptr cinfo); #endif +#ifdef GIF_SUPPORTED EXTERN(djpeg_dest_ptr) jinit_write_gif(j_decompress_ptr cinfo, boolean is_lzw); EXTERN(djpeg_dest_ptr) j12init_write_gif(j_decompress_ptr cinfo, boolean is_lzw); -EXTERN(cjpeg_source_ptr) jinit_read_ppm(j_compress_ptr cinfo); +#endif /* GIF_SUPPORTED */ +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(cjpeg_source_ptr) jinit_read_ppm(j_compress_ptr cinfo); EXTERN(cjpeg_source_ptr) j12init_read_ppm(j_compress_ptr cinfo); #ifdef C_LOSSLESS_SUPPORTED -EXTERN(cjpeg_source_ptr) j16init_read_ppm(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(cjpeg_source_ptr) j16init_read_ppm(j_compress_ptr cinfo); #endif EXTERN(djpeg_dest_ptr) jinit_write_ppm(j_decompress_ptr cinfo); EXTERN(djpeg_dest_ptr) j12init_write_ppm(j_decompress_ptr cinfo); #ifdef D_LOSSLESS_SUPPORTED -EXTERN(djpeg_dest_ptr) j16init_write_ppm(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(djpeg_dest_ptr) j16init_write_ppm(j_decompress_ptr cinfo); #endif EXTERN(cjpeg_source_ptr) jinit_read_targa(j_compress_ptr cinfo); EXTERN(djpeg_dest_ptr) jinit_write_targa(j_decompress_ptr cinfo); @@ -148,8 +157,10 @@ EXTERN(boolean) set_sample_factors(j_compress_ptr cinfo, char *arg); /* djpeg support routines (in rdcolmap.c) */ -EXTERN(void) read_color_map(j_decompress_ptr cinfo, FILE *infile); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) read_color_map(j_decompress_ptr cinfo, FILE *infile); EXTERN(void) read_color_map_12(j_decompress_ptr cinfo, FILE *infile); +#define read_color_map read_color_map_12 /* common support routines (in cdjpeg.c) */ diff --git a/Sources/TurboJPEG/cjpeg.c b/Sources/TurboJPEG/cjpeg.c index ed649d21..4cc42cfd 100644 --- a/Sources/TurboJPEG/cjpeg.c +++ b/Sources/TurboJPEG/cjpeg.c @@ -121,7 +121,8 @@ select_file_type(j_compress_ptr cinfo, FILE *infile) case 'P': if (cinfo->data_precision == 16) { #ifdef C_LOSSLESS_SUPPORTED - return j16init_read_ppm(cinfo); + // j16XXX hack until I clean up TurboJPEG. + return j12init_read_ppm(cinfo); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); break; @@ -129,7 +130,8 @@ select_file_type(j_compress_ptr cinfo, FILE *infile) } else if (cinfo->data_precision == 12) return j12init_read_ppm(cinfo); else - return jinit_read_ppm(cinfo); + // j16XXX hack until I clean up TurboJPEG. + return j12init_read_ppm(cinfo); #endif #ifdef TARGA_SUPPORTED case 0x00: @@ -616,225 +618,226 @@ my_emit_message(j_common_ptr cinfo, int msg_level) * The main program. */ -int -main(int argc, char **argv) -{ - struct jpeg_compress_struct cinfo; -#ifdef CJPEG_FUZZER - struct my_error_mgr myerr; - struct jpeg_error_mgr &jerr = myerr.pub; -#else - struct jpeg_error_mgr jerr; -#endif - struct cdjpeg_progress_mgr progress; - int file_index; - cjpeg_source_ptr src_mgr; - FILE *input_file = NULL; - FILE *icc_file; - JOCTET *icc_profile = NULL; - long icc_len = 0; - FILE *output_file = NULL; - unsigned char *outbuffer = NULL; - unsigned long outsize = 0; - JDIMENSION num_scanlines; - - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "cjpeg"; /* in case C library doesn't provide it */ - - /* Initialize the JPEG compression object with default error handling. */ - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - /* Add some application-specific error messages (from cderror.h) */ - jerr.addon_message_table = cdjpeg_message_table; - jerr.first_addon_message = JMSG_FIRSTADDONCODE; - jerr.last_addon_message = JMSG_LASTADDONCODE; - - /* Initialize JPEG parameters. - * Much of this may be overridden later. - * In particular, we don't yet know the input file's color space, - * but we need to provide some value for jpeg_set_defaults() to work. - */ - - cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ - jpeg_set_defaults(&cinfo); - - /* Scan command line to find file names. - * It is convenient to use just one switch-parsing routine, but the switch - * values read here are ignored; we will rescan the switches after opening - * the input file. - */ - - file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); - - if (strict) - jerr.emit_message = my_emit_message; - -#ifdef TWO_FILE_COMMANDLINE - if (!memdst) { - /* Must have either -outfile switch or explicit output file name */ - if (outfilename == NULL) { - if (file_index != argc - 2) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - outfilename = argv[file_index + 1]; - } else { - if (file_index != argc - 1) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - } - } -#else - /* Unix style: expect zero or one file name */ - if (file_index < argc - 1) { - fprintf(stderr, "%s: only one input file\n", progname); - usage(); - } -#endif /* TWO_FILE_COMMANDLINE */ - - /* Open the input file. */ - if (file_index < argc) { - if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); - exit(EXIT_FAILURE); - } - } else { - /* default input file is stdin */ - input_file = read_stdin(); - } - - /* Open the output file. */ - if (outfilename != NULL) { - if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, outfilename); - exit(EXIT_FAILURE); - } - } else if (!memdst) { - /* default output file is stdout */ - output_file = write_stdout(); - } - - if (icc_filename != NULL) { - if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); - exit(EXIT_FAILURE); - } - if (fseek(icc_file, 0, SEEK_END) < 0 || - (icc_len = ftell(icc_file)) < 1 || - fseek(icc_file, 0, SEEK_SET) < 0) { - fprintf(stderr, "%s: can't determine size of %s\n", progname, - icc_filename); - exit(EXIT_FAILURE); - } - if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) { - fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname); - fclose(icc_file); - exit(EXIT_FAILURE); - } - if (fread(icc_profile, icc_len, 1, icc_file) < 1) { - fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, - icc_filename); - free(icc_profile); - fclose(icc_file); - exit(EXIT_FAILURE); - } - fclose(icc_file); - } - -#ifdef CJPEG_FUZZER - jerr.error_exit = my_error_exit; - jerr.emit_message = my_emit_message_fuzzer; - if (setjmp(myerr.setjmp_buffer)) - HANDLE_ERROR() -#endif - - if (report) { - start_progress_monitor((j_common_ptr)&cinfo, &progress); - progress.report = report; - } - - /* Figure out the input file format, and set up to read it. */ - src_mgr = select_file_type(&cinfo, input_file); - src_mgr->input_file = input_file; -#ifdef CJPEG_FUZZER - src_mgr->max_pixels = 1048576; -#endif - - /* Read the input file header to obtain file size & colorspace. */ - (*src_mgr->start_input) (&cinfo, src_mgr); - - /* Now that we know input colorspace, fix colorspace-dependent defaults */ - jpeg_default_colorspace(&cinfo); - - /* Adjust default compression parameters by re-parsing the options */ - file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); - - /* Specify data destination for compression */ - if (memdst) - jpeg_mem_dest(&cinfo, &outbuffer, &outsize); - else - jpeg_stdio_dest(&cinfo, output_file); - -#ifdef CJPEG_FUZZER - if (setjmp(myerr.setjmp_buffer)) - HANDLE_ERROR() -#endif - - /* Start compressor */ - jpeg_start_compress(&cinfo, TRUE); - - if (icc_profile != NULL) - jpeg_write_icc_profile(&cinfo, icc_profile, (unsigned int)icc_len); - - /* Process data */ - if (cinfo.data_precision == 16) { -#ifdef C_LOSSLESS_SUPPORTED - while (cinfo.next_scanline < cinfo.image_height) { - num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); - (void)jpeg16_write_scanlines(&cinfo, src_mgr->buffer16, num_scanlines); - } -#else - ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); -#endif - } else if (cinfo.data_precision == 12) { - while (cinfo.next_scanline < cinfo.image_height) { - num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); - (void)jpeg12_write_scanlines(&cinfo, src_mgr->buffer12, num_scanlines); - } - } else { - while (cinfo.next_scanline < cinfo.image_height) { - num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); - (void)jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); - } - } - - /* Finish compression and release memory */ - (*src_mgr->finish_input) (&cinfo, src_mgr); - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - /* Close files, if we opened them */ - if (input_file != stdin) - fclose(input_file); - if (output_file != stdout && output_file != NULL) - fclose(output_file); - - if (report) - end_progress_monitor((j_common_ptr)&cinfo); - - if (memdst) { -#ifndef CJPEG_FUZZER - fprintf(stderr, "Compressed size: %lu bytes\n", outsize); -#endif - free(outbuffer); - } - - free(icc_profile); - - /* All done. */ - return (jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); -} +// int +// main(int argc, char **argv) +// { +// struct jpeg_compress_struct cinfo; +// #ifdef CJPEG_FUZZER +// struct my_error_mgr myerr; +// struct jpeg_error_mgr &jerr = myerr.pub; +// #else +// struct jpeg_error_mgr jerr; +// #endif +// struct cdjpeg_progress_mgr progress; +// int file_index; +// cjpeg_source_ptr src_mgr; +// FILE *input_file = NULL; +// FILE *icc_file; +// JOCTET *icc_profile = NULL; +// long icc_len = 0; +// FILE *output_file = NULL; +// unsigned char *outbuffer = NULL; +// unsigned long outsize = 0; +// JDIMENSION num_scanlines; + +// progname = argv[0]; +// if (progname == NULL || progname[0] == 0) +// progname = "cjpeg"; /* in case C library doesn't provide it */ + +// /* Initialize the JPEG compression object with default error handling. */ +// cinfo.err = jpeg_std_error(&jerr); +// jpeg_create_compress(&cinfo); +// /* Add some application-specific error messages (from cderror.h) */ +// jerr.addon_message_table = cdjpeg_message_table; +// jerr.first_addon_message = JMSG_FIRSTADDONCODE; +// jerr.last_addon_message = JMSG_LASTADDONCODE; + +// /* Initialize JPEG parameters. +// * Much of this may be overridden later. +// * In particular, we don't yet know the input file's color space, +// * but we need to provide some value for jpeg_set_defaults() to work. +// */ + +// cinfo.in_color_space = JCS_RGB; /* arbitrary guess */ +// jpeg_set_defaults(&cinfo); + +// /* Scan command line to find file names. +// * It is convenient to use just one switch-parsing routine, but the switch +// * values read here are ignored; we will rescan the switches after opening +// * the input file. +// */ + +// file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +// if (strict) +// jerr.emit_message = my_emit_message; + +// #ifdef TWO_FILE_COMMANDLINE +// if (!memdst) { +// /* Must have either -outfile switch or explicit output file name */ +// if (outfilename == NULL) { +// if (file_index != argc - 2) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// outfilename = argv[file_index + 1]; +// } else { +// if (file_index != argc - 1) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// } +// } +// #else +// /* Unix style: expect zero or one file name */ +// if (file_index < argc - 1) { +// fprintf(stderr, "%s: only one input file\n", progname); +// usage(); +// } +// #endif /* TWO_FILE_COMMANDLINE */ + +// /* Open the input file. */ +// if (file_index < argc) { +// if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default input file is stdin */ +// input_file = read_stdin(); +// } + +// /* Open the output file. */ +// if (outfilename != NULL) { +// if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, outfilename); +// exit(EXIT_FAILURE); +// } +// } else if (!memdst) { +// /* default output file is stdout */ +// output_file = write_stdout(); +// } + +// if (icc_filename != NULL) { +// if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); +// exit(EXIT_FAILURE); +// } +// if (fseek(icc_file, 0, SEEK_END) < 0 || +// (icc_len = ftell(icc_file)) < 1 || +// fseek(icc_file, 0, SEEK_SET) < 0) { +// fprintf(stderr, "%s: can't determine size of %s\n", progname, +// icc_filename); +// exit(EXIT_FAILURE); +// } +// if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) { +// fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname); +// fclose(icc_file); +// exit(EXIT_FAILURE); +// } +// if (fread(icc_profile, icc_len, 1, icc_file) < 1) { +// fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, +// icc_filename); +// free(icc_profile); +// fclose(icc_file); +// exit(EXIT_FAILURE); +// } +// fclose(icc_file); +// } + +// #ifdef CJPEG_FUZZER +// jerr.error_exit = my_error_exit; +// jerr.emit_message = my_emit_message_fuzzer; +// if (setjmp(myerr.setjmp_buffer)) +// HANDLE_ERROR() +// #endif + +// if (report) { +// start_progress_monitor((j_common_ptr)&cinfo, &progress); +// progress.report = report; +// } + +// /* Figure out the input file format, and set up to read it. */ +// src_mgr = select_file_type(&cinfo, input_file); +// src_mgr->input_file = input_file; +// #ifdef CJPEG_FUZZER +// src_mgr->max_pixels = 1048576; +// #endif + +// /* Read the input file header to obtain file size & colorspace. */ +// (*src_mgr->start_input) (&cinfo, src_mgr); + +// /* Now that we know input colorspace, fix colorspace-dependent defaults */ +// jpeg_default_colorspace(&cinfo); + +// /* Adjust default compression parameters by re-parsing the options */ +// file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + +// /* Specify data destination for compression */ +// if (memdst) +// jpeg_mem_dest(&cinfo, &outbuffer, &outsize); +// else +// jpeg_stdio_dest(&cinfo, output_file); + +// #ifdef CJPEG_FUZZER +// if (setjmp(myerr.setjmp_buffer)) +// HANDLE_ERROR() +// #endif + +// /* Start compressor */ +// jpeg_start_compress(&cinfo, TRUE); + +// if (icc_profile != NULL) +// jpeg_write_icc_profile(&cinfo, icc_profile, (unsigned int)icc_len); + +// /* Process data */ +// if (cinfo.data_precision == 16) { +// #ifdef C_LOSSLESS_SUPPORTED +// while (cinfo.next_scanline < cinfo.image_height) { +// num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); +// // j16XXX hack until I clean up TurboJPEG. +// (void)jpeg12_write_scanlines(&cinfo, src_mgr->buffer12, num_scanlines); +// } +// #else +// ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); +// #endif +// } else if (cinfo.data_precision == 12) { +// while (cinfo.next_scanline < cinfo.image_height) { +// num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); +// (void)jpeg12_write_scanlines(&cinfo, src_mgr->buffer12, num_scanlines); +// } +// } else { +// while (cinfo.next_scanline < cinfo.image_height) { +// num_scanlines = (*src_mgr->get_pixel_rows) (&cinfo, src_mgr); +// (void)jpeg_write_scanlines(&cinfo, src_mgr->buffer, num_scanlines); +// } +// } + +// /* Finish compression and release memory */ +// (*src_mgr->finish_input) (&cinfo, src_mgr); +// jpeg_finish_compress(&cinfo); +// jpeg_destroy_compress(&cinfo); + +// /* Close files, if we opened them */ +// if (input_file != stdin) +// fclose(input_file); +// if (output_file != stdout && output_file != NULL) +// fclose(output_file); + +// if (report) +// end_progress_monitor((j_common_ptr)&cinfo); + +// if (memdst) { +// #ifndef CJPEG_FUZZER +// fprintf(stderr, "Compressed size: %lu bytes\n", outsize); +// #endif +// free(outbuffer); +// } + +// free(icc_profile); + +// /* All done. */ +// return (jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); +// } diff --git a/Sources/TurboJPEG/djpeg.c b/Sources/TurboJPEG/djpeg.c index 4ea5c4bd..6f647519 100644 --- a/Sources/TurboJPEG/djpeg.c +++ b/Sources/TurboJPEG/djpeg.c @@ -333,7 +333,8 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv, if (cinfo->data_precision == 12) read_color_map_12(cinfo, mapfile); else - read_color_map(cinfo, mapfile); + // j16XXX hack until I clean up TurboJPEG. + read_color_map_12(cinfo, mapfile); fclose(mapfile); cinfo->quantize_colors = TRUE; #else @@ -521,411 +522,415 @@ my_emit_message(j_common_ptr cinfo, int msg_level) * The main program. */ -int -main(int argc, char **argv) -{ - struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; - struct cdjpeg_progress_mgr progress; - int file_index; - djpeg_dest_ptr dest_mgr = NULL; - FILE *input_file; - FILE *output_file; - unsigned char *inbuffer = NULL; - unsigned long insize = 0; - JDIMENSION num_scanlines; - - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "djpeg"; /* in case C library doesn't provide it */ - - /* Initialize the JPEG decompression object with default error handling. */ - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_decompress(&cinfo); - /* Add some application-specific error messages (from cderror.h) */ - jerr.addon_message_table = cdjpeg_message_table; - jerr.first_addon_message = JMSG_FIRSTADDONCODE; - jerr.last_addon_message = JMSG_LASTADDONCODE; - - /* Insert custom marker processor for COM and APP12. - * APP12 is used by some digital camera makers for textual info, - * so we provide the ability to display it as text. - * If you like, additional APPn marker types can be selected for display, - * but don't try to override APP0 or APP14 this way (see libjpeg.txt). - */ - jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); - jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 12, print_text_marker); - - /* Scan command line to find file names. */ - /* It is convenient to use just one switch-parsing routine, but the switch - * values read here are ignored; we will rescan the switches after opening - * the input file. - * (Exception: tracing level set here controls verbosity for COM markers - * found during jpeg_read_header...) - */ - - file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); - - if (strict) - jerr.emit_message = my_emit_message; - -#ifdef TWO_FILE_COMMANDLINE - /* Must have either -outfile switch or explicit output file name */ - if (outfilename == NULL) { - if (file_index != argc - 2) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - outfilename = argv[file_index + 1]; - } else { - if (file_index != argc - 1) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - } -#else - /* Unix style: expect zero or one file name */ - if (file_index < argc - 1) { - fprintf(stderr, "%s: only one input file\n", progname); - usage(); - } -#endif /* TWO_FILE_COMMANDLINE */ - - /* Open the input file. */ - if (file_index < argc) { - if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); - exit(EXIT_FAILURE); - } - } else { - /* default input file is stdin */ - input_file = read_stdin(); - } - - /* Open the output file. */ - if (outfilename != NULL) { - if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, outfilename); - exit(EXIT_FAILURE); - } - } else { - /* default output file is stdout */ - output_file = write_stdout(); - } - - if (report || max_scans != 0) { - start_progress_monitor((j_common_ptr)&cinfo, &progress); - progress.report = report; - progress.max_scans = max_scans; - } - - /* Specify data source for decompression */ - if (memsrc) { - size_t nbytes; - do { - inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); - if (inbuffer == NULL) { - fprintf(stderr, "%s: memory allocation failure\n", progname); - exit(EXIT_FAILURE); - } - nbytes = fread(&inbuffer[insize], 1, INPUT_BUF_SIZE, input_file); - if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) { - if (file_index < argc) - fprintf(stderr, "%s: can't read from %s\n", progname, - argv[file_index]); - else - fprintf(stderr, "%s: can't read from stdin\n", progname); - } - insize += (unsigned long)nbytes; - } while (nbytes == INPUT_BUF_SIZE); - fprintf(stderr, "Compressed size: %lu bytes\n", insize); - jpeg_mem_src(&cinfo, inbuffer, insize); - } else - jpeg_stdio_src(&cinfo, input_file); - - /* Read file header, set default decompression parameters */ - (void)jpeg_read_header(&cinfo, TRUE); - - /* Adjust default decompression parameters by re-parsing the options */ - file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); - - /* Initialize the output module now to let it override any crucial - * option settings (for instance, GIF wants to force color quantization). - */ - switch (requested_fmt) { -#ifdef BMP_SUPPORTED - case FMT_BMP: - dest_mgr = jinit_write_bmp(&cinfo, FALSE, TRUE); - break; - case FMT_OS2: - dest_mgr = jinit_write_bmp(&cinfo, TRUE, TRUE); - break; -#endif -#ifdef GIF_SUPPORTED - case FMT_GIF: - if (cinfo.data_precision == 16) - ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); - else if (cinfo.data_precision == 12) - dest_mgr = j12init_write_gif(&cinfo, TRUE); - else - dest_mgr = jinit_write_gif(&cinfo, TRUE); - break; - case FMT_GIF0: - dest_mgr = jinit_write_gif(&cinfo, FALSE); - break; -#endif -#ifdef PPM_SUPPORTED - case FMT_PPM: - if (cinfo.data_precision == 16) -#ifdef D_LOSSLESS_SUPPORTED - dest_mgr = j16init_write_ppm(&cinfo); -#else - ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); -#endif - else if (cinfo.data_precision == 12) - dest_mgr = j12init_write_ppm(&cinfo); - else - dest_mgr = jinit_write_ppm(&cinfo); - break; -#endif -#ifdef TARGA_SUPPORTED - case FMT_TARGA: - dest_mgr = jinit_write_targa(&cinfo); - break; -#endif - default: - ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); - break; - } - dest_mgr->output_file = output_file; - - /* Start decompressor */ - (void)jpeg_start_decompress(&cinfo); - - /* Skip rows */ - if (skip) { - JDIMENSION tmp; - - /* Check for valid skip_end. We cannot check this value until after - * jpeg_start_decompress() is called. Note that we have already verified - * that skip_start <= skip_end. - */ - if (skip_end > cinfo.output_height - 1) { - fprintf(stderr, "%s: skip region exceeds image height %u\n", progname, - cinfo.output_height); - exit(EXIT_FAILURE); - } - - /* Write output file header. This is a hack to ensure that the destination - * manager creates an output image of the proper size. - */ - tmp = cinfo.output_height; - cinfo.output_height -= (skip_end - skip_start + 1); - (*dest_mgr->start_output) (&cinfo, dest_mgr); - cinfo.output_height = tmp; - - if (cinfo.data_precision == 16) - ERREXIT(&cinfo, JERR_NOTIMPL); - else if (cinfo.data_precision == 12) { - /* Process data */ - while (cinfo.output_scanline < skip_start) { - num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - if ((tmp = jpeg12_skip_scanlines(&cinfo, skip_end - skip_start + 1)) != - skip_end - skip_start + 1) { - fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", - progname, tmp, skip_end - skip_start + 1); - exit(EXIT_FAILURE); - } - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - } else { - /* Process data */ - while (cinfo.output_scanline < skip_start) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) != - skip_end - skip_start + 1) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", - progname, tmp, skip_end - skip_start + 1); - exit(EXIT_FAILURE); - } - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - } - - /* Decompress a subregion */ - } else if (crop) { - JDIMENSION tmp; - - /* Check for valid crop dimensions. We cannot check these values until - * after jpeg_start_decompress() is called. - */ - if (crop_x + crop_width > cinfo.output_width || - crop_y + crop_height > cinfo.output_height) { - fprintf(stderr, "%s: crop dimensions exceed image dimensions %u x %u\n", - progname, cinfo.output_width, cinfo.output_height); - exit(EXIT_FAILURE); - } - - if (cinfo.data_precision == 16) - ERREXIT(&cinfo, JERR_NOTIMPL); - else if (cinfo.data_precision == 12) - jpeg12_crop_scanline(&cinfo, &crop_x, &crop_width); - else - jpeg_crop_scanline(&cinfo, &crop_x, &crop_width); - if (dest_mgr->calc_buffer_dimensions) - (*dest_mgr->calc_buffer_dimensions) (&cinfo, dest_mgr); - else - ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); - - /* Write output file header. This is a hack to ensure that the destination - * manager creates an output image of the proper size. - */ - tmp = cinfo.output_height; - cinfo.output_height = crop_height; - (*dest_mgr->start_output) (&cinfo, dest_mgr); - cinfo.output_height = tmp; - - if (cinfo.data_precision == 16) - ERREXIT(&cinfo, JERR_NOTIMPL); - else if (cinfo.data_precision == 12) { - /* Process data */ - if ((tmp = jpeg12_skip_scanlines(&cinfo, crop_y)) != crop_y) { - fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", - progname, tmp, crop_y); - exit(EXIT_FAILURE); - } - while (cinfo.output_scanline < crop_y + crop_height) { - num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - if ((tmp = - jpeg12_skip_scanlines(&cinfo, cinfo.output_height - crop_y - - crop_height)) != - cinfo.output_height - crop_y - crop_height) { - fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", - progname, tmp, cinfo.output_height - crop_y - crop_height); - exit(EXIT_FAILURE); - } - } else { - /* Process data */ - if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", - progname, tmp, crop_y); - exit(EXIT_FAILURE); - } - while (cinfo.output_scanline < crop_y + crop_height) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - if ((tmp = - jpeg_skip_scanlines(&cinfo, - cinfo.output_height - crop_y - crop_height)) != - cinfo.output_height - crop_y - crop_height) { - fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", - progname, tmp, cinfo.output_height - crop_y - crop_height); - exit(EXIT_FAILURE); - } - } - - /* Normal full-image decompress */ - } else { - /* Write output file header */ - (*dest_mgr->start_output) (&cinfo, dest_mgr); - - if (cinfo.data_precision == 16) { -#ifdef D_LOSSLESS_SUPPORTED - /* Process data */ - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg16_read_scanlines(&cinfo, dest_mgr->buffer16, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } -#else - ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); -#endif - } else if (cinfo.data_precision == 12) { - /* Process data */ - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - } else { - /* Process data */ - while (cinfo.output_scanline < cinfo.output_height) { - num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, - dest_mgr->buffer_height); - (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); - } - } - } - - /* Hack: count final pass as done in case finish_output does an extra pass. - * The library won't have updated completed_passes. - */ - if (report || max_scans != 0) - progress.pub.completed_passes = progress.pub.total_passes; - - if (icc_filename != NULL) { - FILE *icc_file; - JOCTET *icc_profile; - unsigned int icc_len; - - if ((icc_file = fopen(icc_filename, WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); - exit(EXIT_FAILURE); - } - if (jpeg_read_icc_profile(&cinfo, &icc_profile, &icc_len)) { - if (fwrite(icc_profile, icc_len, 1, icc_file) < 1) { - fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, - icc_filename); - free(icc_profile); - fclose(icc_file); - exit(EXIT_FAILURE); - } - free(icc_profile); - fclose(icc_file); - } else if (cinfo.err->msg_code != JWRN_BOGUS_ICC) - fprintf(stderr, "%s: no ICC profile data in JPEG file\n", progname); - } - - /* Finish decompression and release memory. - * I must do it in this order because output module has allocated memory - * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. - */ - (*dest_mgr->finish_output) (&cinfo, dest_mgr); - (void)jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - - /* Close files, if we opened them */ - if (input_file != stdin) - fclose(input_file); - if (output_file != stdout) - fclose(output_file); - - if (report || max_scans != 0) - end_progress_monitor((j_common_ptr)&cinfo); - - if (memsrc) - free(inbuffer); - - /* All done. */ - exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); - return 0; /* suppress no-return-value warnings */ -} +// int +// main(int argc, char **argv) +// { +// struct jpeg_decompress_struct cinfo; +// struct jpeg_error_mgr jerr; +// struct cdjpeg_progress_mgr progress; +// int file_index; +// djpeg_dest_ptr dest_mgr = NULL; +// FILE *input_file; +// FILE *output_file; +// unsigned char *inbuffer = NULL; +// unsigned long insize = 0; +// JDIMENSION num_scanlines; + +// progname = argv[0]; +// if (progname == NULL || progname[0] == 0) +// progname = "djpeg"; /* in case C library doesn't provide it */ + +// /* Initialize the JPEG decompression object with default error handling. */ +// cinfo.err = jpeg_std_error(&jerr); +// jpeg_create_decompress(&cinfo); +// /* Add some application-specific error messages (from cderror.h) */ +// jerr.addon_message_table = cdjpeg_message_table; +// jerr.first_addon_message = JMSG_FIRSTADDONCODE; +// jerr.last_addon_message = JMSG_LASTADDONCODE; + +// /* Insert custom marker processor for COM and APP12. +// * APP12 is used by some digital camera makers for textual info, +// * so we provide the ability to display it as text. +// * If you like, additional APPn marker types can be selected for display, +// * but don't try to override APP0 or APP14 this way (see libjpeg.txt). +// */ +// jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); +// jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 12, print_text_marker); + +// /* Scan command line to find file names. */ +// /* It is convenient to use just one switch-parsing routine, but the switch +// * values read here are ignored; we will rescan the switches after opening +// * the input file. +// * (Exception: tracing level set here controls verbosity for COM markers +// * found during jpeg_read_header...) +// */ + +// file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); + +// if (strict) +// jerr.emit_message = my_emit_message; + +// #ifdef TWO_FILE_COMMANDLINE +// /* Must have either -outfile switch or explicit output file name */ +// if (outfilename == NULL) { +// if (file_index != argc - 2) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// outfilename = argv[file_index + 1]; +// } else { +// if (file_index != argc - 1) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// } +// #else +// /* Unix style: expect zero or one file name */ +// if (file_index < argc - 1) { +// fprintf(stderr, "%s: only one input file\n", progname); +// usage(); +// } +// #endif /* TWO_FILE_COMMANDLINE */ + +// /* Open the input file. */ +// if (file_index < argc) { +// if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default input file is stdin */ +// input_file = read_stdin(); +// } + +// /* Open the output file. */ +// if (outfilename != NULL) { +// if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, outfilename); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default output file is stdout */ +// output_file = write_stdout(); +// } + +// if (report || max_scans != 0) { +// start_progress_monitor((j_common_ptr)&cinfo, &progress); +// progress.report = report; +// progress.max_scans = max_scans; +// } + +// /* Specify data source for decompression */ +// if (memsrc) { +// size_t nbytes; +// do { +// inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); +// if (inbuffer == NULL) { +// fprintf(stderr, "%s: memory allocation failure\n", progname); +// exit(EXIT_FAILURE); +// } +// nbytes = fread(&inbuffer[insize], 1, INPUT_BUF_SIZE, input_file); +// if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) { +// if (file_index < argc) +// fprintf(stderr, "%s: can't read from %s\n", progname, +// argv[file_index]); +// else +// fprintf(stderr, "%s: can't read from stdin\n", progname); +// } +// insize += (unsigned long)nbytes; +// } while (nbytes == INPUT_BUF_SIZE); +// fprintf(stderr, "Compressed size: %lu bytes\n", insize); +// jpeg_mem_src(&cinfo, inbuffer, insize); +// } else +// jpeg_stdio_src(&cinfo, input_file); + +// /* Read file header, set default decompression parameters */ +// (void)jpeg_read_header(&cinfo, TRUE); + +// /* Adjust default decompression parameters by re-parsing the options */ +// file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); + +// /* Initialize the output module now to let it override any crucial +// * option settings (for instance, GIF wants to force color quantization). +// */ +// switch (requested_fmt) { +// #ifdef BMP_SUPPORTED +// case FMT_BMP: +// dest_mgr = jinit_write_bmp(&cinfo, FALSE, TRUE); +// break; +// case FMT_OS2: +// dest_mgr = jinit_write_bmp(&cinfo, TRUE, TRUE); +// break; +// #endif +// #ifdef GIF_SUPPORTED +// case FMT_GIF: +// if (cinfo.data_precision == 16) +// ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); +// else if (cinfo.data_precision == 12) +// dest_mgr = j12init_write_gif(&cinfo, TRUE); +// else +// dest_mgr = jinit_write_gif(&cinfo, TRUE); +// break; +// case FMT_GIF0: +// dest_mgr = jinit_write_gif(&cinfo, FALSE); +// break; +// #endif +// #ifdef PPM_SUPPORTED +// case FMT_PPM: +// if (cinfo.data_precision == 16) +// #ifdef D_LOSSLESS_SUPPORTED +// // j16XXX hack until I clean up TurboJPEG. +// dest_mgr = j12init_write_ppm(&cinfo); +// #else +// ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); +// #endif +// else if (cinfo.data_precision == 12) +// dest_mgr = j12init_write_ppm(&cinfo); +// else +// // j16XXX hack until I clean up TurboJPEG. +// dest_mgr = j12init_write_ppm(&cinfo); +// break; +// #endif +// #ifdef TARGA_SUPPORTED +// case FMT_TARGA: +// dest_mgr = jinit_write_targa(&cinfo); +// break; +// #endif +// default: +// ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); +// break; +// } +// dest_mgr->output_file = output_file; + +// /* Start decompressor */ +// (void)jpeg_start_decompress(&cinfo); + +// /* Skip rows */ +// if (skip) { +// JDIMENSION tmp; + +// /* Check for valid skip_end. We cannot check this value until after +// * jpeg_start_decompress() is called. Note that we have already verified +// * that skip_start <= skip_end. +// */ +// if (skip_end > cinfo.output_height - 1) { +// fprintf(stderr, "%s: skip region exceeds image height %u\n", progname, +// cinfo.output_height); +// exit(EXIT_FAILURE); +// } + +// /* Write output file header. This is a hack to ensure that the destination +// * manager creates an output image of the proper size. +// */ +// tmp = cinfo.output_height; +// cinfo.output_height -= (skip_end - skip_start + 1); +// (*dest_mgr->start_output) (&cinfo, dest_mgr); +// cinfo.output_height = tmp; + +// if (cinfo.data_precision == 16) +// ERREXIT(&cinfo, JERR_NOTIMPL); +// else if (cinfo.data_precision == 12) { +// /* Process data */ +// while (cinfo.output_scanline < skip_start) { +// num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// if ((tmp = jpeg12_skip_scanlines(&cinfo, skip_end - skip_start + 1)) != +// skip_end - skip_start + 1) { +// fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, skip_end - skip_start + 1); +// exit(EXIT_FAILURE); +// } +// while (cinfo.output_scanline < cinfo.output_height) { +// num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// } else { +// /* Process data */ +// while (cinfo.output_scanline < skip_start) { +// num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// if ((tmp = jpeg_skip_scanlines(&cinfo, skip_end - skip_start + 1)) != +// skip_end - skip_start + 1) { +// fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, skip_end - skip_start + 1); +// exit(EXIT_FAILURE); +// } +// while (cinfo.output_scanline < cinfo.output_height) { +// num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// } + +// /* Decompress a subregion */ +// } else if (crop) { +// JDIMENSION tmp; + +// /* Check for valid crop dimensions. We cannot check these values until +// * after jpeg_start_decompress() is called. +// */ +// if (crop_x + crop_width > cinfo.output_width || +// crop_y + crop_height > cinfo.output_height) { +// fprintf(stderr, "%s: crop dimensions exceed image dimensions %u x %u\n", +// progname, cinfo.output_width, cinfo.output_height); +// exit(EXIT_FAILURE); +// } + +// if (cinfo.data_precision == 16) +// ERREXIT(&cinfo, JERR_NOTIMPL); +// else if (cinfo.data_precision == 12) +// jpeg12_crop_scanline(&cinfo, &crop_x, &crop_width); +// else +// // j16XXX hack until I clean up TurboJPEG. +// jpeg12_crop_scanline(&cinfo, &crop_x, &crop_width); +// if (dest_mgr->calc_buffer_dimensions) +// (*dest_mgr->calc_buffer_dimensions) (&cinfo, dest_mgr); +// else +// ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); + +// /* Write output file header. This is a hack to ensure that the destination +// * manager creates an output image of the proper size. +// */ +// tmp = cinfo.output_height; +// cinfo.output_height = crop_height; +// (*dest_mgr->start_output) (&cinfo, dest_mgr); +// cinfo.output_height = tmp; + +// if (cinfo.data_precision == 16) +// ERREXIT(&cinfo, JERR_NOTIMPL); +// else if (cinfo.data_precision == 12) { +// /* Process data */ +// if ((tmp = jpeg12_skip_scanlines(&cinfo, crop_y)) != crop_y) { +// fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, crop_y); +// exit(EXIT_FAILURE); +// } +// while (cinfo.output_scanline < crop_y + crop_height) { +// num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// if ((tmp = +// jpeg12_skip_scanlines(&cinfo, cinfo.output_height - crop_y - +// crop_height)) != +// cinfo.output_height - crop_y - crop_height) { +// fprintf(stderr, "%s: jpeg12_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, cinfo.output_height - crop_y - crop_height); +// exit(EXIT_FAILURE); +// } +// } else { +// /* Process data */ +// if ((tmp = jpeg_skip_scanlines(&cinfo, crop_y)) != crop_y) { +// fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, crop_y); +// exit(EXIT_FAILURE); +// } +// while (cinfo.output_scanline < crop_y + crop_height) { +// num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// if ((tmp = +// jpeg_skip_scanlines(&cinfo, +// cinfo.output_height - crop_y - crop_height)) != +// cinfo.output_height - crop_y - crop_height) { +// fprintf(stderr, "%s: jpeg_skip_scanlines() returned %u rather than %u\n", +// progname, tmp, cinfo.output_height - crop_y - crop_height); +// exit(EXIT_FAILURE); +// } +// } + +// /* Normal full-image decompress */ +// } else { +// /* Write output file header */ +// (*dest_mgr->start_output) (&cinfo, dest_mgr); + +// if (cinfo.data_precision == 16) { +// #ifdef D_LOSSLESS_SUPPORTED +// /* Process data */ +// while (cinfo.output_scanline < cinfo.output_height) { +// // j16XXX hack until I clean up TurboJPEG. +// num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// #else +// ERREXIT1(&cinfo, JERR_BAD_PRECISION, cinfo.data_precision); +// #endif +// } else if (cinfo.data_precision == 12) { +// /* Process data */ +// while (cinfo.output_scanline < cinfo.output_height) { +// num_scanlines = jpeg12_read_scanlines(&cinfo, dest_mgr->buffer12, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// } else { +// /* Process data */ +// while (cinfo.output_scanline < cinfo.output_height) { +// num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, +// dest_mgr->buffer_height); +// (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); +// } +// } +// } + +// /* Hack: count final pass as done in case finish_output does an extra pass. +// * The library won't have updated completed_passes. +// */ +// if (report || max_scans != 0) +// progress.pub.completed_passes = progress.pub.total_passes; + +// if (icc_filename != NULL) { +// FILE *icc_file; +// JOCTET *icc_profile; +// unsigned int icc_len; + +// if ((icc_file = fopen(icc_filename, WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); +// exit(EXIT_FAILURE); +// } +// if (jpeg_read_icc_profile(&cinfo, &icc_profile, &icc_len)) { +// if (fwrite(icc_profile, icc_len, 1, icc_file) < 1) { +// fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, +// icc_filename); +// free(icc_profile); +// fclose(icc_file); +// exit(EXIT_FAILURE); +// } +// free(icc_profile); +// fclose(icc_file); +// } else if (cinfo.err->msg_code != JWRN_BOGUS_ICC) +// fprintf(stderr, "%s: no ICC profile data in JPEG file\n", progname); +// } + +// /* Finish decompression and release memory. +// * I must do it in this order because output module has allocated memory +// * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. +// */ +// (*dest_mgr->finish_output) (&cinfo, dest_mgr); +// (void)jpeg_finish_decompress(&cinfo); +// jpeg_destroy_decompress(&cinfo); + +// /* Close files, if we opened them */ +// if (input_file != stdin) +// fclose(input_file); +// if (output_file != stdout) +// fclose(output_file); + +// if (report || max_scans != 0) +// end_progress_monitor((j_common_ptr)&cinfo); + +// if (memsrc) +// free(inbuffer); + +// /* All done. */ +// exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); +// return 0; /* suppress no-return-value warnings */ +// } diff --git a/Sources/TurboJPEG/example.c b/Sources/TurboJPEG/example.c index 4a826955..56396b9f 100644 --- a/Sources/TurboJPEG/example.c +++ b/Sources/TurboJPEG/example.c @@ -509,7 +509,8 @@ do_read_JPEG_file(struct jpeg_decompress_struct *cinfo, char *infilename, * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ - (void)jpeg_read_scanlines(cinfo, buffer, 1); + // j16XXX hack until I clean up TurboJPEG. + (void)jpeg12_read_scanlines(cinfo, buffer, 1); fwrite(buffer[0], 1, row_stride, outfile); } } diff --git a/Sources/TurboJPEG/include/turbo/jmorecfg.h b/Sources/TurboJPEG/include/turbo/jmorecfg.h index 89c7842c..e8b5b348 100644 --- a/Sources/TurboJPEG/include/turbo/jmorecfg.h +++ b/Sources/TurboJPEG/include/turbo/jmorecfg.h @@ -45,12 +45,16 @@ /* JSAMPLE should be the smallest type that will hold the values 0..255. */ -typedef unsigned char JSAMPLE; +// j16XXX hack until I clean up TurboJPEG. +// typedef unsigned char JSAMPLE; +typedef short JSAMPLE; #define GETJSAMPLE(value) ((int)(value)) -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 - +// j16XXX hack until I clean up TurboJPEG. +//#define MAXJSAMPLE 255 +//#define CENTERJSAMPLE 128 +#define MAXJSAMPLE 4095 +#define CENTERJSAMPLE 2048 /* J12SAMPLE should be the smallest type that will hold the values 0..4095. */ diff --git a/Sources/TurboJPEG/include/turbo/jpeglib.h b/Sources/TurboJPEG/include/turbo/jpeglib.h index dd0e61c3..b50301b8 100644 --- a/Sources/TurboJPEG/include/turbo/jpeglib.h +++ b/Sources/TurboJPEG/include/turbo/jpeglib.h @@ -1008,15 +1008,18 @@ EXTERN(JHUFF_TBL *) jpeg_alloc_huff_table(j_common_ptr cinfo); /* Main entry points for compression */ EXTERN(void) jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables); -EXTERN(JDIMENSION) jpeg_write_scanlines(j_compress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION num_lines); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg_write_scanlines(j_compress_ptr cinfo, +// JSAMPARRAY scanlines, +// JDIMENSION num_lines); EXTERN(JDIMENSION) jpeg12_write_scanlines(j_compress_ptr cinfo, J12SAMPARRAY scanlines, JDIMENSION num_lines); -EXTERN(JDIMENSION) jpeg16_write_scanlines(j_compress_ptr cinfo, - J16SAMPARRAY scanlines, - JDIMENSION num_lines); +#define jpeg_write_scanlines jpeg12_write_scanlines +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg16_write_scanlines(j_compress_ptr cinfo, +// J16SAMPARRAY scanlines, +// JDIMENSION num_lines); EXTERN(void) jpeg_finish_compress(j_compress_ptr cinfo); #if JPEG_LIB_VERSION >= 70 @@ -1025,12 +1028,13 @@ EXTERN(void) jpeg_calc_jpeg_dimensions(j_compress_ptr cinfo); #endif /* Replaces jpeg_write_scanlines when writing raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data, - JDIMENSION num_lines); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg_write_raw_data(j_compress_ptr cinfo, JSAMPIMAGE data, +// JDIMENSION num_lines); EXTERN(JDIMENSION) jpeg12_write_raw_data(j_compress_ptr cinfo, J12SAMPIMAGE data, JDIMENSION num_lines); - +#define jpeg_write_raw_data jpeg12_write_raw_data /* Write a special marker. See libjpeg.txt concerning safe usage. */ EXTERN(void) jpeg_write_marker(j_compress_ptr cinfo, int marker, const JOCTET *dataptr, unsigned int datalen); @@ -1062,32 +1066,40 @@ EXTERN(int) jpeg_read_header(j_decompress_ptr cinfo, boolean require_image); /* Main entry points for decompression */ EXTERN(boolean) jpeg_start_decompress(j_decompress_ptr cinfo); -EXTERN(JDIMENSION) jpeg_read_scanlines(j_decompress_ptr cinfo, - JSAMPARRAY scanlines, - JDIMENSION max_lines); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg_read_scanlines(j_decompress_ptr cinfo, +// JSAMPARRAY scanlines, +// JDIMENSION max_lines); EXTERN(JDIMENSION) jpeg12_read_scanlines(j_decompress_ptr cinfo, J12SAMPARRAY scanlines, JDIMENSION max_lines); -EXTERN(JDIMENSION) jpeg16_read_scanlines(j_decompress_ptr cinfo, - J16SAMPARRAY scanlines, - JDIMENSION max_lines); -EXTERN(JDIMENSION) jpeg_skip_scanlines(j_decompress_ptr cinfo, - JDIMENSION num_lines); +#define jpeg_read_scanlines jpeg12_read_scanlines +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg16_read_scanlines(j_decompress_ptr cinfo, +// J16SAMPARRAY scanlines, +// +// j16XXX hack until I clean up TurboJPEG. JDIMENSION max_lines); +// EXTERN(JDIMENSION) jpeg_skip_scanlines(j_decompress_ptr cinfo, +// JDIMENSION num_lines); EXTERN(JDIMENSION) jpeg12_skip_scanlines(j_decompress_ptr cinfo, JDIMENSION num_lines); -EXTERN(void) jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, - JDIMENSION *width); +#define jpeg_skip_scanlines jpeg12_skip_scanlines +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, +// JDIMENSION *width); EXTERN(void) jpeg12_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset, JDIMENSION *width); +#define jpeg_crop_scanline jpeg12_crop_scanline EXTERN(boolean) jpeg_finish_decompress(j_decompress_ptr cinfo); /* Replaces jpeg_read_scanlines when reading raw downsampled data. */ -EXTERN(JDIMENSION) jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data, - JDIMENSION max_lines); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(JDIMENSION) jpeg_read_raw_data(j_decompress_ptr cinfo, JSAMPIMAGE data, +// JDIMENSION max_lines); EXTERN(JDIMENSION) jpeg12_read_raw_data(j_decompress_ptr cinfo, J12SAMPIMAGE data, JDIMENSION max_lines); - +#define jpeg_read_raw_data jpeg12_read_raw_data /* Additional entry points for buffered-image mode. */ EXTERN(boolean) jpeg_has_multiple_scans(j_decompress_ptr cinfo); EXTERN(boolean) jpeg_start_output(j_decompress_ptr cinfo, int scan_number); diff --git a/Sources/TurboJPEG/include/turbo/jpegturbo.h b/Sources/TurboJPEG/include/turbo/jpegturbo.h index 8cac2ee6..a9f9628b 100644 --- a/Sources/TurboJPEG/include/turbo/jpegturbo.h +++ b/Sources/TurboJPEG/include/turbo/jpegturbo.h @@ -1125,9 +1125,10 @@ DLLEXPORT int tj3Get(tjhandle handle, int param); * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() * and #tj3GetErrorCode().) */ -DLLEXPORT int tj3Compress8(tjhandle handle, const unsigned char *srcBuf, - int width, int pitch, int height, int pixelFormat, - unsigned char **jpegBuf, size_t *jpegSize); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3Compress8(tjhandle handle, const unsigned char *srcBuf, +// int width, int pitch, int height, int pixelFormat, +// unsigned char **jpegBuf, size_t *jpegSize); /** * Compress a 12-bit-per-sample packed-pixel RGB, grayscale, or CMYK image into @@ -1145,9 +1146,10 @@ DLLEXPORT int tj3Compress12(tjhandle handle, const short *srcBuf, int width, * * \details \copydetails tj3Compress8() */ -DLLEXPORT int tj3Compress16(tjhandle handle, const unsigned short *srcBuf, - int width, int pitch, int height, int pixelFormat, - unsigned char **jpegBuf, size_t *jpegSize); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3Compress16(tjhandle handle, const unsigned short *srcBuf, +// int width, int pitch, int height, int pixelFormat, +// unsigned char **jpegBuf, size_t *jpegSize); /** @@ -1619,9 +1621,10 @@ DLLEXPORT int tj3SetCroppingRegion(tjhandle handle, tjregion croppingRegion); * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr() * and #tj3GetErrorCode().) */ -DLLEXPORT int tj3Decompress8(tjhandle handle, const unsigned char *jpegBuf, - size_t jpegSize, unsigned char *dstBuf, int pitch, - int pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3Decompress8(tjhandle handle, const unsigned char *jpegBuf, +// size_t jpegSize, unsigned char *dstBuf, int pitch, +// int pixelFormat); /** * Decompress a 12-bit-per-sample JPEG image into a 12-bit-per-sample @@ -1639,9 +1642,10 @@ DLLEXPORT int tj3Decompress12(tjhandle handle, const unsigned char *jpegBuf, * * \details \copydetails tj3Decompress8() */ -DLLEXPORT int tj3Decompress16(tjhandle handle, const unsigned char *jpegBuf, - size_t jpegSize, unsigned short *dstBuf, - int pitch, int pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3Decompress16(tjhandle handle, const unsigned char *jpegBuf, +// size_t jpegSize, unsigned short *dstBuf, +// int pitch, int pixelFormat); /** @@ -1964,9 +1968,10 @@ DLLEXPORT void *tj3Alloc(size_t bytes); * alignment, or NULL if an error occurred (see #tj3GetErrorStr().) This * buffer should be freed using #tj3Free(). */ -DLLEXPORT unsigned char *tj3LoadImage8(tjhandle handle, const char *filename, - int *width, int align, int *height, - int *pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT unsigned char *tj3LoadImage8(tjhandle handle, const char *filename, +// int *width, int align, int *height, +// int *pixelFormat); /** * Load a 12-bit-per-sample packed-pixel image from disk into memory. @@ -1982,9 +1987,10 @@ DLLEXPORT short *tj3LoadImage12(tjhandle handle, const char *filename, * * \details \copydetails tj3LoadImage8() */ -DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename, - int *width, int align, int *height, - int *pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename, +// int *width, int align, int *height, +// int *pixelFormat); /** @@ -2019,9 +2025,10 @@ DLLEXPORT unsigned short *tj3LoadImage16(tjhandle handle, const char *filename, * * @return 0 if successful, or -1 if an error occurred (see #tj3GetErrorStr().) */ -DLLEXPORT int tj3SaveImage8(tjhandle handle, const char *filename, - const unsigned char *buffer, int width, int pitch, - int height, int pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3SaveImage8(tjhandle handle, const char *filename, +// const unsigned char *buffer, int width, int pitch, +// int height, int pixelFormat); /** * Save a 12-bit-per-sample packed-pixel image from memory to disk. @@ -2037,9 +2044,10 @@ DLLEXPORT int tj3SaveImage12(tjhandle handle, const char *filename, * * \details \copydetails tj3SaveImage8() */ -DLLEXPORT int tj3SaveImage16(tjhandle handle, const char *filename, - const unsigned short *buffer, int width, - int pitch, int height, int pixelFormat); +// j16XXX hack until I clean up TurboJPEG. +// DLLEXPORT int tj3SaveImage16(tjhandle handle, const char *filename, +// const unsigned short *buffer, int width, +// int pitch, int height, int pixelFormat); /** diff --git a/Sources/TurboJPEG/jcapistd.c b/Sources/TurboJPEG/jcapistd.c index 2053028f..e1debed4 100644 --- a/Sources/TurboJPEG/jcapistd.c +++ b/Sources/TurboJPEG/jcapistd.c @@ -22,8 +22,8 @@ #include "jpeglib.h" #include "jsamplecomp.h" - -#if BITS_IN_JSAMPLE == 8 +// j16XXX hack until I clean up TurboJPEG. +// #if BITS_IN_JSAMPLE == 8 /* * Compression initialization. @@ -63,7 +63,7 @@ jpeg_start_compress(j_compress_ptr cinfo, boolean write_all_tables) cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING); } -#endif +// #endif /* BITS_IN_JSAMPLE == 8 */ /* diff --git a/Sources/TurboJPEG/jcinit.c b/Sources/TurboJPEG/jcinit.c index fe8a13a8..bb4425ac 100644 --- a/Sources/TurboJPEG/jcinit.c +++ b/Sources/TurboJPEG/jcinit.c @@ -42,9 +42,10 @@ jinit_compress_master(j_compress_ptr cinfo) if (!cinfo->raw_data_in) { if (cinfo->data_precision == 16) { #ifdef C_LOSSLESS_SUPPORTED - j16init_color_converter(cinfo); - j16init_downsampler(cinfo); - j16init_c_prep_controller(cinfo, + // j16XXX hack until I clean up TurboJPEG. + j12init_color_converter(cinfo); + j12init_downsampler(cinfo); + j12init_c_prep_controller(cinfo, FALSE /* never need full buffer here */); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); @@ -55,9 +56,10 @@ jinit_compress_master(j_compress_ptr cinfo) j12init_c_prep_controller(cinfo, FALSE /* never need full buffer here */); } else { - jinit_color_converter(cinfo); - jinit_downsampler(cinfo); - jinit_c_prep_controller(cinfo, FALSE /* never need full buffer here */); + // j16XXX hack until I clean up TurboJPEG. + j12init_color_converter(cinfo); + j12init_downsampler(cinfo); + j12init_c_prep_controller(cinfo, FALSE /* never need full buffer here */); } } @@ -65,11 +67,13 @@ jinit_compress_master(j_compress_ptr cinfo) #ifdef C_LOSSLESS_SUPPORTED /* Prediction, sample differencing, and point transform */ if (cinfo->data_precision == 16) - j16init_lossless_compressor(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_lossless_compressor(cinfo); else if (cinfo->data_precision == 12) j12init_lossless_compressor(cinfo); else - jinit_lossless_compressor(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_lossless_compressor(cinfo); /* Entropy encoding: either Huffman or arithmetic coding. */ if (cinfo->arith_code) { ERREXIT(cinfo, JERR_ARITH_NOTIMPL); @@ -79,13 +83,15 @@ jinit_compress_master(j_compress_ptr cinfo) /* Need a full-image difference buffer in any multi-pass mode. */ if (cinfo->data_precision == 16) - j16init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 || + // j16XXX hack until I clean up TurboJPEG. + j12init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 || cinfo->optimize_coding)); else if (cinfo->data_precision == 12) j12init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 || cinfo->optimize_coding)); else - jinit_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 || + // j16XXX hack until I clean up TurboJPEG. + j12init_c_diff_controller(cinfo, (boolean)(cinfo->num_scans > 1 || cinfo->optimize_coding)); #else ERREXIT(cinfo, JERR_NOT_COMPILED); @@ -97,7 +103,8 @@ jinit_compress_master(j_compress_ptr cinfo) if (cinfo->data_precision == 12) j12init_forward_dct(cinfo); else - jinit_forward_dct(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_forward_dct(cinfo); /* Entropy encoding: either Huffman or arithmetic coding. */ if (cinfo->arith_code) { #ifdef C_ARITH_CODING_SUPPORTED @@ -121,20 +128,23 @@ jinit_compress_master(j_compress_ptr cinfo) j12init_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 || cinfo->optimize_coding)); else - jinit_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 || - cinfo->optimize_coding)); + // j16XXX hack until I clean up TurboJPEG. + j12init_c_coef_controller(cinfo, (boolean)(cinfo->num_scans > 1 || + cinfo->optimize_coding)); } if (cinfo->data_precision == 16) #ifdef C_LOSSLESS_SUPPORTED - j16init_c_main_controller(cinfo, FALSE /* never need full buffer here */); + // j16XXX hack until I clean up TurboJPEG. + j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); #endif else if (cinfo->data_precision == 12) j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */); else - jinit_c_main_controller(cinfo, FALSE /* never need full buffer here */); + // j16XXX hack until I clean up TurboJPEG. + j12init_c_main_controller(cinfo, FALSE /* never need full buffer here */); jinit_marker_writer(cinfo); diff --git a/Sources/TurboJPEG/jconfigint.h b/Sources/TurboJPEG/jconfigint.h index 3f4510bc..a270de1f 100644 --- a/Sources/TurboJPEG/jconfigint.h +++ b/Sources/TurboJPEG/jconfigint.h @@ -52,7 +52,7 @@ */ #ifndef BITS_IN_JSAMPLE -#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ +#define BITS_IN_JSAMPLE 12 /* use 8 or 12 */ #endif #undef C_ARITH_CODING_SUPPORTED diff --git a/Sources/TurboJPEG/jcstest.c b/Sources/TurboJPEG/jcstest.c index 8b1fe380..20195ba4 100644 --- a/Sources/TurboJPEG/jcstest.c +++ b/Sources/TurboJPEG/jcstest.c @@ -60,67 +60,67 @@ static void my_output_message(j_common_ptr cinfo) (*cinfo->err->format_message) (cinfo, lasterror); } -int main(void) -{ - int jcs_valid = -1, jcs_alpha_valid = -1; - struct jpeg_compress_struct cinfo; - error_mgr jerr; - - printf("libjpeg-turbo colorspace extensions:\n"); -#if JCS_EXTENSIONS - printf(" Present at compile time\n"); -#else - printf(" Not present at compile time\n"); -#endif - - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = my_error_exit; - jerr.pub.output_message = my_output_message; - - if (setjmp(jerr.jb)) { - /* this will execute if libjpeg has an error */ - jcs_valid = 0; - goto done; - } - - jpeg_create_compress(&cinfo); - cinfo.input_components = 3; - jpeg_set_defaults(&cinfo); - cinfo.in_color_space = JCS_EXT_RGB; - jpeg_default_colorspace(&cinfo); - jcs_valid = 1; - -done: - if (jcs_valid) - printf(" Working properly\n"); - else - printf(" Not working properly. Error returned was:\n %s\n", - lasterror); - - printf("libjpeg-turbo alpha colorspace extensions:\n"); -#if JCS_ALPHA_EXTENSIONS - printf(" Present at compile time\n"); -#else - printf(" Not present at compile time\n"); -#endif - - if (setjmp(jerr.jb)) { - /* this will execute if libjpeg has an error */ - jcs_alpha_valid = 0; - goto done2; - } - - cinfo.in_color_space = JCS_EXT_RGBA; - jpeg_default_colorspace(&cinfo); - jcs_alpha_valid = 1; - -done2: - if (jcs_alpha_valid) - printf(" Working properly\n"); - else - printf(" Not working properly. Error returned was:\n %s\n", - lasterror); - - jpeg_destroy_compress(&cinfo); - return 0; -} +// int main(void) +// { +// int jcs_valid = -1, jcs_alpha_valid = -1; +// struct jpeg_compress_struct cinfo; +// error_mgr jerr; + +// printf("libjpeg-turbo colorspace extensions:\n"); +// #if JCS_EXTENSIONS +// printf(" Present at compile time\n"); +// #else +// printf(" Not present at compile time\n"); +// #endif + +// cinfo.err = jpeg_std_error(&jerr.pub); +// jerr.pub.error_exit = my_error_exit; +// jerr.pub.output_message = my_output_message; + +// if (setjmp(jerr.jb)) { +// /* this will execute if libjpeg has an error */ +// jcs_valid = 0; +// goto done; +// } + +// jpeg_create_compress(&cinfo); +// cinfo.input_components = 3; +// jpeg_set_defaults(&cinfo); +// cinfo.in_color_space = JCS_EXT_RGB; +// jpeg_default_colorspace(&cinfo); +// jcs_valid = 1; + +// done: +// if (jcs_valid) +// printf(" Working properly\n"); +// else +// printf(" Not working properly. Error returned was:\n %s\n", +// lasterror); + +// printf("libjpeg-turbo alpha colorspace extensions:\n"); +// #if JCS_ALPHA_EXTENSIONS +// printf(" Present at compile time\n"); +// #else +// printf(" Not present at compile time\n"); +// #endif + +// if (setjmp(jerr.jb)) { +// /* this will execute if libjpeg has an error */ +// jcs_alpha_valid = 0; +// goto done2; +// } + +// cinfo.in_color_space = JCS_EXT_RGBA; +// jpeg_default_colorspace(&cinfo); +// jcs_alpha_valid = 1; + +// done2: +// if (jcs_alpha_valid) +// printf(" Working properly\n"); +// else +// printf(" Not working properly. Error returned was:\n %s\n", +// lasterror); + +// jpeg_destroy_compress(&cinfo); +// return 0; +// } diff --git a/Sources/TurboJPEG/jdapistd.c b/Sources/TurboJPEG/jdapistd.c index 1f449272..7f77fdc9 100644 --- a/Sources/TurboJPEG/jdapistd.c +++ b/Sources/TurboJPEG/jdapistd.c @@ -31,7 +31,8 @@ #include "jdsample.h" #include "jmemsys.h" -#if BITS_IN_JSAMPLE == 8 +// j16XXX hack until I clean up TurboJPEG. +// #if BITS_IN_JSAMPLE == 8 /* Forward declarations */ LOCAL(boolean) output_pass_setup(j_decompress_ptr cinfo); @@ -160,7 +161,7 @@ output_pass_setup(j_decompress_ptr cinfo) return TRUE; } -#endif /* BITS_IN_JSAMPLE == 8 */ +// #endif /* BITS_IN_JSAMPLE == 8 */ #if BITS_IN_JSAMPLE != 16 diff --git a/Sources/TurboJPEG/jdmaster.c b/Sources/TurboJPEG/jdmaster.c index 80a4842a..0ed589c0 100644 --- a/Sources/TurboJPEG/jdmaster.c +++ b/Sources/TurboJPEG/jdmaster.c @@ -25,7 +25,6 @@ #include "jpegapicomp.h" #include "jdmaster.h" - /* * Determine whether merged upsample/color conversion should be used. * CRUCIAL: this must match the actual capabilities of jdmerge.c! @@ -575,7 +574,8 @@ master_selection(j_decompress_ptr cinfo) else if (cinfo->data_precision == 12) j12init_1pass_quantizer(cinfo); else - jinit_1pass_quantizer(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_1pass_quantizer(cinfo); master->quantizer_1pass = cinfo->cquantize; #else ERREXIT(cinfo, JERR_NOT_COMPILED); @@ -590,7 +590,8 @@ master_selection(j_decompress_ptr cinfo) else if (cinfo->data_precision == 12) j12init_2pass_quantizer(cinfo); else - jinit_2pass_quantizer(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_2pass_quantizer(cinfo); master->quantizer_2pass = cinfo->cquantize; #else ERREXIT(cinfo, JERR_NOT_COMPILED); @@ -610,15 +611,17 @@ master_selection(j_decompress_ptr cinfo) else if (cinfo->data_precision == 12) j12init_merged_upsampler(cinfo); /* does color conversion too */ else - jinit_merged_upsampler(cinfo); /* does color conversion too */ + // j16XXX hack until I clean up TurboJPEG. + j12init_merged_upsampler(cinfo); /* does color conversion too */ #else ERREXIT(cinfo, JERR_NOT_COMPILED); #endif } else { if (cinfo->data_precision == 16) { #ifdef D_LOSSLESS_SUPPORTED - j16init_color_deconverter(cinfo); - j16init_upsampler(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_color_deconverter(cinfo); + j12init_upsampler(cinfo); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); #endif @@ -626,20 +629,23 @@ master_selection(j_decompress_ptr cinfo) j12init_color_deconverter(cinfo); j12init_upsampler(cinfo); } else { - jinit_color_deconverter(cinfo); - jinit_upsampler(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_color_deconverter(cinfo); + j12init_upsampler(cinfo); } } if (cinfo->data_precision == 16) #ifdef D_LOSSLESS_SUPPORTED - j16init_d_post_controller(cinfo, cinfo->enable_2pass_quant); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); #endif else if (cinfo->data_precision == 12) j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant); else - jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_post_controller(cinfo, cinfo->enable_2pass_quant); } if (cinfo->master->lossless) { @@ -648,11 +654,13 @@ master_selection(j_decompress_ptr cinfo) * scaling */ if (cinfo->data_precision == 16) - j16init_lossless_decompressor(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_lossless_decompressor(cinfo); else if (cinfo->data_precision == 12) j12init_lossless_decompressor(cinfo); else - jinit_lossless_decompressor(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_lossless_decompressor(cinfo); /* Entropy decoding: either Huffman or arithmetic coding. */ if (cinfo->arith_code) { ERREXIT(cinfo, JERR_ARITH_NOTIMPL); @@ -664,11 +672,13 @@ master_selection(j_decompress_ptr cinfo) use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; if (cinfo->data_precision == 16) - j16init_d_diff_controller(cinfo, use_c_buffer); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_diff_controller(cinfo, use_c_buffer); else if (cinfo->data_precision == 12) j12init_d_diff_controller(cinfo, use_c_buffer); else - jinit_d_diff_controller(cinfo, use_c_buffer); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_diff_controller(cinfo, use_c_buffer); #else ERREXIT(cinfo, JERR_NOT_COMPILED); #endif @@ -679,7 +689,8 @@ master_selection(j_decompress_ptr cinfo) if (cinfo->data_precision == 12) j12init_inverse_dct(cinfo); else - jinit_inverse_dct(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_inverse_dct(cinfo); /* Entropy decoding: either Huffman or arithmetic coding. */ if (cinfo->arith_code) { #ifdef D_ARITH_CODING_SUPPORTED @@ -704,13 +715,15 @@ master_selection(j_decompress_ptr cinfo) if (cinfo->data_precision == 12) j12init_d_coef_controller(cinfo, use_c_buffer); else - jinit_d_coef_controller(cinfo, use_c_buffer); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_coef_controller(cinfo, use_c_buffer); } if (!cinfo->raw_data_out) { if (cinfo->data_precision == 16) #ifdef D_LOSSLESS_SUPPORTED - j16init_d_main_controller(cinfo, + // j16XXX hack until I clean up TurboJPEG. + j12init_d_main_controller(cinfo, FALSE /* never need full buffer here */); #else ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); @@ -719,7 +732,8 @@ master_selection(j_decompress_ptr cinfo) j12init_d_main_controller(cinfo, FALSE /* never need full buffer here */); else - jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_main_controller(cinfo, FALSE /* never need full buffer here */); } /* We can now tell the memory manager to allocate virtual arrays. */ diff --git a/Sources/TurboJPEG/jdtrans.c b/Sources/TurboJPEG/jdtrans.c index 719813f6..94c56c67 100644 --- a/Sources/TurboJPEG/jdtrans.c +++ b/Sources/TurboJPEG/jdtrans.c @@ -133,7 +133,8 @@ transdecode_master_selection(j_decompress_ptr cinfo) if (cinfo->data_precision == 12) j12init_d_coef_controller(cinfo, TRUE); else - jinit_d_coef_controller(cinfo, TRUE); + // j16XXX hack until I clean up TurboJPEG. + j12init_d_coef_controller(cinfo, TRUE); /* We can now tell the memory manager to allocate virtual arrays. */ (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo); diff --git a/Sources/TurboJPEG/jpegint.h b/Sources/TurboJPEG/jpegint.h index 65414201..6bb019d8 100644 --- a/Sources/TurboJPEG/jpegint.h +++ b/Sources/TurboJPEG/jpegint.h @@ -470,59 +470,72 @@ struct jpeg_color_quantizer { EXTERN(void) jinit_compress_master(j_compress_ptr cinfo); EXTERN(void) jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only); -EXTERN(void) jinit_c_main_controller(j_compress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_c_main_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_c_main_controller(j_compress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) jinit_c_prep_controller(j_compress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_c_prep_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_c_prep_controller(j_compress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) jinit_c_coef_controller(j_compress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_c_coef_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_c_coef_controller(j_compress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) jinit_color_converter(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_color_converter(j_compress_ptr cinfo); EXTERN(void) j12init_color_converter(j_compress_ptr cinfo); -EXTERN(void) jinit_downsampler(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_downsampler(j_compress_ptr cinfo); EXTERN(void) j12init_downsampler(j_compress_ptr cinfo); -EXTERN(void) jinit_forward_dct(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_forward_dct(j_compress_ptr cinfo); EXTERN(void) j12init_forward_dct(j_compress_ptr cinfo); EXTERN(void) jinit_huff_encoder(j_compress_ptr cinfo); EXTERN(void) jinit_phuff_encoder(j_compress_ptr cinfo); EXTERN(void) jinit_arith_encoder(j_compress_ptr cinfo); EXTERN(void) jinit_marker_writer(j_compress_ptr cinfo); #ifdef C_LOSSLESS_SUPPORTED -EXTERN(void) j16init_c_main_controller(j_compress_ptr cinfo, - boolean need_full_buffer); -EXTERN(void) j16init_c_prep_controller(j_compress_ptr cinfo, - boolean need_full_buffer); -EXTERN(void) j16init_color_converter(j_compress_ptr cinfo); -EXTERN(void) j16init_downsampler(j_compress_ptr cinfo); -EXTERN(void) jinit_c_diff_controller(j_compress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_c_main_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); +// EXTERN(void) j16init_c_prep_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); +// EXTERN(void) j16init_color_converter(j_compress_ptr cinfo); +// EXTERN(void) j16init_downsampler(j_compress_ptr cinfo); +// EXTERN(void) jinit_c_diff_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_c_diff_controller(j_compress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) j16init_c_diff_controller(j_compress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_c_diff_controller(j_compress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) jinit_lhuff_encoder(j_compress_ptr cinfo); -EXTERN(void) jinit_lossless_compressor(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_lossless_compressor(j_compress_ptr cinfo); EXTERN(void) j12init_lossless_compressor(j_compress_ptr cinfo); -EXTERN(void) j16init_lossless_compressor(j_compress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_lossless_compressor(j_compress_ptr cinfo); #endif /* Decompression module initialization routines */ EXTERN(void) jinit_master_decompress(j_decompress_ptr cinfo); -EXTERN(void) jinit_d_main_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_d_main_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_d_main_controller(j_decompress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) jinit_d_coef_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_d_coef_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_d_coef_controller(j_decompress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) jinit_d_post_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_d_post_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_d_post_controller(j_decompress_ptr cinfo, boolean need_full_buffer); EXTERN(void) jinit_input_controller(j_decompress_ptr cinfo); @@ -530,35 +543,47 @@ EXTERN(void) jinit_marker_reader(j_decompress_ptr cinfo); EXTERN(void) jinit_huff_decoder(j_decompress_ptr cinfo); EXTERN(void) jinit_phuff_decoder(j_decompress_ptr cinfo); EXTERN(void) jinit_arith_decoder(j_decompress_ptr cinfo); -EXTERN(void) jinit_inverse_dct(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_inverse_dct(j_decompress_ptr cinfo); EXTERN(void) j12init_inverse_dct(j_decompress_ptr cinfo); -EXTERN(void) jinit_upsampler(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_upsampler(j_decompress_ptr cinfo); EXTERN(void) j12init_upsampler(j_decompress_ptr cinfo); -EXTERN(void) jinit_color_deconverter(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_color_deconverter(j_decompress_ptr cinfo); EXTERN(void) j12init_color_deconverter(j_decompress_ptr cinfo); -EXTERN(void) jinit_1pass_quantizer(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_1pass_quantizer(j_decompress_ptr cinfo); EXTERN(void) j12init_1pass_quantizer(j_decompress_ptr cinfo); -EXTERN(void) jinit_2pass_quantizer(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_2pass_quantizer(j_decompress_ptr cinfo); EXTERN(void) j12init_2pass_quantizer(j_decompress_ptr cinfo); -EXTERN(void) jinit_merged_upsampler(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_merged_upsampler(j_decompress_ptr cinfo); EXTERN(void) j12init_merged_upsampler(j_decompress_ptr cinfo); #ifdef D_LOSSLESS_SUPPORTED -EXTERN(void) j16init_d_main_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); -EXTERN(void) j16init_d_post_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); -EXTERN(void) j16init_upsampler(j_decompress_ptr cinfo); -EXTERN(void) j16init_color_deconverter(j_decompress_ptr cinfo); -EXTERN(void) jinit_d_diff_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_d_main_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); +// EXTERN(void) j16init_d_post_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_upsampler(j_decompress_ptr cinfo); +// EXTERN(void) j16init_color_deconverter(j_decompress_ptr cinfo); +// EXTERN(void) jinit_d_diff_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) j12init_d_diff_controller(j_decompress_ptr cinfo, boolean need_full_buffer); -EXTERN(void) j16init_d_diff_controller(j_decompress_ptr cinfo, - boolean need_full_buffer); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_d_diff_controller(j_decompress_ptr cinfo, +// boolean need_full_buffer); EXTERN(void) jinit_lhuff_decoder(j_decompress_ptr cinfo); -EXTERN(void) jinit_lossless_decompressor(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jinit_lossless_decompressor(j_decompress_ptr cinfo); + EXTERN(void) j12init_lossless_decompressor(j_decompress_ptr cinfo); -EXTERN(void) j16init_lossless_decompressor(j_decompress_ptr cinfo); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16init_lossless_decompressor(j_decompress_ptr cinfo); #endif /* Memory manager initialization */ @@ -567,16 +592,18 @@ EXTERN(void) jinit_memory_mgr(j_common_ptr cinfo); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up(long a, long b); EXTERN(long) jround_up(long a, long b); -EXTERN(void) jcopy_sample_rows(JSAMPARRAY input_array, int source_row, - JSAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) jcopy_sample_rows(JSAMPARRAY input_array, int source_row, +// JSAMPARRAY output_array, int dest_row, +// int num_rows, JDIMENSION num_cols); EXTERN(void) j12copy_sample_rows(J12SAMPARRAY input_array, int source_row, J12SAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols); #if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) -EXTERN(void) j16copy_sample_rows(J16SAMPARRAY input_array, int source_row, - J16SAMPARRAY output_array, int dest_row, - int num_rows, JDIMENSION num_cols); +// j16XXX hack until I clean up TurboJPEG. +// EXTERN(void) j16copy_sample_rows(J16SAMPARRAY input_array, int source_row, +// J16SAMPARRAY output_array, int dest_row, +// int num_rows, JDIMENSION num_cols); #endif EXTERN(void) jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks); diff --git a/Sources/TurboJPEG/jpegtran.c b/Sources/TurboJPEG/jpegtran.c index d1552ec7..5392ed02 100644 --- a/Sources/TurboJPEG/jpegtran.c +++ b/Sources/TurboJPEG/jpegtran.c @@ -450,279 +450,279 @@ my_emit_message(j_common_ptr cinfo, int msg_level) * The main program. */ -int -main(int argc, char **argv) -{ - struct jpeg_decompress_struct srcinfo; -#if TRANSFORMS_SUPPORTED - struct jpeg_decompress_struct dropinfo; - struct jpeg_error_mgr jdroperr; - FILE *drop_file; -#endif - struct jpeg_compress_struct dstinfo; - struct jpeg_error_mgr jsrcerr, jdsterr; - struct cdjpeg_progress_mgr src_progress, dst_progress; - jvirt_barray_ptr *src_coef_arrays; - jvirt_barray_ptr *dst_coef_arrays; - int file_index; - /* We assume all-in-memory processing and can therefore use only a - * single file pointer for sequential input and output operation. - */ - FILE *fp; - FILE *icc_file; - JOCTET *icc_profile = NULL; - long icc_len = 0; - - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "jpegtran"; /* in case C library doesn't provide it */ - - /* Initialize the JPEG decompression object with default error handling. */ - srcinfo.err = jpeg_std_error(&jsrcerr); - jpeg_create_decompress(&srcinfo); - /* Initialize the JPEG compression object with default error handling. */ - dstinfo.err = jpeg_std_error(&jdsterr); - jpeg_create_compress(&dstinfo); - - /* Scan command line to find file names. - * It is convenient to use just one switch-parsing routine, but the switch - * values read here are mostly ignored; we will rescan the switches after - * opening the input file. Also note that most of the switches affect the - * destination JPEG object, so we parse into that and then copy over what - * needs to affect the source too. - */ - - file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); - jsrcerr.trace_level = jdsterr.trace_level; - srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; - - if (strict) - jsrcerr.emit_message = my_emit_message; - -#ifdef TWO_FILE_COMMANDLINE - /* Must have either -outfile switch or explicit output file name */ - if (outfilename == NULL) { - if (file_index != argc - 2) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - outfilename = argv[file_index + 1]; - } else { - if (file_index != argc - 1) { - fprintf(stderr, "%s: must name one input and one output file\n", - progname); - usage(); - } - } -#else - /* Unix style: expect zero or one file name */ - if (file_index < argc - 1) { - fprintf(stderr, "%s: only one input file\n", progname); - usage(); - } -#endif /* TWO_FILE_COMMANDLINE */ - - /* Open the input file. */ - if (file_index < argc) { - if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s for reading\n", progname, - argv[file_index]); - exit(EXIT_FAILURE); - } - } else { - /* default input file is stdin */ - fp = read_stdin(); - } - - if (icc_filename != NULL) { - if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); - exit(EXIT_FAILURE); - } - if (fseek(icc_file, 0, SEEK_END) < 0 || - (icc_len = ftell(icc_file)) < 1 || - fseek(icc_file, 0, SEEK_SET) < 0) { - fprintf(stderr, "%s: can't determine size of %s\n", progname, - icc_filename); - exit(EXIT_FAILURE); - } - if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) { - fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname); - fclose(icc_file); - exit(EXIT_FAILURE); - } - if (fread(icc_profile, icc_len, 1, icc_file) < 1) { - fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, - icc_filename); - free(icc_profile); - fclose(icc_file); - exit(EXIT_FAILURE); - } - fclose(icc_file); - if (copyoption == JCOPYOPT_ALL) - copyoption = JCOPYOPT_ALL_EXCEPT_ICC; - if (copyoption == JCOPYOPT_ICC) - copyoption = JCOPYOPT_NONE; - } - - if (report) { - start_progress_monitor((j_common_ptr)&dstinfo, &dst_progress); - dst_progress.report = report; - } - if (report || max_scans != 0) { - start_progress_monitor((j_common_ptr)&srcinfo, &src_progress); - src_progress.report = report; - src_progress.max_scans = max_scans; - } -#if TRANSFORMS_SUPPORTED - /* Open the drop file. */ - if (dropfilename != NULL) { - if ((drop_file = fopen(dropfilename, READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s for reading\n", progname, - dropfilename); - exit(EXIT_FAILURE); - } - dropinfo.err = jpeg_std_error(&jdroperr); - jpeg_create_decompress(&dropinfo); - jpeg_stdio_src(&dropinfo, drop_file); - } else { - drop_file = NULL; - } -#endif - - /* Specify data source for decompression */ - jpeg_stdio_src(&srcinfo, fp); - - /* Enable saving of extra markers that we want to copy */ - jcopy_markers_setup(&srcinfo, copyoption); - - /* Read file header */ - (void)jpeg_read_header(&srcinfo, TRUE); - -#if TRANSFORMS_SUPPORTED - if (dropfilename != NULL) { - (void)jpeg_read_header(&dropinfo, TRUE); - transformoption.crop_width = dropinfo.image_width; - transformoption.crop_width_set = JCROP_POS; - transformoption.crop_height = dropinfo.image_height; - transformoption.crop_height_set = JCROP_POS; - transformoption.drop_ptr = &dropinfo; - } -#endif - - /* Any space needed by a transform option must be requested before - * jpeg_read_coefficients so that memory allocation will be done right. - */ -#if TRANSFORMS_SUPPORTED - /* Fail right away if -perfect is given and transformation is not perfect. - */ - if (!jtransform_request_workspace(&srcinfo, &transformoption)) { - fprintf(stderr, "%s: transformation is not perfect\n", progname); - exit(EXIT_FAILURE); - } -#endif - - /* Read source file as DCT coefficients */ - src_coef_arrays = jpeg_read_coefficients(&srcinfo); - -#if TRANSFORMS_SUPPORTED - if (dropfilename != NULL) { - transformoption.drop_coef_arrays = jpeg_read_coefficients(&dropinfo); - } -#endif - - /* Initialize destination compression parameters from source values */ - jpeg_copy_critical_parameters(&srcinfo, &dstinfo); - - /* Adjust destination parameters if required by transform options; - * also find out which set of coefficient arrays will hold the output. - */ -#if TRANSFORMS_SUPPORTED - dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, - src_coef_arrays, - &transformoption); -#else - dst_coef_arrays = src_coef_arrays; -#endif - - /* Close input file, if we opened it. - * Note: we assume that jpeg_read_coefficients consumed all input - * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will - * only consume more while (!cinfo->inputctl->eoi_reached). - * We cannot call jpeg_finish_decompress here since we still need the - * virtual arrays allocated from the source object for processing. - */ - if (fp != stdin) - fclose(fp); - - /* Open the output file. */ - if (outfilename != NULL) { - if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s for writing\n", progname, - outfilename); - exit(EXIT_FAILURE); - } - } else { - /* default output file is stdout */ - fp = write_stdout(); - } - - /* Adjust default compression parameters by re-parsing the options */ - file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); - - /* Specify data destination for compression */ - jpeg_stdio_dest(&dstinfo, fp); - - /* Start compressor (note no image data is actually written here) */ - jpeg_write_coefficients(&dstinfo, dst_coef_arrays); - - /* Copy to the output file any extra markers that we want to preserve */ - jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); - - if (icc_profile != NULL) - jpeg_write_icc_profile(&dstinfo, icc_profile, (unsigned int)icc_len); - - /* Execute image transformation, if any */ -#if TRANSFORMS_SUPPORTED - jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, - &transformoption); -#endif - - /* Finish compression and release memory */ - jpeg_finish_compress(&dstinfo); - jpeg_destroy_compress(&dstinfo); -#if TRANSFORMS_SUPPORTED - if (dropfilename != NULL) { - (void)jpeg_finish_decompress(&dropinfo); - jpeg_destroy_decompress(&dropinfo); - } -#endif - (void)jpeg_finish_decompress(&srcinfo); - jpeg_destroy_decompress(&srcinfo); - - /* Close output file, if we opened it */ - if (fp != stdout) - fclose(fp); -#if TRANSFORMS_SUPPORTED - if (drop_file != NULL) - fclose(drop_file); -#endif - - if (report) - end_progress_monitor((j_common_ptr)&dstinfo); - if (report || max_scans != 0) - end_progress_monitor((j_common_ptr)&srcinfo); - - free(icc_profile); - - /* All done. */ -#if TRANSFORMS_SUPPORTED - if (dropfilename != NULL) - exit(jsrcerr.num_warnings + jdroperr.num_warnings + - jdsterr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); -#endif - exit(jsrcerr.num_warnings + jdsterr.num_warnings ? - EXIT_WARNING : EXIT_SUCCESS); - return 0; /* suppress no-return-value warnings */ -} +// int +// main(int argc, char **argv) +// { +// struct jpeg_decompress_struct srcinfo; +// #if TRANSFORMS_SUPPORTED +// struct jpeg_decompress_struct dropinfo; +// struct jpeg_error_mgr jdroperr; +// FILE *drop_file; +// #endif +// struct jpeg_compress_struct dstinfo; +// struct jpeg_error_mgr jsrcerr, jdsterr; +// struct cdjpeg_progress_mgr src_progress, dst_progress; +// jvirt_barray_ptr *src_coef_arrays; +// jvirt_barray_ptr *dst_coef_arrays; +// int file_index; +// /* We assume all-in-memory processing and can therefore use only a +// * single file pointer for sequential input and output operation. +// */ +// FILE *fp; +// FILE *icc_file; +// JOCTET *icc_profile = NULL; +// long icc_len = 0; + +// progname = argv[0]; +// if (progname == NULL || progname[0] == 0) +// progname = "jpegtran"; /* in case C library doesn't provide it */ + +// /* Initialize the JPEG decompression object with default error handling. */ +// srcinfo.err = jpeg_std_error(&jsrcerr); +// jpeg_create_decompress(&srcinfo); +// /* Initialize the JPEG compression object with default error handling. */ +// dstinfo.err = jpeg_std_error(&jdsterr); +// jpeg_create_compress(&dstinfo); + +// /* Scan command line to find file names. +// * It is convenient to use just one switch-parsing routine, but the switch +// * values read here are mostly ignored; we will rescan the switches after +// * opening the input file. Also note that most of the switches affect the +// * destination JPEG object, so we parse into that and then copy over what +// * needs to affect the source too. +// */ + +// file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); +// jsrcerr.trace_level = jdsterr.trace_level; +// srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; + +// if (strict) +// jsrcerr.emit_message = my_emit_message; + +// #ifdef TWO_FILE_COMMANDLINE +// /* Must have either -outfile switch or explicit output file name */ +// if (outfilename == NULL) { +// if (file_index != argc - 2) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// outfilename = argv[file_index + 1]; +// } else { +// if (file_index != argc - 1) { +// fprintf(stderr, "%s: must name one input and one output file\n", +// progname); +// usage(); +// } +// } +// #else +// /* Unix style: expect zero or one file name */ +// if (file_index < argc - 1) { +// fprintf(stderr, "%s: only one input file\n", progname); +// usage(); +// } +// #endif /* TWO_FILE_COMMANDLINE */ + +// /* Open the input file. */ +// if (file_index < argc) { +// if ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s for reading\n", progname, +// argv[file_index]); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default input file is stdin */ +// fp = read_stdin(); +// } + +// if (icc_filename != NULL) { +// if ((icc_file = fopen(icc_filename, READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, icc_filename); +// exit(EXIT_FAILURE); +// } +// if (fseek(icc_file, 0, SEEK_END) < 0 || +// (icc_len = ftell(icc_file)) < 1 || +// fseek(icc_file, 0, SEEK_SET) < 0) { +// fprintf(stderr, "%s: can't determine size of %s\n", progname, +// icc_filename); +// exit(EXIT_FAILURE); +// } +// if ((icc_profile = (JOCTET *)malloc(icc_len)) == NULL) { +// fprintf(stderr, "%s: can't allocate memory for ICC profile\n", progname); +// fclose(icc_file); +// exit(EXIT_FAILURE); +// } +// if (fread(icc_profile, icc_len, 1, icc_file) < 1) { +// fprintf(stderr, "%s: can't read ICC profile from %s\n", progname, +// icc_filename); +// free(icc_profile); +// fclose(icc_file); +// exit(EXIT_FAILURE); +// } +// fclose(icc_file); +// if (copyoption == JCOPYOPT_ALL) +// copyoption = JCOPYOPT_ALL_EXCEPT_ICC; +// if (copyoption == JCOPYOPT_ICC) +// copyoption = JCOPYOPT_NONE; +// } + +// if (report) { +// start_progress_monitor((j_common_ptr)&dstinfo, &dst_progress); +// dst_progress.report = report; +// } +// if (report || max_scans != 0) { +// start_progress_monitor((j_common_ptr)&srcinfo, &src_progress); +// src_progress.report = report; +// src_progress.max_scans = max_scans; +// } +// #if TRANSFORMS_SUPPORTED +// /* Open the drop file. */ +// if (dropfilename != NULL) { +// if ((drop_file = fopen(dropfilename, READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s for reading\n", progname, +// dropfilename); +// exit(EXIT_FAILURE); +// } +// dropinfo.err = jpeg_std_error(&jdroperr); +// jpeg_create_decompress(&dropinfo); +// jpeg_stdio_src(&dropinfo, drop_file); +// } else { +// drop_file = NULL; +// } +// #endif + +// /* Specify data source for decompression */ +// jpeg_stdio_src(&srcinfo, fp); + +// /* Enable saving of extra markers that we want to copy */ +// jcopy_markers_setup(&srcinfo, copyoption); + +// /* Read file header */ +// (void)jpeg_read_header(&srcinfo, TRUE); + +// #if TRANSFORMS_SUPPORTED +// if (dropfilename != NULL) { +// (void)jpeg_read_header(&dropinfo, TRUE); +// transformoption.crop_width = dropinfo.image_width; +// transformoption.crop_width_set = JCROP_POS; +// transformoption.crop_height = dropinfo.image_height; +// transformoption.crop_height_set = JCROP_POS; +// transformoption.drop_ptr = &dropinfo; +// } +// #endif + +// /* Any space needed by a transform option must be requested before +// * jpeg_read_coefficients so that memory allocation will be done right. +// */ +// #if TRANSFORMS_SUPPORTED +// /* Fail right away if -perfect is given and transformation is not perfect. +// */ +// if (!jtransform_request_workspace(&srcinfo, &transformoption)) { +// fprintf(stderr, "%s: transformation is not perfect\n", progname); +// exit(EXIT_FAILURE); +// } +// #endif + +// /* Read source file as DCT coefficients */ +// src_coef_arrays = jpeg_read_coefficients(&srcinfo); + +// #if TRANSFORMS_SUPPORTED +// if (dropfilename != NULL) { +// transformoption.drop_coef_arrays = jpeg_read_coefficients(&dropinfo); +// } +// #endif + +// /* Initialize destination compression parameters from source values */ +// jpeg_copy_critical_parameters(&srcinfo, &dstinfo); + +// /* Adjust destination parameters if required by transform options; +// * also find out which set of coefficient arrays will hold the output. +// */ +// #if TRANSFORMS_SUPPORTED +// dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, +// src_coef_arrays, +// &transformoption); +// #else +// dst_coef_arrays = src_coef_arrays; +// #endif + +// /* Close input file, if we opened it. +// * Note: we assume that jpeg_read_coefficients consumed all input +// * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will +// * only consume more while (!cinfo->inputctl->eoi_reached). +// * We cannot call jpeg_finish_decompress here since we still need the +// * virtual arrays allocated from the source object for processing. +// */ +// if (fp != stdin) +// fclose(fp); + +// /* Open the output file. */ +// if (outfilename != NULL) { +// if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s for writing\n", progname, +// outfilename); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default output file is stdout */ +// fp = write_stdout(); +// } + +// /* Adjust default compression parameters by re-parsing the options */ +// file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); + +// /* Specify data destination for compression */ +// jpeg_stdio_dest(&dstinfo, fp); + +// /* Start compressor (note no image data is actually written here) */ +// jpeg_write_coefficients(&dstinfo, dst_coef_arrays); + +// /* Copy to the output file any extra markers that we want to preserve */ +// jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); + +// if (icc_profile != NULL) +// jpeg_write_icc_profile(&dstinfo, icc_profile, (unsigned int)icc_len); + +// /* Execute image transformation, if any */ +// #if TRANSFORMS_SUPPORTED +// jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, +// &transformoption); +// #endif + +// /* Finish compression and release memory */ +// jpeg_finish_compress(&dstinfo); +// jpeg_destroy_compress(&dstinfo); +// #if TRANSFORMS_SUPPORTED +// if (dropfilename != NULL) { +// (void)jpeg_finish_decompress(&dropinfo); +// jpeg_destroy_decompress(&dropinfo); +// } +// #endif +// (void)jpeg_finish_decompress(&srcinfo); +// jpeg_destroy_decompress(&srcinfo); + +// /* Close output file, if we opened it */ +// if (fp != stdout) +// fclose(fp); +// #if TRANSFORMS_SUPPORTED +// if (drop_file != NULL) +// fclose(drop_file); +// #endif + +// if (report) +// end_progress_monitor((j_common_ptr)&dstinfo); +// if (report || max_scans != 0) +// end_progress_monitor((j_common_ptr)&srcinfo); + +// free(icc_profile); + +// /* All done. */ +// #if TRANSFORMS_SUPPORTED +// if (dropfilename != NULL) +// exit(jsrcerr.num_warnings + jdroperr.num_warnings + +// jdsterr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); +// #endif +// exit(jsrcerr.num_warnings + jdsterr.num_warnings ? +// EXIT_WARNING : EXIT_SUCCESS); +// return 0; /* suppress no-return-value warnings */ +// } diff --git a/Sources/TurboJPEG/jsamplecomp.h b/Sources/TurboJPEG/jsamplecomp.h index f3f275e6..fc87eb12 100644 --- a/Sources/TurboJPEG/jsamplecomp.h +++ b/Sources/TurboJPEG/jsamplecomp.h @@ -61,26 +61,29 @@ /* Global internal functions (jpegint.h) */ #ifdef C_LOSSLESS_SUPPORTED -#define _jinit_c_main_controller j16init_c_main_controller -#define _jinit_c_prep_controller j16init_c_prep_controller -#define _jinit_color_converter j16init_color_converter -#define _jinit_downsampler j16init_downsampler -#define _jinit_c_diff_controller j16init_c_diff_controller -#define _jinit_lossless_compressor j16init_lossless_compressor +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_c_main_controller j12init_c_main_controller +#define _jinit_c_prep_controller j12init_c_prep_controller +#define _jinit_color_converter j12init_color_converter +#define _jinit_downsampler j12init_downsampler +#define _jinit_c_diff_controller j12init_c_diff_controller +#define _jinit_lossless_compressor j12init_lossless_compressor #endif #ifdef D_LOSSLESS_SUPPORTED -#define _jinit_d_main_controller j16init_d_main_controller -#define _jinit_d_post_controller j16init_d_post_controller -#define _jinit_upsampler j16init_upsampler -#define _jinit_color_deconverter j16init_color_deconverter -#define _jinit_merged_upsampler j16init_merged_upsampler -#define _jinit_d_diff_controller j16init_d_diff_controller -#define _jinit_lossless_decompressor j16init_lossless_decompressor +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_d_main_controller j12init_d_main_controller +#define _jinit_d_post_controller j12init_d_post_controller +#define _jinit_upsampler j12init_upsampler +#define _jinit_color_deconverter j12init_color_deconverter +#define _jinit_merged_upsampler j12init_merged_upsampler +#define _jinit_d_diff_controller j12init_d_diff_controller +#define _jinit_lossless_decompressor j12init_lossless_decompressor #endif #if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) -#define _jcopy_sample_rows j16copy_sample_rows +// j16XXX hack until I clean up TurboJPEG. +#define _jcopy_sample_rows j12copy_sample_rows #endif /* Internal fields (cdjpeg.h) */ @@ -88,17 +91,20 @@ #if defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) /* Use the 16-bit buffer in the cjpeg_source_struct and djpeg_dest_struct structures. */ -#define _buffer buffer16 +// j16XXX hack until I clean up TurboJPEG. +#define _buffer buffer12 #endif /* Image I/O functions (cdjpeg.h) */ #ifdef C_LOSSLESS_SUPPORTED -#define _jinit_read_gif j16init_read_gif -#define _jinit_read_ppm j16init_read_ppm +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_read_gif j12init_read_gif +#define _jinit_read_ppm j12init_read_ppm #endif #ifdef D_LOSSLESS_SUPPORTED -#define _jinit_write_ppm j16init_write_ppm +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_write_ppm j12init_write_ppm #endif #elif BITS_IN_JSAMPLE == 12 @@ -219,22 +225,26 @@ #else /* BITS_IN_JSAMPLE */ /* Sample data types and macros (jmorecfg.h) */ -#define _JSAMPLE JSAMPLE +// j16XXX hack until I clean up TurboJPEG. +#define _JSAMPLE J12SAMPLE #define _MAXJSAMPLE MAXJSAMPLE #define _CENTERJSAMPLE CENTERJSAMPLE -#define _JSAMPROW JSAMPROW -#define _JSAMPARRAY JSAMPARRAY -#define _JSAMPIMAGE JSAMPIMAGE +// j16XXX hack until I clean up TurboJPEG. +#define _JSAMPROW J12SAMPROW +#define _JSAMPARRAY J12SAMPARRAY +#define _JSAMPIMAGE J12SAMPIMAGE /* External functions (jpeglib.h) */ -#define _jpeg_write_scanlines jpeg_write_scanlines -#define _jpeg_write_raw_data jpeg_write_raw_data -#define _jpeg_read_scanlines jpeg_read_scanlines -#define _jpeg_skip_scanlines jpeg_skip_scanlines -#define _jpeg_crop_scanline jpeg_crop_scanline -#define _jpeg_read_raw_data jpeg_read_raw_data + +// j16XXX hack until I clean up TurboJPEG. +#define _jpeg_write_scanlines jpeg12_write_scanlines +#define _jpeg_write_raw_data jpeg12_write_raw_data +#define _jpeg_read_scanlines jpeg12_read_scanlines +#define _jpeg_skip_scanlines jpeg12_skip_scanlines +#define _jpeg_crop_scanline jpeg12_crop_scanline +#define _jpeg_read_raw_data jpeg12_read_raw_data /* Internal methods (jpegint.h) */ @@ -267,32 +277,35 @@ #define _color_quantize color_quantize /* Global internal functions (jpegint.h) */ -#define _jinit_c_main_controller jinit_c_main_controller -#define _jinit_c_prep_controller jinit_c_prep_controller -#define _jinit_c_coef_controller jinit_c_coef_controller -#define _jinit_color_converter jinit_color_converter -#define _jinit_downsampler jinit_downsampler -#define _jinit_forward_dct jinit_forward_dct +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_c_main_controller j12init_c_main_controller +#define _jinit_c_prep_controller j12init_c_prep_controller +#define _jinit_c_coef_controller j12init_c_coef_controller +#define _jinit_color_converter j12init_color_converter +#define _jinit_downsampler j12init_downsampler +#define _jinit_forward_dct j12init_forward_dct #ifdef C_LOSSLESS_SUPPORTED -#define _jinit_c_diff_controller jinit_c_diff_controller -#define _jinit_lossless_compressor jinit_lossless_compressor +#define _jinit_c_diff_controller j12init_c_diff_controller +#define _jinit_lossless_compressor j12init_lossless_compressor #endif -#define _jinit_d_main_controller jinit_d_main_controller -#define _jinit_d_coef_controller jinit_d_coef_controller -#define _jinit_d_post_controller jinit_d_post_controller -#define _jinit_inverse_dct jinit_inverse_dct -#define _jinit_upsampler jinit_upsampler -#define _jinit_color_deconverter jinit_color_deconverter -#define _jinit_1pass_quantizer jinit_1pass_quantizer -#define _jinit_2pass_quantizer jinit_2pass_quantizer -#define _jinit_merged_upsampler jinit_merged_upsampler +// j16XXX hack until I clean up TurboJPEG. +#define _jinit_d_main_controller j12init_d_main_controller +#define _jinit_d_coef_controller j12init_d_coef_controller +#define _jinit_d_post_controller j12init_d_post_controller +#define _jinit_inverse_dct j12init_inverse_dct +#define _jinit_upsampler j12init_upsampler +#define _jinit_color_deconverter j12init_color_deconverter +#define _jinit_1pass_quantizer j12init_1pass_quantizer +#define _jinit_2pass_quantizer j12init_2pass_quantizer +#define _jinit_merged_upsampler j12init_merged_upsampler #ifdef D_LOSSLESS_SUPPORTED -#define _jinit_d_diff_controller jinit_d_diff_controller -#define _jinit_lossless_decompressor jinit_lossless_decompressor +#define _jinit_d_diff_controller j12init_d_diff_controller +#define _jinit_lossless_decompressor j12init_lossless_decompressor #endif -#define _jcopy_sample_rows jcopy_sample_rows +// j16XXX hack until I clean up TurboJPEG. +#define _jcopy_sample_rows j12copy_sample_rows /* Global internal functions (jdct.h) */ #define _jpeg_fdct_islow jpeg_fdct_islow @@ -329,7 +342,9 @@ #define _jinit_read_ppm jinit_read_ppm #define _jinit_write_ppm jinit_write_ppm -#define _read_color_map read_color_map +// j16XXX hack until I clean up TurboJPEG. +// #define _read_color_map read_color_map +#define _read_color_map read_color_map_12 #endif /* BITS_IN_JSAMPLE */ diff --git a/Sources/TurboJPEG/jutils.c b/Sources/TurboJPEG/jutils.c index 24caac19..13a5aedd 100644 --- a/Sources/TurboJPEG/jutils.c +++ b/Sources/TurboJPEG/jutils.c @@ -20,7 +20,9 @@ #include "jsamplecomp.h" -#if BITS_IN_JSAMPLE == 8 +// a hack until I clean up TurboJPEG. +// this is supposed to only compile when BITS_IN_JSAMPLE is 8 +// #if BITS_IN_JSAMPLE == 8 /* * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element @@ -92,11 +94,13 @@ jround_up(long a, long b) return a - (a % b); } -#endif /* BITS_IN_JSAMPLE == 8 */ +//#endif /* BITS_IN_JSAMPLE == 8 */ -#if BITS_IN_JSAMPLE != 16 || \ - defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) +// a hack until I clean up TurboJPEG. +// this is supposed to only compile for the below preprocessor condition +// #if BITS_IN_JSAMPLE != 16 || \ +// defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) GLOBAL(void) _jcopy_sample_rows(_JSAMPARRAY input_array, int source_row, @@ -122,11 +126,13 @@ _jcopy_sample_rows(_JSAMPARRAY input_array, int source_row, } } -#endif /* BITS_IN_JSAMPLE != 16 || - defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) */ +// #endif /* BITS_IN_JSAMPLE != 16 || +// defined(C_LOSSLESS_SUPPORTED) || defined(D_LOSSLESS_SUPPORTED) */ -#if BITS_IN_JSAMPLE == 8 +// a hack until I clean up TurboJPEG. +// this is supposed to only compile when BITS_IN_JSAMPLE is 8 +// #if BITS_IN_JSAMPLE == 8 GLOBAL(void) jcopy_block_row(JBLOCKROW input_row, JBLOCKROW output_row, @@ -145,4 +151,4 @@ jzero_far(void *target, size_t bytestozero) memset(target, 0, bytestozero); } -#endif /* BITS_IN_JSAMPLE == 8 */ +// #endif /* BITS_IN_JSAMPLE == 8 */ diff --git a/Sources/TurboJPEG/rdjpgcom.c b/Sources/TurboJPEG/rdjpgcom.c index d9a6f85a..f4255c1e 100644 --- a/Sources/TurboJPEG/rdjpgcom.c +++ b/Sources/TurboJPEG/rdjpgcom.c @@ -433,61 +433,61 @@ keymatch(char *arg, const char *keyword, int minchars) * The main program. */ -int -main(int argc, char **argv) -{ - int argn; - char *arg; - int verbose = 0, raw = 0; - - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "rdjpgcom"; /* in case C library doesn't provide it */ - - /* Parse switches, if any */ - for (argn = 1; argn < argc; argn++) { - arg = argv[argn]; - if (arg[0] != '-') - break; /* not switch, must be file name */ - arg++; /* advance over '-' */ - if (keymatch(arg, "verbose", 1)) { - verbose++; - } else if (keymatch(arg, "raw", 1)) { - raw = 1; - } else - usage(); - } - - /* Open the input file. */ - /* Unix style: expect zero or one file name */ - if (argn < argc - 1) { - fprintf(stderr, "%s: only one input file\n", progname); - usage(); - } - if (argn < argc) { - if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); - exit(EXIT_FAILURE); - } - } else { - /* default input file is stdin */ -#ifdef USE_SETMODE /* need to hack file mode? */ - setmode(fileno(stdin), O_BINARY); -#endif -#ifdef USE_FDOPEN /* need to re-open in binary mode? */ - if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open stdin\n", progname); - exit(EXIT_FAILURE); - } -#else - infile = stdin; -#endif - } - - /* Scan the JPEG headers. */ - (void)scan_JPEG_header(verbose, raw); - - /* All done. */ - exit(EXIT_SUCCESS); - return 0; /* suppress no-return-value warnings */ -} +// int +// main(int argc, char **argv) +// { +// int argn; +// char *arg; +// int verbose = 0, raw = 0; + +// progname = argv[0]; +// if (progname == NULL || progname[0] == 0) +// progname = "rdjpgcom"; /* in case C library doesn't provide it */ + +// /* Parse switches, if any */ +// for (argn = 1; argn < argc; argn++) { +// arg = argv[argn]; +// if (arg[0] != '-') +// break; /* not switch, must be file name */ +// arg++; /* advance over '-' */ +// if (keymatch(arg, "verbose", 1)) { +// verbose++; +// } else if (keymatch(arg, "raw", 1)) { +// raw = 1; +// } else +// usage(); +// } + +// /* Open the input file. */ +// /* Unix style: expect zero or one file name */ +// if (argn < argc - 1) { +// fprintf(stderr, "%s: only one input file\n", progname); +// usage(); +// } +// if (argn < argc) { +// if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default input file is stdin */ +// #ifdef USE_SETMODE /* need to hack file mode? */ +// setmode(fileno(stdin), O_BINARY); +// #endif +// #ifdef USE_FDOPEN /* need to re-open in binary mode? */ +// if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open stdin\n", progname); +// exit(EXIT_FAILURE); +// } +// #else +// infile = stdin; +// #endif +// } + +// /* Scan the JPEG headers. */ +// (void)scan_JPEG_header(verbose, raw); + +// /* All done. */ +// exit(EXIT_SUCCESS); +// return 0; /* suppress no-return-value warnings */ +// } diff --git a/Sources/TurboJPEG/strtest.c b/Sources/TurboJPEG/strtest.c index 3d5e004c..5669923f 100644 --- a/Sources/TurboJPEG/strtest.c +++ b/Sources/TurboJPEG/strtest.c @@ -53,118 +53,118 @@ void invalid_parameter_handler(const wchar_t *expression, #endif -int main(int argc, char **argv) -{ -#if !defined(NO_GETENV) || !defined(NO_PUTENV) - int err; -#endif -#ifndef NO_GETENV - char env[3]; -#endif - -#ifdef _MSC_VER - _set_invalid_parameter_handler(invalid_parameter_handler); -#endif - - /***************************************************************************/ - -#ifndef NO_PUTENV - - printf("PUTENV_S():\n"); - - errno = 0; - err = PUTENV_S(NULL, "12"); - CHECK_ERRNO(err, EINVAL); - - errno = 0; - err = PUTENV_S("TESTENV", NULL); - CHECK_ERRNO(err, EINVAL); - - errno = 0; - err = PUTENV_S("TESTENV", "12"); - CHECK_ERRNO(err, 0); - - printf("SUCCESS!\n\n"); - -#endif - - /***************************************************************************/ - -#ifndef NO_GETENV - - printf("GETENV_S():\n"); - - errno = 0; - env[0] = 1; - env[1] = 2; - env[2] = 3; - err = GETENV_S(env, 3, NULL); - CHECK_ERRNO(err, 0); - CHECK_VALUE(env[0], 0, "env[0]"); - CHECK_VALUE(env[1], 2, "env[1]"); - CHECK_VALUE(env[2], 3, "env[2]"); - - errno = 0; - env[0] = 1; - env[1] = 2; - env[2] = 3; - err = GETENV_S(env, 3, "TESTENV2"); - CHECK_ERRNO(err, 0); - CHECK_VALUE(env[0], 0, "env[0]"); - CHECK_VALUE(env[1], 2, "env[1]"); - CHECK_VALUE(env[2], 3, "env[2]"); - - errno = 0; - err = GETENV_S(NULL, 3, "TESTENV"); - CHECK_ERRNO(err, EINVAL); - - errno = 0; - err = GETENV_S(NULL, 0, "TESTENV"); - CHECK_ERRNO(err, 0); - - errno = 0; - env[0] = 1; - err = GETENV_S(env, 0, "TESTENV"); - CHECK_ERRNO(err, EINVAL); - CHECK_VALUE(env[0], 1, "env[0]"); - - errno = 0; - env[0] = 1; - env[1] = 2; - env[2] = 3; - err = GETENV_S(env, 1, "TESTENV"); - CHECK_VALUE(err, ERANGE, "Return value"); - CHECK_VALUE(errno, 0, "errno"); - CHECK_VALUE(env[0], 0, "env[0]"); - CHECK_VALUE(env[1], 2, "env[1]"); - CHECK_VALUE(env[2], 3, "env[2]"); - - errno = 0; - env[0] = 1; - env[1] = 2; - env[2] = 3; - err = GETENV_S(env, 2, "TESTENV"); - CHECK_VALUE(err, ERANGE, "Return value"); - CHECK_VALUE(errno, 0, "errno"); - CHECK_VALUE(env[0], 0, "env[0]"); - CHECK_VALUE(env[1], 2, "env[1]"); - CHECK_VALUE(env[2], 3, "env[2]"); - - errno = 0; - env[0] = 1; - env[1] = 2; - env[2] = 3; - err = GETENV_S(env, 3, "TESTENV"); - CHECK_ERRNO(err, 0); - CHECK_VALUE(env[0], '1', "env[0]"); - CHECK_VALUE(env[1], '2', "env[1]"); - CHECK_VALUE(env[2], 0, "env[2]"); - - printf("SUCCESS!\n\n"); - -#endif - - /***************************************************************************/ - - return 0; -} +// int main(int argc, char **argv) +// { +// #if !defined(NO_GETENV) || !defined(NO_PUTENV) +// int err; +// #endif +// #ifndef NO_GETENV +// char env[3]; +// #endif + +// #ifdef _MSC_VER +// _set_invalid_parameter_handler(invalid_parameter_handler); +// #endif + +// /***************************************************************************/ + +// #ifndef NO_PUTENV + +// printf("PUTENV_S():\n"); + +// errno = 0; +// err = PUTENV_S(NULL, "12"); +// CHECK_ERRNO(err, EINVAL); + +// errno = 0; +// err = PUTENV_S("TESTENV", NULL); +// CHECK_ERRNO(err, EINVAL); + +// errno = 0; +// err = PUTENV_S("TESTENV", "12"); +// CHECK_ERRNO(err, 0); + +// printf("SUCCESS!\n\n"); + +// #endif + +// /***************************************************************************/ + +// #ifndef NO_GETENV + +// printf("GETENV_S():\n"); + +// errno = 0; +// env[0] = 1; +// env[1] = 2; +// env[2] = 3; +// err = GETENV_S(env, 3, NULL); +// CHECK_ERRNO(err, 0); +// CHECK_VALUE(env[0], 0, "env[0]"); +// CHECK_VALUE(env[1], 2, "env[1]"); +// CHECK_VALUE(env[2], 3, "env[2]"); + +// errno = 0; +// env[0] = 1; +// env[1] = 2; +// env[2] = 3; +// err = GETENV_S(env, 3, "TESTENV2"); +// CHECK_ERRNO(err, 0); +// CHECK_VALUE(env[0], 0, "env[0]"); +// CHECK_VALUE(env[1], 2, "env[1]"); +// CHECK_VALUE(env[2], 3, "env[2]"); + +// errno = 0; +// err = GETENV_S(NULL, 3, "TESTENV"); +// CHECK_ERRNO(err, EINVAL); + +// errno = 0; +// err = GETENV_S(NULL, 0, "TESTENV"); +// CHECK_ERRNO(err, 0); + +// errno = 0; +// env[0] = 1; +// err = GETENV_S(env, 0, "TESTENV"); +// CHECK_ERRNO(err, EINVAL); +// CHECK_VALUE(env[0], 1, "env[0]"); + +// errno = 0; +// env[0] = 1; +// env[1] = 2; +// env[2] = 3; +// err = GETENV_S(env, 1, "TESTENV"); +// CHECK_VALUE(err, ERANGE, "Return value"); +// CHECK_VALUE(errno, 0, "errno"); +// CHECK_VALUE(env[0], 0, "env[0]"); +// CHECK_VALUE(env[1], 2, "env[1]"); +// CHECK_VALUE(env[2], 3, "env[2]"); + +// errno = 0; +// env[0] = 1; +// env[1] = 2; +// env[2] = 3; +// err = GETENV_S(env, 2, "TESTENV"); +// CHECK_VALUE(err, ERANGE, "Return value"); +// CHECK_VALUE(errno, 0, "errno"); +// CHECK_VALUE(env[0], 0, "env[0]"); +// CHECK_VALUE(env[1], 2, "env[1]"); +// CHECK_VALUE(env[2], 3, "env[2]"); + +// errno = 0; +// env[0] = 1; +// env[1] = 2; +// env[2] = 3; +// err = GETENV_S(env, 3, "TESTENV"); +// CHECK_ERRNO(err, 0); +// CHECK_VALUE(env[0], '1', "env[0]"); +// CHECK_VALUE(env[1], '2', "env[1]"); +// CHECK_VALUE(env[2], 0, "env[2]"); + +// printf("SUCCESS!\n\n"); + +// #endif + +// /***************************************************************************/ + +// return 0; +// } diff --git a/Sources/TurboJPEG/tjbench.c b/Sources/TurboJPEG/tjbench.c index adabe8e9..0dff2aea 100644 --- a/Sources/TurboJPEG/tjbench.c +++ b/Sources/TurboJPEG/tjbench.c @@ -276,16 +276,18 @@ static int decomp(unsigned char **jpegBufs, size_t *jpegSizes, void *dstBuf, if (iter >= 0) elapsedDecode += getTime() - startDecode; } else { if (precision == 8) { - if (tj3Decompress8(handle, jpegBufs[tile], jpegSizes[tile], - dstPtr2, pitch, pf) == -1) + // j16XXX hack until I clean up TurboJPEG. + if (tj3Decompress12(handle, jpegBufs[tile], jpegSizes[tile], + (short *)dstPtr2, pitch, pf) == -1) THROW_TJ(); } else if (precision == 12) { if (tj3Decompress12(handle, jpegBufs[tile], jpegSizes[tile], (short *)dstPtr2, pitch, pf) == -1) THROW_TJ(); } else { - if (tj3Decompress16(handle, jpegBufs[tile], jpegSizes[tile], - (unsigned short *)dstPtr2, pitch, pf) == -1) + // j16XXX hack until I clean up TurboJPEG. + if (tj3Decompress12(handle, jpegBufs[tile], jpegSizes[tile], + (short *)dstPtr2, pitch, pf) == -1) THROW_TJ(); } } @@ -339,15 +341,16 @@ static int decomp(unsigned char **jpegBufs, size_t *jpegSizes, void *dstBuf, lossless ? "LOSSLS" : subName[subsamp], qualStr, sizeStr, ext); if (precision == 8) { - if (tj3SaveImage8(handle, tempStr, (unsigned char *)dstBuf, scaledw, 0, - scaledh, pf) == -1) + if (tj3SaveImage12(handle, tempStr, (short *)dstBuf, scaledw, 0, + scaledh, pf) == -1) THROW_TJ(); } else if (precision == 12) { if (tj3SaveImage12(handle, tempStr, (short *)dstBuf, scaledw, 0, scaledh, pf) == -1) THROW_TJ(); } else { - if (tj3SaveImage16(handle, tempStr, (unsigned short *)dstBuf, scaledw, 0, + // j16XXX hack until I clean up TurboJPEG. + if (tj3SaveImage12(handle, tempStr, (short *)dstBuf, scaledw, 0, scaledh, pf) == -1) THROW_TJ(); } @@ -491,15 +494,17 @@ static int fullTest(tjhandle handle, void *srcBuf, int w, int h, int subsamp, THROW_TJ(); } else { if (precision == 8) { - if (tj3Compress8(handle, srcPtr2, width, pitch, height, pf, - &jpegBufs[tile], &jpegSizes[tile]) == -1) + if (tj3Compress12(handle, (short *)srcPtr2, width, pitch, height, + pf, &jpegBufs[tile], &jpegSizes[tile]) == -1) THROW_TJ(); } else if (precision == 12) { + if (tj3Compress12(handle, (short *)srcPtr2, width, pitch, height, pf, &jpegBufs[tile], &jpegSizes[tile]) == -1) THROW_TJ(); } else { - if (tj3Compress16(handle, (unsigned short *)srcPtr2, width, + // j16XXX hack until I clean up TurboJPEG. + if (tj3Compress12(handle, (short *)srcPtr2, width, pitch, height, pf, &jpegBufs[tile], &jpegSizes[tile]) == -1) THROW_TJ(); @@ -975,313 +980,315 @@ static void usage(char *progName) } -int main(int argc, char *argv[]) -{ - void *srcBuf = NULL; - int w = 0, h = 0, i, j, minQual = -1, maxQual = -1; - char *temp; - int minArg = 2, retval = 0, subsamp = -1; - tjhandle handle = NULL; - - if ((scalingFactors = tj3GetScalingFactors(&nsf)) == NULL || nsf == 0) - THROW("executing tj3GetScalingFactors()", tj3GetErrorStr(NULL)); - - if (argc < minArg) usage(argv[0]); - - temp = strrchr(argv[1], '.'); - if (temp != NULL) { - if (!strcasecmp(temp, ".bmp")) ext = "bmp"; - if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) - decompOnly = 1; - } - - printf("\n"); - - if (!decompOnly) { - minArg = 3; - if (argc < minArg) usage(argv[0]); - minQual = atoi(argv[2]); - if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 && - sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual) {} - else maxQual = minQual; - } - - if (argc > minArg) { - for (i = minArg; i < argc; i++) { - if (!strcasecmp(argv[i], "-tile")) { - doTile = 1; xformOpt |= TJXOPT_CROP; - } else if (!strcasecmp(argv[i], "-precision") && i < argc - 1) { - int tempi = atoi(argv[++i]); - - if (tempi != 8 && tempi != 12 && tempi != 16) - usage(argv[0]); - precision = tempi; - } else if (!strcasecmp(argv[i], "-fastupsample")) { - printf("Using fastest upsampling algorithm\n\n"); - fastUpsample = 1; - } else if (!strcasecmp(argv[i], "-fastdct")) { - printf("Using fastest DCT/IDCT algorithm\n\n"); - fastDCT = 1; - } else if (!strcasecmp(argv[i], "-optimize")) { - printf("Using optimized baseline entropy coding\n\n"); - optimize = 1; - xformOpt |= TJXOPT_OPTIMIZE; - } else if (!strcasecmp(argv[i], "-progressive")) { - printf("Using progressive entropy coding\n\n"); - progressive = 1; - xformOpt |= TJXOPT_PROGRESSIVE; - } else if (!strcasecmp(argv[i], "-arithmetic")) { - printf("Using arithmetic entropy coding\n\n"); - arithmetic = 1; - xformOpt |= TJXOPT_ARITHMETIC; - } else if (!strcasecmp(argv[i], "-lossless")) { - lossless = 1; - subsamp = TJSAMP_444; - } else if (!strcasecmp(argv[i], "-rgb")) - pf = TJPF_RGB; - else if (!strcasecmp(argv[i], "-rgbx")) - pf = TJPF_RGBX; - else if (!strcasecmp(argv[i], "-bgr")) - pf = TJPF_BGR; - else if (!strcasecmp(argv[i], "-bgrx")) - pf = TJPF_BGRX; - else if (!strcasecmp(argv[i], "-xbgr")) - pf = TJPF_XBGR; - else if (!strcasecmp(argv[i], "-xrgb")) - pf = TJPF_XRGB; - else if (!strcasecmp(argv[i], "-cmyk")) - pf = TJPF_CMYK; - else if (!strcasecmp(argv[i], "-bottomup")) - bottomUp = 1; - else if (!strcasecmp(argv[i], "-quiet")) - quiet = 1; - else if (!strcasecmp(argv[i], "-qq")) - quiet = 2; - else if (!strcasecmp(argv[i], "-scale") && i < argc - 1) { - int temp1 = 0, temp2 = 0, match = 0; - - if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) { - for (j = 0; j < nsf; j++) { - if (temp1 == scalingFactors[j].num && - temp2 == scalingFactors[j].denom) { - sf = scalingFactors[j]; - match = 1; break; - } - } - if (!match) usage(argv[0]); - } else usage(argv[0]); - } else if (!strcasecmp(argv[i], "-crop") && i < argc - 1) { - int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1; - - if (sscanf(argv[++i], "%dx%d+%d+%d", &temp1, &temp2, &temp3, - &temp4) == 4 && temp1 >= 0 && temp2 >= 0 && temp3 >= 0 && - temp4 >= 0) { - cr.w = temp1; cr.h = temp2; cr.x = temp3; cr.y = temp4; - } else usage(argv[0]); - } else if (!strcasecmp(argv[i], "-hflip")) - xformOp = TJXOP_HFLIP; - else if (!strcasecmp(argv[i], "-vflip")) - xformOp = TJXOP_VFLIP; - else if (!strcasecmp(argv[i], "-transpose")) - xformOp = TJXOP_TRANSPOSE; - else if (!strcasecmp(argv[i], "-transverse")) - xformOp = TJXOP_TRANSVERSE; - else if (!strcasecmp(argv[i], "-rot90")) - xformOp = TJXOP_ROT90; - else if (!strcasecmp(argv[i], "-rot180")) - xformOp = TJXOP_ROT180; - else if (!strcasecmp(argv[i], "-rot270")) - xformOp = TJXOP_ROT270; - else if (!strcasecmp(argv[i], "-grayscale")) - xformOpt |= TJXOPT_GRAY; - else if (!strcasecmp(argv[i], "-custom")) - customFilter = dummyDCTFilter; - else if (!strcasecmp(argv[i], "-nooutput")) - xformOpt |= TJXOPT_NOOUTPUT; - else if (!strcasecmp(argv[i], "-copynone")) - xformOpt |= TJXOPT_COPYNONE; - else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) { - double tempd = atof(argv[++i]); - - if (tempd > 0.0) benchTime = tempd; - else usage(argv[0]); - } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) { - double tempd = atof(argv[++i]); - - if (tempd >= 0.0) warmup = tempd; - else usage(argv[0]); - printf("Warmup time = %.1f seconds\n\n", warmup); - } else if (!strcasecmp(argv[i], "-alloc")) - noRealloc = 0; - else if (!strcasecmp(argv[i], "-bmp")) - ext = "bmp"; - else if (!strcasecmp(argv[i], "-yuv")) { - printf("Testing planar YUV encoding/decoding\n\n"); - doYUV = 1; - } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) { - int tempi = atoi(argv[++i]); - - if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi; - else usage(argv[0]); - } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) { - i++; - if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY; - else { - int tempi = atoi(argv[i]); - - switch (tempi) { - case 444: subsamp = TJSAMP_444; break; - case 422: subsamp = TJSAMP_422; break; - case 440: subsamp = TJSAMP_440; break; - case 420: subsamp = TJSAMP_420; break; - case 411: subsamp = TJSAMP_411; break; - case 441: subsamp = TJSAMP_441; break; - default: usage(argv[0]); - } - } - } else if (!strcasecmp(argv[i], "-componly")) - compOnly = 1; - else if (!strcasecmp(argv[i], "-nowrite")) - doWrite = 0; - else if (!strcasecmp(argv[i], "-limitscans")) - limitScans = 1; - else if (!strcasecmp(argv[i], "-restart") && i < argc - 1) { - int tempi = -1, nscan; char tempc = 0; - - if ((nscan = sscanf(argv[++i], "%d%c", &tempi, &tempc)) < 1 || - tempi < 0 || tempi > 65535 || - (nscan == 2 && tempc != 'B' && tempc != 'b')) - usage(argv[0]); - - if (tempc == 'B' || tempc == 'b') - restartIntervalBlocks = tempi; - else - restartIntervalRows = tempi; - } else if (!strcasecmp(argv[i], "-stoponwarning")) - stopOnWarning = 1; - else usage(argv[0]); - } - } - - if (precision == 16 && !lossless) { - printf("ERROR: -lossless must be specified along with -precision 16\n"); - retval = -1; goto bailout; - } - if (precision != 8 && doYUV) { - printf("ERROR: -yuv requires 8-bit data precision\n"); - retval = -1; goto bailout; - } - if (lossless && doYUV) { - printf("ERROR: -lossless and -yuv are incompatible\n"); - retval = -1; goto bailout; - } - sampleSize = (precision == 8 ? sizeof(unsigned char) : sizeof(short)); - - if ((sf.num != 1 || sf.denom != 1) && doTile) { - printf("Disabling tiled compression/decompression tests, because those tests do not\n"); - printf("work when scaled decompression is enabled.\n\n"); - doTile = 0; xformOpt &= (~TJXOPT_CROP); - } - - if (IS_CROPPED(cr)) { - if (!decompOnly) { - printf("ERROR: Partial image decompression can only be enabled for JPEG input images\n"); - retval = -1; goto bailout; - } - if (doTile) { - printf("Disabling tiled compression/decompression tests, because those tests do not\n"); - printf("work when partial image decompression is enabled.\n\n"); - doTile = 0; xformOpt &= (~TJXOPT_CROP); - } - if (doYUV) { - printf("ERROR: -crop and -yuv are incompatible\n"); - retval = -1; goto bailout; - } - } - - if (!noRealloc && doTile) { - printf("Disabling tiled compression/decompression tests, because those tests do not\n"); - printf("work when dynamic JPEG buffer allocation is enabled.\n\n"); - doTile = 0; xformOpt &= (~TJXOPT_CROP); - } - - if (!decompOnly) { - if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) - THROW_TJG(); - if (tj3Set(handle, TJPARAM_STOPONWARNING, stopOnWarning) == -1) - THROW_TJ(); - if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1) - THROW_TJ(); - - if (precision == 8) { - if ((srcBuf = tj3LoadImage8(handle, argv[1], &w, 1, &h, &pf)) == NULL) - THROW_TJ(); - } else if (precision == 12) { - if ((srcBuf = tj3LoadImage12(handle, argv[1], &w, 1, &h, &pf)) == NULL) - THROW_TJ(); - } else { - if ((srcBuf = tj3LoadImage16(handle, argv[1], &w, 1, &h, &pf)) == NULL) - THROW_TJ(); - } - temp = strrchr(argv[1], '.'); - if (temp != NULL) *temp = '\0'; - } - - if (quiet == 1 && !decompOnly) { - printf("All performance values in Mpixels/sec\n\n"); - printf("Pixel JPEG JPEG %s %s ", - doTile ? "Tile " : "Image", doTile ? "Tile " : "Image"); - if (doYUV) printf("Encode "); - printf("Comp Comp Decomp "); - if (doYUV) printf("Decode"); - printf("\n"); - printf("Format Format %s Width Height ", - lossless ? "PSV " : "Qual"); - if (doYUV) printf("Perf "); - printf("Perf Ratio Perf "); - if (doYUV) printf("Perf"); - printf("\n\n"); - } - - if (decompOnly) { - decompTest(argv[1]); - printf("\n"); - goto bailout; - } - if (lossless) { - if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7) { - puts("ERROR: PSV must be between 1 and 7."); - exit(1); - } - } else { - if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100) { - puts("ERROR: Quality must be between 1 and 100."); - exit(1); - } - } - if (subsamp >= 0 && subsamp < TJ_NUMSAMP) { - for (i = maxQual; i >= minQual; i--) - fullTest(handle, srcBuf, w, h, subsamp, i, argv[1]); - printf("\n"); - } else { - if (pf != TJPF_CMYK) { - for (i = maxQual; i >= minQual; i--) - fullTest(handle, srcBuf, w, h, TJSAMP_GRAY, i, argv[1]); - printf("\n"); - } - for (i = maxQual; i >= minQual; i--) - fullTest(handle, srcBuf, w, h, TJSAMP_420, i, argv[1]); - printf("\n"); - for (i = maxQual; i >= minQual; i--) - fullTest(handle, srcBuf, w, h, TJSAMP_422, i, argv[1]); - printf("\n"); - for (i = maxQual; i >= minQual; i--) - fullTest(handle, srcBuf, w, h, TJSAMP_444, i, argv[1]); - printf("\n"); - } - -bailout: - tj3Destroy(handle); - tj3Free(srcBuf); - return retval; -} +// int main(int argc, char *argv[]) +// { +// void *srcBuf = NULL; +// int w = 0, h = 0, i, j, minQual = -1, maxQual = -1; +// char *temp; +// int minArg = 2, retval = 0, subsamp = -1; +// tjhandle handle = NULL; + +// if ((scalingFactors = tj3GetScalingFactors(&nsf)) == NULL || nsf == 0) +// THROW("executing tj3GetScalingFactors()", tj3GetErrorStr(NULL)); + +// if (argc < minArg) usage(argv[0]); + +// temp = strrchr(argv[1], '.'); +// if (temp != NULL) { +// if (!strcasecmp(temp, ".bmp")) ext = "bmp"; +// if (!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) +// decompOnly = 1; +// } + +// printf("\n"); + +// if (!decompOnly) { +// minArg = 3; +// if (argc < minArg) usage(argv[0]); +// minQual = atoi(argv[2]); +// if ((temp = strchr(argv[2], '-')) != NULL && strlen(temp) > 1 && +// sscanf(&temp[1], "%d", &maxQual) == 1 && maxQual > minQual) {} +// else maxQual = minQual; +// } + +// if (argc > minArg) { +// for (i = minArg; i < argc; i++) { +// if (!strcasecmp(argv[i], "-tile")) { +// doTile = 1; xformOpt |= TJXOPT_CROP; +// } else if (!strcasecmp(argv[i], "-precision") && i < argc - 1) { +// int tempi = atoi(argv[++i]); + +// if (tempi != 8 && tempi != 12 && tempi != 16) +// usage(argv[0]); +// precision = tempi; +// } else if (!strcasecmp(argv[i], "-fastupsample")) { +// printf("Using fastest upsampling algorithm\n\n"); +// fastUpsample = 1; +// } else if (!strcasecmp(argv[i], "-fastdct")) { +// printf("Using fastest DCT/IDCT algorithm\n\n"); +// fastDCT = 1; +// } else if (!strcasecmp(argv[i], "-optimize")) { +// printf("Using optimized baseline entropy coding\n\n"); +// optimize = 1; +// xformOpt |= TJXOPT_OPTIMIZE; +// } else if (!strcasecmp(argv[i], "-progressive")) { +// printf("Using progressive entropy coding\n\n"); +// progressive = 1; +// xformOpt |= TJXOPT_PROGRESSIVE; +// } else if (!strcasecmp(argv[i], "-arithmetic")) { +// printf("Using arithmetic entropy coding\n\n"); +// arithmetic = 1; +// xformOpt |= TJXOPT_ARITHMETIC; +// } else if (!strcasecmp(argv[i], "-lossless")) { +// lossless = 1; +// subsamp = TJSAMP_444; +// } else if (!strcasecmp(argv[i], "-rgb")) +// pf = TJPF_RGB; +// else if (!strcasecmp(argv[i], "-rgbx")) +// pf = TJPF_RGBX; +// else if (!strcasecmp(argv[i], "-bgr")) +// pf = TJPF_BGR; +// else if (!strcasecmp(argv[i], "-bgrx")) +// pf = TJPF_BGRX; +// else if (!strcasecmp(argv[i], "-xbgr")) +// pf = TJPF_XBGR; +// else if (!strcasecmp(argv[i], "-xrgb")) +// pf = TJPF_XRGB; +// else if (!strcasecmp(argv[i], "-cmyk")) +// pf = TJPF_CMYK; +// else if (!strcasecmp(argv[i], "-bottomup")) +// bottomUp = 1; +// else if (!strcasecmp(argv[i], "-quiet")) +// quiet = 1; +// else if (!strcasecmp(argv[i], "-qq")) +// quiet = 2; +// else if (!strcasecmp(argv[i], "-scale") && i < argc - 1) { +// int temp1 = 0, temp2 = 0, match = 0; + +// if (sscanf(argv[++i], "%d/%d", &temp1, &temp2) == 2) { +// for (j = 0; j < nsf; j++) { +// if (temp1 == scalingFactors[j].num && +// temp2 == scalingFactors[j].denom) { +// sf = scalingFactors[j]; +// match = 1; break; +// } +// } +// if (!match) usage(argv[0]); +// } else usage(argv[0]); +// } else if (!strcasecmp(argv[i], "-crop") && i < argc - 1) { +// int temp1 = -1, temp2 = -1, temp3 = -1, temp4 = -1; + +// if (sscanf(argv[++i], "%dx%d+%d+%d", &temp1, &temp2, &temp3, +// &temp4) == 4 && temp1 >= 0 && temp2 >= 0 && temp3 >= 0 && +// temp4 >= 0) { +// cr.w = temp1; cr.h = temp2; cr.x = temp3; cr.y = temp4; +// } else usage(argv[0]); +// } else if (!strcasecmp(argv[i], "-hflip")) +// xformOp = TJXOP_HFLIP; +// else if (!strcasecmp(argv[i], "-vflip")) +// xformOp = TJXOP_VFLIP; +// else if (!strcasecmp(argv[i], "-transpose")) +// xformOp = TJXOP_TRANSPOSE; +// else if (!strcasecmp(argv[i], "-transverse")) +// xformOp = TJXOP_TRANSVERSE; +// else if (!strcasecmp(argv[i], "-rot90")) +// xformOp = TJXOP_ROT90; +// else if (!strcasecmp(argv[i], "-rot180")) +// xformOp = TJXOP_ROT180; +// else if (!strcasecmp(argv[i], "-rot270")) +// xformOp = TJXOP_ROT270; +// else if (!strcasecmp(argv[i], "-grayscale")) +// xformOpt |= TJXOPT_GRAY; +// else if (!strcasecmp(argv[i], "-custom")) +// customFilter = dummyDCTFilter; +// else if (!strcasecmp(argv[i], "-nooutput")) +// xformOpt |= TJXOPT_NOOUTPUT; +// else if (!strcasecmp(argv[i], "-copynone")) +// xformOpt |= TJXOPT_COPYNONE; +// else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) { +// double tempd = atof(argv[++i]); + +// if (tempd > 0.0) benchTime = tempd; +// else usage(argv[0]); +// } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) { +// double tempd = atof(argv[++i]); + +// if (tempd >= 0.0) warmup = tempd; +// else usage(argv[0]); +// printf("Warmup time = %.1f seconds\n\n", warmup); +// } else if (!strcasecmp(argv[i], "-alloc")) +// noRealloc = 0; +// else if (!strcasecmp(argv[i], "-bmp")) +// ext = "bmp"; +// else if (!strcasecmp(argv[i], "-yuv")) { +// printf("Testing planar YUV encoding/decoding\n\n"); +// doYUV = 1; +// } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) { +// int tempi = atoi(argv[++i]); + +// if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi; +// else usage(argv[0]); +// } else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) { +// i++; +// if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY; +// else { +// int tempi = atoi(argv[i]); + +// switch (tempi) { +// case 444: subsamp = TJSAMP_444; break; +// case 422: subsamp = TJSAMP_422; break; +// case 440: subsamp = TJSAMP_440; break; +// case 420: subsamp = TJSAMP_420; break; +// case 411: subsamp = TJSAMP_411; break; +// case 441: subsamp = TJSAMP_441; break; +// default: usage(argv[0]); +// } +// } +// } else if (!strcasecmp(argv[i], "-componly")) +// compOnly = 1; +// else if (!strcasecmp(argv[i], "-nowrite")) +// doWrite = 0; +// else if (!strcasecmp(argv[i], "-limitscans")) +// limitScans = 1; +// else if (!strcasecmp(argv[i], "-restart") && i < argc - 1) { +// int tempi = -1, nscan; char tempc = 0; + +// if ((nscan = sscanf(argv[++i], "%d%c", &tempi, &tempc)) < 1 || +// tempi < 0 || tempi > 65535 || +// (nscan == 2 && tempc != 'B' && tempc != 'b')) +// usage(argv[0]); + +// if (tempc == 'B' || tempc == 'b') +// restartIntervalBlocks = tempi; +// else +// restartIntervalRows = tempi; +// } else if (!strcasecmp(argv[i], "-stoponwarning")) +// stopOnWarning = 1; +// else usage(argv[0]); +// } +// } + +// if (precision == 16 && !lossless) { +// printf("ERROR: -lossless must be specified along with -precision 16\n"); +// retval = -1; goto bailout; +// } +// if (precision != 8 && doYUV) { +// printf("ERROR: -yuv requires 8-bit data precision\n"); +// retval = -1; goto bailout; +// } +// if (lossless && doYUV) { +// printf("ERROR: -lossless and -yuv are incompatible\n"); +// retval = -1; goto bailout; +// } +// sampleSize = (precision == 8 ? sizeof(unsigned char) : sizeof(short)); + +// if ((sf.num != 1 || sf.denom != 1) && doTile) { +// printf("Disabling tiled compression/decompression tests, because those tests do not\n"); +// printf("work when scaled decompression is enabled.\n\n"); +// doTile = 0; xformOpt &= (~TJXOPT_CROP); +// } + +// if (IS_CROPPED(cr)) { +// if (!decompOnly) { +// printf("ERROR: Partial image decompression can only be enabled for JPEG input images\n"); +// retval = -1; goto bailout; +// } +// if (doTile) { +// printf("Disabling tiled compression/decompression tests, because those tests do not\n"); +// printf("work when partial image decompression is enabled.\n\n"); +// doTile = 0; xformOpt &= (~TJXOPT_CROP); +// } +// if (doYUV) { +// printf("ERROR: -crop and -yuv are incompatible\n"); +// retval = -1; goto bailout; +// } +// } + +// if (!noRealloc && doTile) { +// printf("Disabling tiled compression/decompression tests, because those tests do not\n"); +// printf("work when dynamic JPEG buffer allocation is enabled.\n\n"); +// doTile = 0; xformOpt &= (~TJXOPT_CROP); +// } + +// if (!decompOnly) { +// if ((handle = tj3Init(TJINIT_COMPRESS)) == NULL) +// THROW_TJG(); +// if (tj3Set(handle, TJPARAM_STOPONWARNING, stopOnWarning) == -1) +// THROW_TJ(); +// if (tj3Set(handle, TJPARAM_BOTTOMUP, bottomUp) == -1) +// THROW_TJ(); + +// if (precision == 8) { +// // j16XXX hack until I clean up TurboJPEG. +// if ((srcBuf = tj3LoadImage12(handle, argv[1], &w, 1, &h, &pf)) == NULL) +// THROW_TJ(); +// } else if (precision == 12) { +// if ((srcBuf = tj3LoadImage12(handle, argv[1], &w, 1, &h, &pf)) == NULL) +// THROW_TJ(); +// } else { +// // j16XXX hack until I clean up TurboJPEG. +// if ((srcBuf = tj3LoadImage12(handle, argv[1], &w, 1, &h, &pf)) == NULL) +// THROW_TJ(); +// } +// temp = strrchr(argv[1], '.'); +// if (temp != NULL) *temp = '\0'; +// } + +// if (quiet == 1 && !decompOnly) { +// printf("All performance values in Mpixels/sec\n\n"); +// printf("Pixel JPEG JPEG %s %s ", +// doTile ? "Tile " : "Image", doTile ? "Tile " : "Image"); +// if (doYUV) printf("Encode "); +// printf("Comp Comp Decomp "); +// if (doYUV) printf("Decode"); +// printf("\n"); +// printf("Format Format %s Width Height ", +// lossless ? "PSV " : "Qual"); +// if (doYUV) printf("Perf "); +// printf("Perf Ratio Perf "); +// if (doYUV) printf("Perf"); +// printf("\n\n"); +// } + +// if (decompOnly) { +// decompTest(argv[1]); +// printf("\n"); +// goto bailout; +// } +// if (lossless) { +// if (minQual < 1 || minQual > 7 || maxQual < 1 || maxQual > 7) { +// puts("ERROR: PSV must be between 1 and 7."); +// exit(1); +// } +// } else { +// if (minQual < 1 || minQual > 100 || maxQual < 1 || maxQual > 100) { +// puts("ERROR: Quality must be between 1 and 100."); +// exit(1); +// } +// } +// if (subsamp >= 0 && subsamp < TJ_NUMSAMP) { +// for (i = maxQual; i >= minQual; i--) +// fullTest(handle, srcBuf, w, h, subsamp, i, argv[1]); +// printf("\n"); +// } else { +// if (pf != TJPF_CMYK) { +// for (i = maxQual; i >= minQual; i--) +// fullTest(handle, srcBuf, w, h, TJSAMP_GRAY, i, argv[1]); +// printf("\n"); +// } +// for (i = maxQual; i >= minQual; i--) +// fullTest(handle, srcBuf, w, h, TJSAMP_420, i, argv[1]); +// printf("\n"); +// for (i = maxQual; i >= minQual; i--) +// fullTest(handle, srcBuf, w, h, TJSAMP_422, i, argv[1]); +// printf("\n"); +// for (i = maxQual; i >= minQual; i--) +// fullTest(handle, srcBuf, w, h, TJSAMP_444, i, argv[1]); +// printf("\n"); +// } + +// bailout: +// tj3Destroy(handle); +// tj3Free(srcBuf); +// return retval; +// } diff --git a/Sources/TurboJPEG/tjexample.c b/Sources/TurboJPEG/tjexample.c index 230e2e41..f3a57942 100644 --- a/Sources/TurboJPEG/tjexample.c +++ b/Sources/TurboJPEG/tjexample.c @@ -345,9 +345,9 @@ int main(int argc, char **argv) (unsigned char *)malloc(sizeof(unsigned char) * width * height * tjPixelSize[pixelFormat])) == NULL) THROW_UNIX("allocating uncompressed image buffer"); - - if (tj3Decompress8(tjInstance, jpegBuf, jpegSize, imgBuf, 0, - pixelFormat) < 0) + // j16XXX hack until I clean up TurboJPEG. + if (tj3Decompress12(tjInstance, jpegBuf, jpegSize, (short *)imgBuf, 0, + pixelFormat) < 0) THROW_TJ("decompressing JPEG image"); tj3Free(jpegBuf); jpegBuf = NULL; tj3Destroy(tjInstance); tjInstance = NULL; @@ -355,8 +355,8 @@ int main(int argc, char **argv) /* Input image is not a JPEG image. Load it into memory. */ if ((tjInstance = tj3Init(TJINIT_COMPRESS)) == NULL) THROW_TJ("initializing compressor"); - if ((imgBuf = tj3LoadImage8(tjInstance, argv[1], &width, 1, &height, - &pixelFormat)) == NULL) + if ((imgBuf = (unsigned char *)tj3LoadImage12(tjInstance, argv[1], &width, 1, &height, + &pixelFormat)) == NULL) THROW_TJ("loading input image"); if (outSubsamp < 0) { if (pixelFormat == TJPF_GRAY) @@ -388,8 +388,12 @@ int main(int argc, char **argv) THROW_TJ("setting TJPARAM_QUALITY"); if (tj3Set(tjInstance, TJPARAM_FASTDCT, fastDCT) < 0) THROW_TJ("setting TJPARAM_FASTDCT"); - if (tj3Compress8(tjInstance, imgBuf, width, 0, height, pixelFormat, - &jpegBuf, &jpegSize) < 0) + // j16XXX hack until I clean up TurboJPEG. + // if (tj3Compress8(tjInstance, imgBuf, width, 0, height, pixelFormat, + // &jpegBuf, &jpegSize) < 0) + // THROW_TJ("compressing image"); + if (tj3Compress12(tjInstance, (short *)imgBuf, width, 0, height, pixelFormat, + &jpegBuf, &jpegSize) < 0) THROW_TJ("compressing image"); tj3Destroy(tjInstance); tjInstance = NULL; @@ -405,8 +409,8 @@ int main(int argc, char **argv) /* Output image format is not JPEG. Save the uncompressed image directly to disk. */ printf("\n"); - if (tj3SaveImage8(tjInstance, argv[2], imgBuf, width, 0, height, - pixelFormat) < 0) + if (tj3SaveImage12(tjInstance, argv[2], (short *)imgBuf, width, 0, height, + pixelFormat) < 0) THROW_TJ("saving output image"); } diff --git a/Sources/TurboJPEG/tjunittest.c b/Sources/TurboJPEG/tjunittest.c index db4456e0..6c779da0 100644 --- a/Sources/TurboJPEG/tjunittest.c +++ b/Sources/TurboJPEG/tjunittest.c @@ -446,13 +446,14 @@ static void compTest(tjhandle handle, unsigned char **dstBuf, size_t *dstSize, printf("%s %s -> %s Q%d ... ", pfStr, buStrLong, subNameLong[subsamp], jpegQual); if (precision == 8) { - TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, w, 0, h, pf, + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, pf, dstBuf, dstSize)); } else if (precision == 12) { TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, pf, dstBuf, dstSize)); } else { - TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, w, 0, h, + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, pf, dstBuf, dstSize)); } } @@ -537,14 +538,15 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf, printf("%d/%d ... ", sf.num, sf.denom); else printf("... "); if (precision == 8) { - TRY_TJ(handle, tj3Decompress8(handle, jpegBuf, jpegSize, - (unsigned char *)dstBuf, 0, pf)); + TRY_TJ(handle, tj3Decompress12(handle, jpegBuf, jpegSize, + (short *)dstBuf, 0, pf)); } else if (precision == 12) { TRY_TJ(handle, tj3Decompress12(handle, jpegBuf, jpegSize, (short *)dstBuf, 0, pf)); } else { - TRY_TJ(handle, tj3Decompress16(handle, jpegBuf, jpegSize, - (unsigned short *)dstBuf, 0, pf)); + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3Decompress12(handle, jpegBuf, jpegSize, + (short *)dstBuf, 0, pf)); } } @@ -765,13 +767,14 @@ static void bufSizeTest(void) h, TJPF_BGRX, dstBuf, yuvAlign)); } else { if (precision == 8) { - TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, w, 0, - h, TJPF_BGRX, &dstBuf, &dstSize)); + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, + TJPF_BGRX, &dstBuf, &dstSize)); } else if (precision == 12) { TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, TJPF_BGRX, &dstBuf, &dstSize)); } else { - TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, w, + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, w, 0, h, TJPF_BGRX, &dstBuf, &dstSize)); } } @@ -799,13 +802,14 @@ static void bufSizeTest(void) w, TJPF_BGRX, dstBuf, yuvAlign)); } else { if (precision == 8) { - TRY_TJ(handle, tj3Compress8(handle, (unsigned char *)srcBuf, h, 0, - w, TJPF_BGRX, &dstBuf, &dstSize)); + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, h, 0, w, + TJPF_BGRX, &dstBuf, &dstSize)); } else if (precision == 12) { TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, h, 0, w, TJPF_BGRX, &dstBuf, &dstSize)); } else { - TRY_TJ(handle, tj3Compress16(handle, (unsigned short *)srcBuf, h, + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3Compress12(handle, (short *)srcBuf, h, 0, w, TJPF_BGRX, &dstBuf, &dstSize)); } } @@ -982,14 +986,16 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, SNPRINTF(filename, 80, "test_bmp%d_%s_%d_%s_%d.%s", precision, pixFormatStr[pf], align, bottomUp ? "bu" : "td", getpid(), ext); if (precision == 8) { - TRY_TJ(handle, tj3SaveImage8(handle, filename, (unsigned char *)buf, width, - pitch, height, pf)); + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3SaveImage12(handle, filename, (short *)buf, width, + pitch, height, pf)); } else if (precision == 12) { TRY_TJ(handle, tj3SaveImage12(handle, filename, (short *)buf, width, pitch, height, pf)); } else { - TRY_TJ(handle, tj3SaveImage16(handle, filename, (unsigned short *)buf, - width, pitch, height, pf)); + // j16XXX hack until I clean up TurboJPEG. + TRY_TJ(handle, tj3SaveImage12(handle, filename, (short *)buf, width, pitch, + height, pf)); } md5sum = MD5File(filename, md5buf); if (!md5sum) { @@ -1001,15 +1007,16 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, tj3Free(buf); buf = NULL; if (precision == 8) { - if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, &loadHeight, - &pf)) == NULL) + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, + &pf)) == NULL) THROW_TJ(handle); } else if (precision == 12) { if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } else { - if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, &loadHeight, + // j16XXX hack until I clean up TurboJPEG. + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } @@ -1025,15 +1032,16 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, tj3Free(buf); buf = NULL; pf = TJPF_XBGR; if (precision == 8) { - if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, - &loadHeight, &pf)) == NULL) + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, + &loadHeight, &pf)) == NULL) THROW_TJ(handle); } else if (precision == 12) { if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } else { - if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, + // j16XXX hack until I clean up TurboJPEG. + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } @@ -1046,15 +1054,16 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, tj3Free(buf); buf = NULL; pf = TJPF_CMYK; if (precision == 8) { - if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, - &loadHeight, &pf)) == NULL) + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, + &loadHeight, &pf)) == NULL) THROW_TJ(handle); } else if (precision == 12) { if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } else { - if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, + // j16XXX hack until I clean up TurboJPEG. + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pf)) == NULL) THROW_TJ(handle); } @@ -1070,15 +1079,16 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, pf = pixelFormat; pixelFormat = TJPF_UNKNOWN; if (precision == 8) { - if ((buf = tj3LoadImage8(handle, filename, &loadWidth, align, &loadHeight, - &pixelFormat)) == NULL) + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, + &pixelFormat)) == NULL) THROW_TJ(handle); } else if (precision == 12) { if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pixelFormat)) == NULL) THROW_TJ(handle); } else { - if ((buf = tj3LoadImage16(handle, filename, &loadWidth, align, &loadHeight, + // j16XXX hack until I clean up TurboJPEG. + if ((buf = tj3LoadImage12(handle, filename, &loadWidth, align, &loadHeight, &pixelFormat)) == NULL) THROW_TJ(handle); } @@ -1087,7 +1097,7 @@ static int doBmpTest(const char *ext, int width, int align, int height, int pf, pixelFormat != TJPF_BGR) || (pf != TJPF_GRAY && !strcasecmp(ext, "ppm") && pixelFormat != TJPF_RGB)) { - printf("\n tj3LoadImage8() returned unexpected pixel format: %s\n", + printf("\n tj3LoadImage8() [hacked into tj3LoadImage12()] returned unexpected pixel format: %s\n", pixFormatStr[pixelFormat]); retval = -1; } diff --git a/Sources/TurboJPEG/turbojpeg-jni.c b/Sources/TurboJPEG/turbojpeg-jni.c index 168bd0bc..61c94eff 100644 --- a/Sources/TurboJPEG/turbojpeg-jni.c +++ b/Sources/TurboJPEG/turbojpeg-jni.c @@ -246,9 +246,9 @@ static jint TJCompressor_compress BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (precision == 8) { - if (tj3Compress8(handle, &((unsigned char *)srcBuf)[y * actualPitch + - x * tjPixelSize[pf]], - width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) { + if (tj3Compress12(handle, &((short *)srcBuf)[y * actualPitch + + x * tjPixelSize[pf]], + width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) { SAFE_RELEASE(dst, jpegBuf); SAFE_RELEASE(src, srcBuf); THROW_TJ(); @@ -262,7 +262,8 @@ static jint TJCompressor_compress THROW_TJ(); } } else { - if (tj3Compress16(handle, &((unsigned short *)srcBuf)[y * actualPitch + + // j16XXX hack until I clean up TurboJPEG. + if (tj3Compress12(handle, &((short *)srcBuf)[y * actualPitch + x * tjPixelSize[pf]], width, pitch, height, pf, &jpegBuf, &jpegSize) == -1) { SAFE_RELEASE(dst, jpegBuf); @@ -750,9 +751,9 @@ static void TJDecompressor_decompress BAILIF0NOEC(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0)); if (precision == 8) { - if (tj3Decompress8(handle, jpegBuf, (size_t)jpegSize, - &((unsigned char *)dstBuf)[y * actualPitch + - x * tjPixelSize[pf]], + if (tj3Decompress12(handle, jpegBuf, (size_t)jpegSize, + &((short *)dstBuf)[y * actualPitch + + x * tjPixelSize[pf]], pitch, pf) == -1) { SAFE_RELEASE(dst, dstBuf); SAFE_RELEASE(src, jpegBuf); @@ -768,8 +769,9 @@ static void TJDecompressor_decompress THROW_TJ(); } } else { - if (tj3Decompress16(handle, jpegBuf, (size_t)jpegSize, - &((unsigned short *)dstBuf)[y * actualPitch + + // j16XXX hack until I clean up TurboJPEG. + if (tj3Decompress12(handle, jpegBuf, (size_t)jpegSize, + &((short *)dstBuf)[y * actualPitch + x * tjPixelSize[pf]], pitch, pf) == -1) { SAFE_RELEASE(dst, dstBuf); @@ -1300,15 +1302,16 @@ JNIEXPORT jobject JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_loadImage BAILIF0(filename = (*env)->GetStringUTFChars(env, jfilename, &isCopy)); if (precision == 8) { - if ((dstBuf = tj3LoadImage8(handle, filename, &width, align, &height, - &pixelFormat)) == NULL) + if ((dstBuf = tj3LoadImage12(handle, filename, &width, align, &height, + &pixelFormat)) == NULL) THROW_TJ(); } else if (precision == 12) { if ((dstBuf = tj3LoadImage12(handle, filename, &width, align, &height, &pixelFormat)) == NULL) THROW_TJ(); } else { - if ((dstBuf = tj3LoadImage16(handle, filename, &width, align, &height, + // j16XXX hack until I clean up TurboJPEG. + if ((dstBuf = tj3LoadImage12(handle, filename, &width, align, &height, &pixelFormat)) == NULL) THROW_TJ(); } @@ -1381,15 +1384,16 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_saveImage BAILIF0(filename = (*env)->GetStringUTFChars(env, jfilename, &isCopy)); if (precision == 8) { - if (tj3SaveImage8(handle, filename, srcBuf, width, pitch, height, - pixelFormat) == -1) + if (tj3SaveImage12(handle, filename, srcBuf, width, pitch, height, + pixelFormat) == -1) THROW_TJ(); } else if (precision == 12) { if (tj3SaveImage12(handle, filename, srcBuf, width, pitch, height, pixelFormat) == -1) THROW_TJ(); } else { - if (tj3SaveImage16(handle, filename, srcBuf, width, pitch, height, + // j16XXX hack until I clean up TurboJPEG. + if (tj3SaveImage12(handle, filename, srcBuf, width, pitch, height, pixelFormat) == -1) THROW_TJ(); } diff --git a/Sources/TurboJPEG/turbojpeg.c b/Sources/TurboJPEG/turbojpeg.c index 91b1552d..8f864df6 100644 --- a/Sources/TurboJPEG/turbojpeg.c +++ b/Sources/TurboJPEG/turbojpeg.c @@ -1134,1034 +1134,22 @@ DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride, /* tj3Compress*() is implemented in turbojpeg-mp.c */ -#undef BITS_IN_JSAMPLE -#define BITS_IN_JSAMPLE 8 - -/* TurboJPEG API functions that must be compiled for multiple data - precisions */ - -#if BITS_IN_JSAMPLE == 8 -#define _JSAMPLE JSAMPLE -#define _JSAMPROW JSAMPROW -#define _buffer buffer -#define _jinit_read_ppm jinit_read_ppm -#define _jinit_write_ppm jinit_write_ppm -#define _jpeg_crop_scanline jpeg_crop_scanline -#define _jpeg_read_scanlines jpeg_read_scanlines -#define _jpeg_skip_scanlines jpeg_skip_scanlines -#define _jpeg_write_scanlines jpeg_write_scanlines -#elif BITS_IN_JSAMPLE == 12 -#define _JSAMPLE J12SAMPLE -#define _JSAMPROW J12SAMPROW -#define _buffer buffer12 -#define _jinit_read_ppm j12init_read_ppm -#define _jinit_write_ppm j12init_write_ppm -#define _jpeg_crop_scanline jpeg12_crop_scanline -#define _jpeg_read_scanlines jpeg12_read_scanlines -#define _jpeg_skip_scanlines jpeg12_skip_scanlines -#define _jpeg_write_scanlines jpeg12_write_scanlines -#elif BITS_IN_JSAMPLE == 16 -#define _JSAMPLE J16SAMPLE -#define _JSAMPROW J16SAMPROW -#define _buffer buffer16 -#define _jinit_read_ppm j16init_read_ppm -#define _jinit_write_ppm j16init_write_ppm -#define _jpeg_read_scanlines jpeg16_read_scanlines -#define _jpeg_write_scanlines jpeg16_write_scanlines -#endif - -#define _GET_NAME(name, suffix) name##suffix -#define GET_NAME(name, suffix) _GET_NAME(name, suffix) -#define _GET_STRING(name, suffix) #name #suffix -#define GET_STRING(name, suffix) _GET_STRING(name, suffix) - - -/******************************** Compressor *********************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3Compress, BITS_IN_JSAMPLE) - (tjhandle handle, const _JSAMPLE *srcBuf, int width, int pitch, int height, - int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize) -{ - static const char FUNCTION_NAME[] = GET_STRING(tj3Compress, BITS_IN_JSAMPLE); - int i, retval = 0; - boolean alloc = TRUE; - _JSAMPROW *row_pointer = NULL; - - GET_CINSTANCE(handle) - if ((this->init & COMPRESS) == 0) - THROW("Instance has not been initialized for compression"); - - if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL || - jpegSize == NULL) - THROW("Invalid argument"); - - if (!this->lossless && this->quality == -1) - THROW("TJPARAM_QUALITY must be specified"); - if (!this->lossless && this->subsamp == TJSAMP_UNKNOWN) - THROW("TJPARAM_SUBSAMP must be specified"); - - if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; - - if ((row_pointer = (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * height)) == NULL) - THROW("Memory allocation failure"); - - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - cinfo->image_width = width; - cinfo->image_height = height; - cinfo->data_precision = BITS_IN_JSAMPLE; - - setCompDefaults(this, pixelFormat); - if (this->noRealloc) { - alloc = FALSE; - *jpegSize = tj3JPEGBufSize(width, height, this->subsamp); - } - jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); - - jpeg_start_compress(cinfo, TRUE); - for (i = 0; i < height; i++) { - if (this->bottomUp) - row_pointer[i] = (_JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch]; - else - row_pointer[i] = (_JSAMPROW)&srcBuf[i * (size_t)pitch]; - } - while (cinfo->next_scanline < cinfo->image_height) - _jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], - cinfo->image_height - cinfo->next_scanline); - jpeg_finish_compress(cinfo); - -bailout: - if (cinfo->global_state > CSTATE_START) { - if (alloc) (*cinfo->dest->term_destination) (cinfo); - jpeg_abort_compress(cinfo); - } - free(row_pointer); - if (this->jerr.warning) retval = -1; - return retval; -} - - -/******************************* Decompressor ********************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3Decompress, BITS_IN_JSAMPLE) - (tjhandle handle, const unsigned char *jpegBuf, size_t jpegSize, - _JSAMPLE *dstBuf, int pitch, int pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3Decompress, BITS_IN_JSAMPLE); - _JSAMPROW *row_pointer = NULL; - int croppedHeight, i, retval = 0; -#if BITS_IN_JSAMPLE != 16 - int scaledWidth; -#endif - struct my_progress_mgr progress; - - GET_DINSTANCE(handle); - if ((this->init & DECOMPRESS) == 0) - THROW("Instance has not been initialized for decompression"); - - if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || pitch < 0 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - - if (this->scanLimit) { - memset(&progress, 0, sizeof(struct my_progress_mgr)); - progress.pub.progress_monitor = my_progress_monitor; - progress.this = this; - dinfo->progress = &progress.pub; - } else - dinfo->progress = NULL; - - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - if (dinfo->global_state <= DSTATE_START) { - jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); - jpeg_read_header(dinfo, TRUE); - } - setDecompParameters(this); - this->dinfo.out_color_space = pf2cs[pixelFormat]; -#if BITS_IN_JSAMPLE != 16 - scaledWidth = TJSCALED(dinfo->image_width, this->scalingFactor); -#endif - dinfo->do_fancy_upsampling = !this->fastUpsample; - this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW; - - dinfo->scale_num = this->scalingFactor.num; - dinfo->scale_denom = this->scalingFactor.denom; - - jpeg_start_decompress(dinfo); - -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.x != 0 || - (this->croppingRegion.w != 0 && this->croppingRegion.w != scaledWidth)) { - JDIMENSION crop_x = this->croppingRegion.x; - JDIMENSION crop_w = this->croppingRegion.w; - - _jpeg_crop_scanline(dinfo, &crop_x, &crop_w); - if ((int)crop_x != this->croppingRegion.x) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region left boundary", - this->croppingRegion.x, (int)crop_x); - if ((int)crop_w != this->croppingRegion.w) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region width", - this->croppingRegion.w, (int)crop_w); - } -#endif - - if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat]; - - croppedHeight = dinfo->output_height; -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0) - croppedHeight = this->croppingRegion.h; -#endif - if ((row_pointer = - (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * croppedHeight)) == NULL) - THROW("Memory allocation failure"); - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - for (i = 0; i < (int)croppedHeight; i++) { - if (this->bottomUp) - row_pointer[i] = &dstBuf[(croppedHeight - i - 1) * (size_t)pitch]; - else - row_pointer[i] = &dstBuf[i * (size_t)pitch]; - } - -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0) { - if (this->croppingRegion.y != 0) { - JDIMENSION lines = _jpeg_skip_scanlines(dinfo, this->croppingRegion.y); - - if ((int)lines != this->croppingRegion.y) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region upper boundary", - this->croppingRegion.y, (int)lines); - } - while ((int)dinfo->output_scanline < - this->croppingRegion.y + this->croppingRegion.h) - _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline - - this->croppingRegion.y], - this->croppingRegion.y + this->croppingRegion.h - - dinfo->output_scanline); - if (this->croppingRegion.y + this->croppingRegion.h != - (int)dinfo->output_height) { - JDIMENSION lines = _jpeg_skip_scanlines(dinfo, dinfo->output_height - - this->croppingRegion.y - - this->croppingRegion.h); - - if (lines != dinfo->output_height - this->croppingRegion.y - - this->croppingRegion.h) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region lower boundary", - this->croppingRegion.y + this->croppingRegion.h, - (int)(dinfo->output_height - lines)); - } - } else -#endif - { - while (dinfo->output_scanline < dinfo->output_height) - _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], - dinfo->output_height - dinfo->output_scanline); - } - jpeg_finish_decompress(dinfo); - -bailout: - if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); - free(row_pointer); - if (this->jerr.warning) retval = -1; - return retval; -} - - -/*************************** Packed-Pixel Image I/O **************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) - (tjhandle handle, const char *filename, int *width, int align, int *height, - int *pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3LoadImage, BITS_IN_JSAMPLE); - -#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) - - int retval = 0, tempc; - size_t pitch; - tjhandle handle2 = NULL; - tjinstance *this2; - j_compress_ptr cinfo = NULL; - cjpeg_source_ptr src; - _JSAMPLE *dstBuf = NULL; - FILE *file = NULL; - boolean invert; - - GET_TJINSTANCE(handle, NULL) - - if (!filename || !width || align < 1 || !height || !pixelFormat || - *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - if ((align & (align - 1)) != 0) - THROW("Alignment must be a power of 2"); - - /* The instance handle passed to this function is used only for parameter - retrieval. Create a new temporary instance to avoid interfering with the - libjpeg state of the primary instance. */ - if ((handle2 = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL; - this2 = (tjinstance *)handle2; - cinfo = &this2->cinfo; - -#ifdef _MSC_VER - if (fopen_s(&file, filename, "rb") || file == NULL) -#else - if ((file = fopen(filename, "rb")) == NULL) -#endif - THROW_UNIX("Cannot open input file"); - - if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF) - THROW_UNIX("Could not read input file") - else if (tempc == EOF) - THROW("Input file contains no data"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - cinfo->data_precision = BITS_IN_JSAMPLE; - if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN; - else cinfo->in_color_space = pf2cs[*pixelFormat]; - if (tempc == 'B') { - if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL) - THROW("Could not initialize bitmap loader"); - invert = !this->bottomUp; - } else if (tempc == 'P') { - if ((src = _jinit_read_ppm(cinfo)) == NULL) - THROW("Could not initialize PPM loader"); - invert = this->bottomUp; - } else - THROW("Unsupported file type"); - - src->input_file = file; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Refuse to load images larger than 1 Megapixel when fuzzing. */ - src->max_pixels = this->maxPixels; -#endif - (*src->start_input) (cinfo, src); - if (tempc == 'B') { - if (cinfo->X_density && cinfo->Y_density) { - this->xDensity = cinfo->X_density; - this->yDensity = cinfo->Y_density; - this->densityUnits = cinfo->density_unit; - } - } - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo); - - *width = cinfo->image_width; *height = cinfo->image_height; - *pixelFormat = cs2pf[cinfo->in_color_space]; - - pitch = PAD((*width) * tjPixelSize[*pixelFormat], align); - if ((unsigned long long)pitch * (unsigned long long)(*height) > - (unsigned long long)((size_t)-1) || - (dstBuf = (_JSAMPLE *)malloc(pitch * (*height) * - sizeof(_JSAMPLE))) == NULL) - THROW("Memory allocation failure"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - while (cinfo->next_scanline < cinfo->image_height) { - int i, nlines = (*src->get_pixel_rows) (cinfo, src); - - for (i = 0; i < nlines; i++) { - _JSAMPLE *dstptr; - int row; - - row = cinfo->next_scanline + i; - if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch]; - else dstptr = &dstBuf[row * pitch]; - memcpy(dstptr, src->_buffer[i], - (*width) * tjPixelSize[*pixelFormat] * sizeof(_JSAMPLE)); - } - cinfo->next_scanline += nlines; - } - - (*src->finish_input) (cinfo, src); - -bailout: - tj3Destroy(handle2); - if (file) fclose(file); - if (retval < 0) { free(dstBuf); dstBuf = NULL; } - return dstBuf; - -#else /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */ - - static const char ERROR_MSG[] = - "16-bit data precision requires lossless JPEG,\n" - "which was disabled at build time."; - _JSAMPLE *retval = NULL; - - GET_TJINSTANCE(handle, NULL) - SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, - ERROR_MSG); - this->isInstanceError = TRUE; THROWG(ERROR_MSG, NULL) - -bailout: - return retval; - -#endif -} - - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE) - (tjhandle handle, const char *filename, const _JSAMPLE *buffer, int width, - int pitch, int height, int pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3SaveImage, BITS_IN_JSAMPLE); - int retval = 0; - -#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) - - tjhandle handle2 = NULL; - tjinstance *this2; - j_decompress_ptr dinfo = NULL; - djpeg_dest_ptr dst; - FILE *file = NULL; - char *ptr = NULL; - boolean invert; - - GET_TJINSTANCE(handle, -1) - - if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - - /* The instance handle passed to this function is used only for parameter - retrieval. Create a new temporary instance to avoid interfering with the - libjpeg state of the primary instance. */ - if ((handle2 = tj3Init(TJINIT_DECOMPRESS)) == NULL) - return -1; - this2 = (tjinstance *)handle2; - dinfo = &this2->dinfo; - -#ifdef _MSC_VER - if (fopen_s(&file, filename, "wb") || file == NULL) -#else - if ((file = fopen(filename, "wb")) == NULL) -#endif - THROW_UNIX("Cannot open output file"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - this2->dinfo.out_color_space = pf2cs[pixelFormat]; - dinfo->image_width = width; dinfo->image_height = height; - dinfo->global_state = DSTATE_READY; - dinfo->scale_num = dinfo->scale_denom = 1; - dinfo->data_precision = BITS_IN_JSAMPLE; - - ptr = strrchr(filename, '.'); - if (ptr && !strcasecmp(ptr, ".bmp")) { - if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL) - THROW("Could not initialize bitmap writer"); - invert = !this->bottomUp; - dinfo->X_density = (UINT16)this->xDensity; - dinfo->Y_density = (UINT16)this->yDensity; - dinfo->density_unit = (UINT8)this->densityUnits; - } else { - if ((dst = _jinit_write_ppm(dinfo)) == NULL) - THROW("Could not initialize PPM writer"); - invert = this->bottomUp; - } - - dst->output_file = file; - (*dst->start_output) (dinfo, dst); - (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo); - - if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; - - while (dinfo->output_scanline < dinfo->output_height) { - _JSAMPLE *rowptr; - - if (invert) - rowptr = - (_JSAMPLE *)&buffer[(height - dinfo->output_scanline - 1) * pitch]; - else - rowptr = (_JSAMPLE *)&buffer[dinfo->output_scanline * pitch]; - memcpy(dst->_buffer[0], rowptr, - width * tjPixelSize[pixelFormat] * sizeof(_JSAMPLE)); - (*dst->put_pixel_rows) (dinfo, dst, 1); - dinfo->output_scanline++; - } - - (*dst->finish_output) (dinfo, dst); - -bailout: - tj3Destroy(handle2); - if (file) fclose(file); - return retval; - -#else /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */ - - GET_TJINSTANCE(handle, -1) - THROW("16-bit data precision requires lossless JPEG,\n" - "which was disabled at build time.") -bailout: - return retval; - -#endif -} - - -#undef _JSAMPLE -#undef _JSAMPROW -#undef _buffer -#undef _jinit_read_ppm -#undef _jinit_write_ppm -#undef _jpeg_crop_scanline -#undef _jpeg_read_scanlines -#undef _jpeg_skip_scanlines -#undef _jpeg_write_scanlines - -#undef BITS_IN_JSAMPLE -#define BITS_IN_JSAMPLE 12 - -/* TurboJPEG API functions that must be compiled for multiple data - precisions */ - -#if BITS_IN_JSAMPLE == 8 -#define _JSAMPLE JSAMPLE -#define _JSAMPROW JSAMPROW -#define _buffer buffer -#define _jinit_read_ppm jinit_read_ppm -#define _jinit_write_ppm jinit_write_ppm -#define _jpeg_crop_scanline jpeg_crop_scanline -#define _jpeg_read_scanlines jpeg_read_scanlines -#define _jpeg_skip_scanlines jpeg_skip_scanlines -#define _jpeg_write_scanlines jpeg_write_scanlines -#elif BITS_IN_JSAMPLE == 12 -#define _JSAMPLE J12SAMPLE -#define _JSAMPROW J12SAMPROW -#define _buffer buffer12 -#define _jinit_read_ppm j12init_read_ppm -#define _jinit_write_ppm j12init_write_ppm -#define _jpeg_crop_scanline jpeg12_crop_scanline -#define _jpeg_read_scanlines jpeg12_read_scanlines -#define _jpeg_skip_scanlines jpeg12_skip_scanlines -#define _jpeg_write_scanlines jpeg12_write_scanlines -#elif BITS_IN_JSAMPLE == 16 -#define _JSAMPLE J16SAMPLE -#define _JSAMPROW J16SAMPROW -#define _buffer buffer16 -#define _jinit_read_ppm j16init_read_ppm -#define _jinit_write_ppm j16init_write_ppm -#define _jpeg_read_scanlines jpeg16_read_scanlines -#define _jpeg_write_scanlines jpeg16_write_scanlines -#endif - -#define _GET_NAME(name, suffix) name##suffix -#define GET_NAME(name, suffix) _GET_NAME(name, suffix) -#define _GET_STRING(name, suffix) #name #suffix -#define GET_STRING(name, suffix) _GET_STRING(name, suffix) - - -/******************************** Compressor *********************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3Compress, BITS_IN_JSAMPLE) - (tjhandle handle, const _JSAMPLE *srcBuf, int width, int pitch, int height, - int pixelFormat, unsigned char **jpegBuf, size_t *jpegSize) -{ - static const char FUNCTION_NAME[] = GET_STRING(tj3Compress, BITS_IN_JSAMPLE); - int i, retval = 0; - boolean alloc = TRUE; - _JSAMPROW *row_pointer = NULL; - - GET_CINSTANCE(handle) - if ((this->init & COMPRESS) == 0) - THROW("Instance has not been initialized for compression"); - - if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL || - jpegSize == NULL) - THROW("Invalid argument"); - - if (!this->lossless && this->quality == -1) - THROW("TJPARAM_QUALITY must be specified"); - if (!this->lossless && this->subsamp == TJSAMP_UNKNOWN) - THROW("TJPARAM_SUBSAMP must be specified"); - - if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; - - if ((row_pointer = (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * height)) == NULL) - THROW("Memory allocation failure"); - - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - cinfo->image_width = width; - cinfo->image_height = height; - cinfo->data_precision = BITS_IN_JSAMPLE; - - setCompDefaults(this, pixelFormat); - if (this->noRealloc) { - alloc = FALSE; - *jpegSize = tj3JPEGBufSize(width, height, this->subsamp); - } - jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); - - jpeg_start_compress(cinfo, TRUE); - for (i = 0; i < height; i++) { - if (this->bottomUp) - row_pointer[i] = (_JSAMPROW)&srcBuf[(height - i - 1) * (size_t)pitch]; - else - row_pointer[i] = (_JSAMPROW)&srcBuf[i * (size_t)pitch]; - } - while (cinfo->next_scanline < cinfo->image_height) - _jpeg_write_scanlines(cinfo, &row_pointer[cinfo->next_scanline], - cinfo->image_height - cinfo->next_scanline); - jpeg_finish_compress(cinfo); - -bailout: - if (cinfo->global_state > CSTATE_START) { - if (alloc) (*cinfo->dest->term_destination) (cinfo); - jpeg_abort_compress(cinfo); - } - free(row_pointer); - if (this->jerr.warning) retval = -1; - return retval; -} - - -/******************************* Decompressor ********************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3Decompress, BITS_IN_JSAMPLE) - (tjhandle handle, const unsigned char *jpegBuf, size_t jpegSize, - _JSAMPLE *dstBuf, int pitch, int pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3Decompress, BITS_IN_JSAMPLE); - _JSAMPROW *row_pointer = NULL; - int croppedHeight, i, retval = 0; -#if BITS_IN_JSAMPLE != 16 - int scaledWidth; -#endif - struct my_progress_mgr progress; - - GET_DINSTANCE(handle); - if ((this->init & DECOMPRESS) == 0) - THROW("Instance has not been initialized for decompression"); - - if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || pitch < 0 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - - if (this->scanLimit) { - memset(&progress, 0, sizeof(struct my_progress_mgr)); - progress.pub.progress_monitor = my_progress_monitor; - progress.this = this; - dinfo->progress = &progress.pub; - } else - dinfo->progress = NULL; - - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - if (dinfo->global_state <= DSTATE_START) { - jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); - jpeg_read_header(dinfo, TRUE); - } - setDecompParameters(this); - this->dinfo.out_color_space = pf2cs[pixelFormat]; -#if BITS_IN_JSAMPLE != 16 - scaledWidth = TJSCALED(dinfo->image_width, this->scalingFactor); -#endif - dinfo->do_fancy_upsampling = !this->fastUpsample; - this->dinfo.dct_method = this->fastDCT ? JDCT_FASTEST : JDCT_ISLOW; - - dinfo->scale_num = this->scalingFactor.num; - dinfo->scale_denom = this->scalingFactor.denom; - - jpeg_start_decompress(dinfo); - -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.x != 0 || - (this->croppingRegion.w != 0 && this->croppingRegion.w != scaledWidth)) { - JDIMENSION crop_x = this->croppingRegion.x; - JDIMENSION crop_w = this->croppingRegion.w; - - _jpeg_crop_scanline(dinfo, &crop_x, &crop_w); - if ((int)crop_x != this->croppingRegion.x) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region left boundary", - this->croppingRegion.x, (int)crop_x); - if ((int)crop_w != this->croppingRegion.w) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region width", - this->croppingRegion.w, (int)crop_w); - } -#endif - - if (pitch == 0) pitch = dinfo->output_width * tjPixelSize[pixelFormat]; - - croppedHeight = dinfo->output_height; -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0) - croppedHeight = this->croppingRegion.h; -#endif - if ((row_pointer = - (_JSAMPROW *)malloc(sizeof(_JSAMPROW) * croppedHeight)) == NULL) - THROW("Memory allocation failure"); - if (setjmp(this->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - for (i = 0; i < (int)croppedHeight; i++) { - if (this->bottomUp) - row_pointer[i] = &dstBuf[(croppedHeight - i - 1) * (size_t)pitch]; - else - row_pointer[i] = &dstBuf[i * (size_t)pitch]; - } - -#if BITS_IN_JSAMPLE != 16 - if (this->croppingRegion.y != 0 || this->croppingRegion.h != 0) { - if (this->croppingRegion.y != 0) { - JDIMENSION lines = _jpeg_skip_scanlines(dinfo, this->croppingRegion.y); - - if ((int)lines != this->croppingRegion.y) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region upper boundary", - this->croppingRegion.y, (int)lines); - } - while ((int)dinfo->output_scanline < - this->croppingRegion.y + this->croppingRegion.h) - _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline - - this->croppingRegion.y], - this->croppingRegion.y + this->croppingRegion.h - - dinfo->output_scanline); - if (this->croppingRegion.y + this->croppingRegion.h != - (int)dinfo->output_height) { - JDIMENSION lines = _jpeg_skip_scanlines(dinfo, dinfo->output_height - - this->croppingRegion.y - - this->croppingRegion.h); - - if (lines != dinfo->output_height - this->croppingRegion.y - - this->croppingRegion.h) - THROWI("Unexplained mismatch between specified (%d) and\n" - "actual (%d) cropping region lower boundary", - this->croppingRegion.y + this->croppingRegion.h, - (int)(dinfo->output_height - lines)); - } - } else -#endif - { - while (dinfo->output_scanline < dinfo->output_height) - _jpeg_read_scanlines(dinfo, &row_pointer[dinfo->output_scanline], - dinfo->output_height - dinfo->output_scanline); - } - jpeg_finish_decompress(dinfo); - -bailout: - if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); - free(row_pointer); - if (this->jerr.warning) retval = -1; - return retval; -} - - -/*************************** Packed-Pixel Image I/O **************************/ - -/* TurboJPEG 3+ */ -DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) - (tjhandle handle, const char *filename, int *width, int align, int *height, - int *pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3LoadImage, BITS_IN_JSAMPLE); - -#if BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) - - int retval = 0, tempc; - size_t pitch; - tjhandle handle2 = NULL; - tjinstance *this2; - j_compress_ptr cinfo = NULL; - cjpeg_source_ptr src; - _JSAMPLE *dstBuf = NULL; - FILE *file = NULL; - boolean invert; - - GET_TJINSTANCE(handle, NULL) - - if (!filename || !width || align < 1 || !height || !pixelFormat || - *pixelFormat < TJPF_UNKNOWN || *pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - if ((align & (align - 1)) != 0) - THROW("Alignment must be a power of 2"); - - /* The instance handle passed to this function is used only for parameter - retrieval. Create a new temporary instance to avoid interfering with the - libjpeg state of the primary instance. */ - if ((handle2 = tj3Init(TJINIT_COMPRESS)) == NULL) return NULL; - this2 = (tjinstance *)handle2; - cinfo = &this2->cinfo; - -#ifdef _MSC_VER - if (fopen_s(&file, filename, "rb") || file == NULL) -#else - if ((file = fopen(filename, "rb")) == NULL) -#endif - THROW_UNIX("Cannot open input file"); - - if ((tempc = getc(file)) < 0 || ungetc(tempc, file) == EOF) - THROW_UNIX("Could not read input file") - else if (tempc == EOF) - THROW("Input file contains no data"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - cinfo->data_precision = BITS_IN_JSAMPLE; - if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN; - else cinfo->in_color_space = pf2cs[*pixelFormat]; - if (tempc == 'B') { - if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL) - THROW("Could not initialize bitmap loader"); - invert = !this->bottomUp; - } else if (tempc == 'P') { - if ((src = _jinit_read_ppm(cinfo)) == NULL) - THROW("Could not initialize PPM loader"); - invert = this->bottomUp; - } else - THROW("Unsupported file type"); - - src->input_file = file; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Refuse to load images larger than 1 Megapixel when fuzzing. */ - src->max_pixels = this->maxPixels; -#endif - (*src->start_input) (cinfo, src); - if (tempc == 'B') { - if (cinfo->X_density && cinfo->Y_density) { - this->xDensity = cinfo->X_density; - this->yDensity = cinfo->Y_density; - this->densityUnits = cinfo->density_unit; - } - } - (*cinfo->mem->realize_virt_arrays) ((j_common_ptr)cinfo); - - *width = cinfo->image_width; *height = cinfo->image_height; - *pixelFormat = cs2pf[cinfo->in_color_space]; - - pitch = PAD((*width) * tjPixelSize[*pixelFormat], align); - if ((unsigned long long)pitch * (unsigned long long)(*height) > - (unsigned long long)((size_t)-1) || - (dstBuf = (_JSAMPLE *)malloc(pitch * (*height) * - sizeof(_JSAMPLE))) == NULL) - THROW("Memory allocation failure"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - while (cinfo->next_scanline < cinfo->image_height) { - int i, nlines = (*src->get_pixel_rows) (cinfo, src); - - for (i = 0; i < nlines; i++) { - _JSAMPLE *dstptr; - int row; - - row = cinfo->next_scanline + i; - if (invert) dstptr = &dstBuf[((*height) - row - 1) * pitch]; - else dstptr = &dstBuf[row * pitch]; - memcpy(dstptr, src->_buffer[i], - (*width) * tjPixelSize[*pixelFormat] * sizeof(_JSAMPLE)); - } - cinfo->next_scanline += nlines; - } - - (*src->finish_input) (cinfo, src); - -bailout: - tj3Destroy(handle2); - if (file) fclose(file); - if (retval < 0) { free(dstBuf); dstBuf = NULL; } - return dstBuf; - -#else /* BITS_IN_JSAMPLE != 16 || defined(C_LOSSLESS_SUPPORTED) */ - - static const char ERROR_MSG[] = - "16-bit data precision requires lossless JPEG,\n" - "which was disabled at build time."; - _JSAMPLE *retval = NULL; - - GET_TJINSTANCE(handle, NULL) - SNPRINTF(this->errStr, JMSG_LENGTH_MAX, "%s(): %s", FUNCTION_NAME, - ERROR_MSG); - this->isInstanceError = TRUE; THROWG(ERROR_MSG, NULL) - -bailout: - return retval; - -#endif -} - - -/* TurboJPEG 3+ */ -DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE) - (tjhandle handle, const char *filename, const _JSAMPLE *buffer, int width, - int pitch, int height, int pixelFormat) -{ - static const char FUNCTION_NAME[] = - GET_STRING(tj3SaveImage, BITS_IN_JSAMPLE); - int retval = 0; - -#if BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) - - tjhandle handle2 = NULL; - tjinstance *this2; - j_decompress_ptr dinfo = NULL; - djpeg_dest_ptr dst; - FILE *file = NULL; - char *ptr = NULL; - boolean invert; - - GET_TJINSTANCE(handle, -1) - - if (!filename || !buffer || width < 1 || pitch < 0 || height < 1 || - pixelFormat < 0 || pixelFormat >= TJ_NUMPF) - THROW("Invalid argument"); - - /* The instance handle passed to this function is used only for parameter - retrieval. Create a new temporary instance to avoid interfering with the - libjpeg state of the primary instance. */ - if ((handle2 = tj3Init(TJINIT_DECOMPRESS)) == NULL) - return -1; - this2 = (tjinstance *)handle2; - dinfo = &this2->dinfo; - -#ifdef _MSC_VER - if (fopen_s(&file, filename, "wb") || file == NULL) -#else - if ((file = fopen(filename, "wb")) == NULL) -#endif - THROW_UNIX("Cannot open output file"); - - if (setjmp(this2->jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. */ - retval = -1; goto bailout; - } - - this2->dinfo.out_color_space = pf2cs[pixelFormat]; - dinfo->image_width = width; dinfo->image_height = height; - dinfo->global_state = DSTATE_READY; - dinfo->scale_num = dinfo->scale_denom = 1; - dinfo->data_precision = BITS_IN_JSAMPLE; - - ptr = strrchr(filename, '.'); - if (ptr && !strcasecmp(ptr, ".bmp")) { - if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL) - THROW("Could not initialize bitmap writer"); - invert = !this->bottomUp; - dinfo->X_density = (UINT16)this->xDensity; - dinfo->Y_density = (UINT16)this->yDensity; - dinfo->density_unit = (UINT8)this->densityUnits; - } else { - if ((dst = _jinit_write_ppm(dinfo)) == NULL) - THROW("Could not initialize PPM writer"); - invert = this->bottomUp; - } - - dst->output_file = file; - (*dst->start_output) (dinfo, dst); - (*dinfo->mem->realize_virt_arrays) ((j_common_ptr)dinfo); - - if (pitch == 0) pitch = width * tjPixelSize[pixelFormat]; - - while (dinfo->output_scanline < dinfo->output_height) { - _JSAMPLE *rowptr; - - if (invert) - rowptr = - (_JSAMPLE *)&buffer[(height - dinfo->output_scanline - 1) * pitch]; - else - rowptr = (_JSAMPLE *)&buffer[dinfo->output_scanline * pitch]; - memcpy(dst->_buffer[0], rowptr, - width * tjPixelSize[pixelFormat] * sizeof(_JSAMPLE)); - (*dst->put_pixel_rows) (dinfo, dst, 1); - dinfo->output_scanline++; - } - - (*dst->finish_output) (dinfo, dst); - -bailout: - tj3Destroy(handle2); - if (file) fclose(file); - return retval; - -#else /* BITS_IN_JSAMPLE != 16 || defined(D_LOSSLESS_SUPPORTED) */ - - GET_TJINSTANCE(handle, -1) - THROW("16-bit data precision requires lossless JPEG,\n" - "which was disabled at build time.") -bailout: - return retval; - -#endif -} - - -#undef _JSAMPLE -#undef _JSAMPROW -#undef _buffer -#undef _jinit_read_ppm -#undef _jinit_write_ppm -#undef _jpeg_crop_scanline -#undef _jpeg_read_scanlines -#undef _jpeg_skip_scanlines -#undef _jpeg_write_scanlines - -#undef BITS_IN_JSAMPLE -#define BITS_IN_JSAMPLE 16 +#define BITS_IN_JSAMPLE 12 /* TurboJPEG API functions that must be compiled for multiple data precisions */ #if BITS_IN_JSAMPLE == 8 -#define _JSAMPLE JSAMPLE -#define _JSAMPROW JSAMPROW -#define _buffer buffer -#define _jinit_read_ppm jinit_read_ppm -#define _jinit_write_ppm jinit_write_ppm -#define _jpeg_crop_scanline jpeg_crop_scanline -#define _jpeg_read_scanlines jpeg_read_scanlines -#define _jpeg_skip_scanlines jpeg_skip_scanlines -#define _jpeg_write_scanlines jpeg_write_scanlines +// j16XXX hack until I clean up TurboJPEG. +#define _JSAMPLE J12SAMPLE +#define _JSAMPROW J12SAMPROW +#define _buffer buffer12 +#define _jinit_read_ppm j12init_read_ppm +#define _jinit_write_ppm j12init_write_ppm +#define _jpeg_crop_scanline jpeg12_crop_scanline +#define _jpeg_read_scanlines jpeg12_read_scanlines +#define _jpeg_skip_scanlines jpeg12_skip_scanlines +#define _jpeg_write_scanlines jpeg12_write_scanlines #elif BITS_IN_JSAMPLE == 12 #define _JSAMPLE J12SAMPLE #define _JSAMPROW J12SAMPROW @@ -2173,13 +1161,14 @@ DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE) #define _jpeg_skip_scanlines jpeg12_skip_scanlines #define _jpeg_write_scanlines jpeg12_write_scanlines #elif BITS_IN_JSAMPLE == 16 -#define _JSAMPLE J16SAMPLE -#define _JSAMPROW J16SAMPROW -#define _buffer buffer16 -#define _jinit_read_ppm j16init_read_ppm -#define _jinit_write_ppm j16init_write_ppm -#define _jpeg_read_scanlines jpeg16_read_scanlines -#define _jpeg_write_scanlines jpeg16_write_scanlines +// j16XXX hack until I clean up TurboJPEG. +#define _JSAMPLE J12SAMPLE +#define _JSAMPROW J12SAMPROW +#define _buffer buffer12 +#define _jinit_read_ppm j12init_read_ppm +#define _jinit_write_ppm j12init_write_ppm +#define _jpeg_read_scanlines jpeg12_read_scanlines +#define _jpeg_write_scanlines jpeg12_write_scanlines #endif #define _GET_NAME(name, suffix) name##suffix @@ -2455,8 +1444,12 @@ DLLEXPORT _JSAMPLE *GET_NAME(tj3LoadImage, BITS_IN_JSAMPLE) if (*pixelFormat == TJPF_UNKNOWN) cinfo->in_color_space = JCS_UNKNOWN; else cinfo->in_color_space = pf2cs[*pixelFormat]; if (tempc == 'B') { + #ifdef BMP_SUPPORTED if ((src = jinit_read_bmp(cinfo, FALSE)) == NULL) THROW("Could not initialize bitmap loader"); + #else + THROW("BMP support was not compiled"); + #endif /* BMP_SUPPORTED */ invert = !this->bottomUp; } else if (tempc == 'P') { if ((src = _jinit_read_ppm(cinfo)) == NULL) @@ -2591,8 +1584,12 @@ DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE) ptr = strrchr(filename, '.'); if (ptr && !strcasecmp(ptr, ".bmp")) { + #ifdef BMP_SUPPORTED if ((dst = jinit_write_bmp(dinfo, FALSE, FALSE)) == NULL) THROW("Could not initialize bitmap writer"); + #else + THROW("BMP support was not compiled"); + #endif /* BMP_SUPPORTED */ invert = !this->bottomUp; dinfo->X_density = (UINT16)this->xDensity; dinfo->Y_density = (UINT16)this->yDensity; @@ -2653,6 +1650,8 @@ DLLEXPORT int GET_NAME(tj3SaveImage, BITS_IN_JSAMPLE) #undef _jpeg_write_scanlines #undef BITS_IN_JSAMPLE +// j16XXX hack until I clean up TurboJPEG. +#define BITS_IN_JSAMPLE 12 /* TurboJPEG 1.2+ */ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, @@ -2675,8 +1674,8 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf, processFlags(handle, flags, COMPRESS); size = (size_t)(*jpegSize); - retval = tj3Compress8(handle, srcBuf, width, pitch, height, pixelFormat, - jpegBuf, &size); + retval = tj3Compress12(handle, (JSAMPLE *)srcBuf, width, pitch, height, pixelFormat, + jpegBuf, &size); *jpegSize = (unsigned long)size; bailout: @@ -2765,8 +1764,10 @@ DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf, THROW("libjpeg API is in the wrong state"); (*cinfo->err->reset_error_mgr) ((j_common_ptr)cinfo); jinit_c_master_control(cinfo, FALSE); - jinit_color_converter(cinfo); - jinit_downsampler(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_color_converter(cinfo); + // j16XXX hack until I clean up TurboJPEG. + j12init_downsampler(cinfo); (*cinfo->cconvert->start_pass) (cinfo); pw0 = PAD(width, cinfo->max_h_samp_factor); @@ -2799,7 +1800,7 @@ DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf, unsigned char *_tmpbuf_aligned = (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32); - tmpbuf[i][row] = &_tmpbuf_aligned[ + tmpbuf[i][row] = (JSAMPROW)&_tmpbuf_aligned[ PAD((compptr->width_in_blocks * cinfo->max_h_samp_factor * DCTSIZE) / compptr->h_samp_factor, 32) * row]; } @@ -2815,15 +1816,14 @@ DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf, unsigned char *_tmpbuf2_aligned = (unsigned char *)PAD((JUINTPTR)_tmpbuf2[i], 32); - tmpbuf2[i][row] = - &_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; + tmpbuf2[i][row] = (JSAMPROW)&_tmpbuf2_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; } pw[i] = pw0 * compptr->h_samp_factor / cinfo->max_h_samp_factor; ph[i] = ph0 * compptr->v_samp_factor / cinfo->max_v_samp_factor; outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i]); if (!outbuf[i]) THROW("Memory allocation failure"); - ptr = dstPlanes[i]; + ptr = (JSAMPLE *)dstPlanes[i]; for (row = 0; row < ph[i]; row++) { outbuf[i][row] = ptr; ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; @@ -2841,7 +1841,8 @@ DLLEXPORT int tj3EncodeYUVPlanes8(tjhandle handle, const unsigned char *srcBuf, (cinfo->downsample->downsample) (cinfo, tmpbuf, 0, tmpbuf2, 0); for (i = 0, compptr = cinfo->comp_info; i < cinfo->num_components; i++, compptr++) - jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], + // j16XXX hack until I clean up TurboJPEG. + j12copy_sample_rows(tmpbuf2[i], 0, outbuf[i], row * compptr->v_samp_factor / cinfo->max_v_samp_factor, compptr->v_samp_factor, pw[i]); } @@ -3485,7 +2486,7 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, return -1; if (tj3SetCroppingRegion(handle, TJUNCROPPED) == -1) return -1; - return tj3Decompress8(handle, jpegBuf, jpegSize, dstBuf, pitch, pixelFormat); + return tj3Decompress12(handle, jpegBuf, jpegSize, (JSAMPLE *)dstBuf, pitch, pixelFormat); bailout: if (dinfo->global_state > DSTATE_START) jpeg_abort_decompress(dinfo); @@ -3629,9 +2630,9 @@ DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle, THROW("Memory allocation failure"); for (i = 0; i < height; i++) { if (this->bottomUp) - row_pointer[i] = &dstBuf[(height - i - 1) * (size_t)pitch]; + row_pointer[i] = (JSAMPROW)&dstBuf[(height - i - 1) * (size_t)pitch]; else - row_pointer[i] = &dstBuf[i * (size_t)pitch]; + row_pointer[i] = (JSAMPROW)&dstBuf[i * (size_t)pitch]; } if (height < ph0) for (i = height; i < ph0; i++) row_pointer[i] = row_pointer[height - 1]; @@ -3650,8 +2651,7 @@ DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle, unsigned char *_tmpbuf_aligned = (unsigned char *)PAD((JUINTPTR)_tmpbuf[i], 32); - tmpbuf[i][row] = - &_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; + tmpbuf[i][row] = (JSAMPROW)&_tmpbuf_aligned[PAD(compptr->width_in_blocks * DCTSIZE, 32) * row]; } pw[i] = pw0 * compptr->h_samp_factor / dinfo->max_h_samp_factor; ph[i] = ph0 * compptr->v_samp_factor / dinfo->max_v_samp_factor; @@ -3675,7 +2675,8 @@ DLLEXPORT int tj3DecodeYUVPlanes8(tjhandle handle, for (i = 0, compptr = dinfo->comp_info; i < dinfo->num_components; i++, compptr++) - jcopy_sample_rows(inbuf[i], + // j16XXX hack until I clean up TurboJPEG. + j12copy_sample_rows(inbuf[i], row * compptr->v_samp_factor / dinfo->max_v_samp_factor, tmpbuf[i], 0, compptr->v_samp_factor, pw[i]); (dinfo->upsample->upsample) (dinfo, tmpbuf, &inrow, @@ -3862,7 +2863,7 @@ DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle, tmpbufsize += iw[i] * th[i]; if ((outbuf[i] = (JSAMPROW *)malloc(sizeof(JSAMPROW) * ph[i])) == NULL) THROW("Memory allocation failure"); - ptr = dstPlanes[i]; + ptr = (JSAMPLE *)dstPlanes[i]; for (row = 0; row < ph[i]; row++) { outbuf[i][row] = ptr; ptr += (strides && strides[i] != 0) ? strides[i] : pw[i]; @@ -3921,8 +2922,9 @@ DLLEXPORT int tj3DecompressToYUVPlanes8(tjhandle handle, if (usetmpbuf) yuvptr[i] = tmpbuf[i]; else yuvptr[i] = &outbuf[i][crow[i]]; } - jpeg_read_raw_data(dinfo, yuvptr, - dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size); + // j16XXX hack until I clean up TurboJPEG. + jpeg12_read_raw_data(dinfo, yuvptr, + dinfo->max_v_samp_factor * dinfo->_min_DCT_scaled_size); if (usetmpbuf) { int j; @@ -4347,7 +3349,7 @@ DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width, processFlags(handle, flags, COMPRESS); - dstBuf = tj3LoadImage8(handle, filename, width, align, height, pixelFormat); + dstBuf = (unsigned char *)tj3LoadImage12(handle, filename, width, align, height, pixelFormat); tj3Destroy(handle); return dstBuf; @@ -4368,8 +3370,8 @@ DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer, processFlags(handle, flags, DECOMPRESS); - retval = tj3SaveImage8(handle, filename, buffer, width, pitch, height, - pixelFormat); + retval = tj3SaveImage12(handle, filename, (short *)buffer, width, pitch, height, + pixelFormat); tj3Destroy(handle); return retval; diff --git a/Sources/TurboJPEG/wrjpgcom.c b/Sources/TurboJPEG/wrjpgcom.c index 060925fe..e4663dea 100644 --- a/Sources/TurboJPEG/wrjpgcom.c +++ b/Sources/TurboJPEG/wrjpgcom.c @@ -394,184 +394,184 @@ keymatch(char *arg, const char *keyword, int minchars) * The main program. */ -int -main(int argc, char **argv) -{ - int argn; - char *arg; - int keep_COM = 1; - char *comment_arg = NULL; - FILE *comment_file = NULL; - unsigned int comment_length = 0; - int marker; - - progname = argv[0]; - if (progname == NULL || progname[0] == 0) - progname = "wrjpgcom"; /* in case C library doesn't provide it */ - - /* Parse switches, if any */ - for (argn = 1; argn < argc; argn++) { - arg = argv[argn]; - if (arg[0] != '-') - break; /* not switch, must be file name */ - arg++; /* advance over '-' */ - if (keymatch(arg, "replace", 1)) { - keep_COM = 0; - } else if (keymatch(arg, "cfile", 2)) { - if (++argn >= argc) usage(); - if ((comment_file = fopen(argv[argn], "r")) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); - exit(EXIT_FAILURE); - } - } else if (keymatch(arg, "comment", 1)) { - if (++argn >= argc) usage(); - comment_arg = argv[argn]; - /* If the comment text starts with '"', then we are probably running - * under MS-DOG and must parse out the quoted string ourselves. Sigh. - */ - if (comment_arg[0] == '"') { - comment_arg = (char *)malloc((size_t)MAX_COM_LENGTH); - if (comment_arg == NULL) - ERREXIT("Insufficient memory"); - if (strlen(argv[argn]) + 2 >= (size_t)MAX_COM_LENGTH) { - fprintf(stderr, "Comment text may not exceed %u bytes\n", - (unsigned int)MAX_COM_LENGTH); - exit(EXIT_FAILURE); - } - strcpy(comment_arg, argv[argn] + 1); - for (;;) { - comment_length = (unsigned int)strlen(comment_arg); - if (comment_length > 0 && comment_arg[comment_length - 1] == '"') { - comment_arg[comment_length - 1] = '\0'; /* zap terminating quote */ - break; - } - if (++argn >= argc) - ERREXIT("Missing ending quote mark"); - if (strlen(comment_arg) + strlen(argv[argn]) + 2 >= - (size_t)MAX_COM_LENGTH) { - fprintf(stderr, "Comment text may not exceed %u bytes\n", - (unsigned int)MAX_COM_LENGTH); - exit(EXIT_FAILURE); - } - strcat(comment_arg, " "); - strcat(comment_arg, argv[argn]); - } - } else if (strlen(argv[argn]) >= (size_t)MAX_COM_LENGTH) { - fprintf(stderr, "Comment text may not exceed %u bytes\n", - (unsigned int)MAX_COM_LENGTH); - exit(EXIT_FAILURE); - } - comment_length = (unsigned int)strlen(comment_arg); - } else - usage(); - } - - /* Cannot use both -comment and -cfile. */ - if (comment_arg != NULL && comment_file != NULL) - usage(); - /* If there is neither -comment nor -cfile, we will read the comment text - * from stdin; in this case there MUST be an input JPEG file name. - */ - if (comment_arg == NULL && comment_file == NULL && argn >= argc) - usage(); - - /* Open the input file. */ - if (argn < argc) { - if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); - exit(EXIT_FAILURE); - } - } else { - /* default input file is stdin */ -#ifdef USE_SETMODE /* need to hack file mode? */ - setmode(fileno(stdin), O_BINARY); -#endif -#ifdef USE_FDOPEN /* need to re-open in binary mode? */ - if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open stdin\n", progname); - exit(EXIT_FAILURE); - } -#else - infile = stdin; -#endif - } - - /* Open the output file. */ -#ifdef TWO_FILE_COMMANDLINE - /* Must have explicit output file name */ - if (argn != argc - 2) { - fprintf(stderr, "%s: must name one input and one output file\n", progname); - usage(); - } - if ((outfile = fopen(argv[argn + 1], WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open %s\n", progname, argv[argn + 1]); - exit(EXIT_FAILURE); - } -#else - /* Unix style: expect zero or one file name */ - if (argn < argc - 1) { - fprintf(stderr, "%s: only one input file\n", progname); - usage(); - } - /* default output file is stdout */ -#ifdef USE_SETMODE /* need to hack file mode? */ - setmode(fileno(stdout), O_BINARY); -#endif -#ifdef USE_FDOPEN /* need to re-open in binary mode? */ - if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { - fprintf(stderr, "%s: can't open stdout\n", progname); - exit(EXIT_FAILURE); - } -#else - outfile = stdout; -#endif -#endif /* TWO_FILE_COMMANDLINE */ - - /* Collect comment text from comment_file or stdin, if necessary */ - if (comment_arg == NULL) { - FILE *src_file; - int c; - - comment_arg = (char *)malloc((size_t)MAX_COM_LENGTH); - if (comment_arg == NULL) - ERREXIT("Insufficient memory"); - comment_length = 0; - src_file = (comment_file != NULL ? comment_file : stdin); - while ((c = getc(src_file)) != EOF) { - if (comment_length >= (unsigned int)MAX_COM_LENGTH) { - fprintf(stderr, "Comment text may not exceed %u bytes\n", - (unsigned int)MAX_COM_LENGTH); - exit(EXIT_FAILURE); - } - comment_arg[comment_length++] = (char)c; - } - if (comment_file != NULL) - fclose(comment_file); - } - - /* Copy JPEG headers until SOFn marker; - * we will insert the new comment marker just before SOFn. - * This (a) causes the new comment to appear after, rather than before, - * existing comments; and (b) ensures that comments come after any JFIF - * or JFXX markers, as required by the JFIF specification. - */ - marker = scan_JPEG_header(keep_COM); - /* Insert the new COM marker, but only if nonempty text has been supplied */ - if (comment_length > 0) { - write_marker(M_COM); - write_2_bytes(comment_length + 2); - while (comment_length > 0) { - write_1_byte(*comment_arg++); - comment_length--; - } - } - /* Duplicate the remainder of the source file. - * Note that any COM markers occurring after SOF will not be touched. - */ - write_marker(marker); - copy_rest_of_file(); - - /* All done. */ - exit(EXIT_SUCCESS); - return 0; /* suppress no-return-value warnings */ -} +// int +// main(int argc, char **argv) +// { +// int argn; +// char *arg; +// int keep_COM = 1; +// char *comment_arg = NULL; +// FILE *comment_file = NULL; +// unsigned int comment_length = 0; +// int marker; + +// progname = argv[0]; +// if (progname == NULL || progname[0] == 0) +// progname = "wrjpgcom"; /* in case C library doesn't provide it */ + +// /* Parse switches, if any */ +// for (argn = 1; argn < argc; argn++) { +// arg = argv[argn]; +// if (arg[0] != '-') +// break; /* not switch, must be file name */ +// arg++; /* advance over '-' */ +// if (keymatch(arg, "replace", 1)) { +// keep_COM = 0; +// } else if (keymatch(arg, "cfile", 2)) { +// if (++argn >= argc) usage(); +// if ((comment_file = fopen(argv[argn], "r")) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); +// exit(EXIT_FAILURE); +// } +// } else if (keymatch(arg, "comment", 1)) { +// if (++argn >= argc) usage(); +// comment_arg = argv[argn]; +// /* If the comment text starts with '"', then we are probably running +// * under MS-DOG and must parse out the quoted string ourselves. Sigh. +// */ +// if (comment_arg[0] == '"') { +// comment_arg = (char *)malloc((size_t)MAX_COM_LENGTH); +// if (comment_arg == NULL) +// ERREXIT("Insufficient memory"); +// if (strlen(argv[argn]) + 2 >= (size_t)MAX_COM_LENGTH) { +// fprintf(stderr, "Comment text may not exceed %u bytes\n", +// (unsigned int)MAX_COM_LENGTH); +// exit(EXIT_FAILURE); +// } +// strcpy(comment_arg, argv[argn] + 1); +// for (;;) { +// comment_length = (unsigned int)strlen(comment_arg); +// if (comment_length > 0 && comment_arg[comment_length - 1] == '"') { +// comment_arg[comment_length - 1] = '\0'; /* zap terminating quote */ +// break; +// } +// if (++argn >= argc) +// ERREXIT("Missing ending quote mark"); +// if (strlen(comment_arg) + strlen(argv[argn]) + 2 >= +// (size_t)MAX_COM_LENGTH) { +// fprintf(stderr, "Comment text may not exceed %u bytes\n", +// (unsigned int)MAX_COM_LENGTH); +// exit(EXIT_FAILURE); +// } +// strcat(comment_arg, " "); +// strcat(comment_arg, argv[argn]); +// } +// } else if (strlen(argv[argn]) >= (size_t)MAX_COM_LENGTH) { +// fprintf(stderr, "Comment text may not exceed %u bytes\n", +// (unsigned int)MAX_COM_LENGTH); +// exit(EXIT_FAILURE); +// } +// comment_length = (unsigned int)strlen(comment_arg); +// } else +// usage(); +// } + +// /* Cannot use both -comment and -cfile. */ +// if (comment_arg != NULL && comment_file != NULL) +// usage(); +// /* If there is neither -comment nor -cfile, we will read the comment text +// * from stdin; in this case there MUST be an input JPEG file name. +// */ +// if (comment_arg == NULL && comment_file == NULL && argn >= argc) +// usage(); + +// /* Open the input file. */ +// if (argn < argc) { +// if ((infile = fopen(argv[argn], READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[argn]); +// exit(EXIT_FAILURE); +// } +// } else { +// /* default input file is stdin */ +// #ifdef USE_SETMODE /* need to hack file mode? */ +// setmode(fileno(stdin), O_BINARY); +// #endif +// #ifdef USE_FDOPEN /* need to re-open in binary mode? */ +// if ((infile = fdopen(fileno(stdin), READ_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open stdin\n", progname); +// exit(EXIT_FAILURE); +// } +// #else +// infile = stdin; +// #endif +// } + +// /* Open the output file. */ +// #ifdef TWO_FILE_COMMANDLINE +// /* Must have explicit output file name */ +// if (argn != argc - 2) { +// fprintf(stderr, "%s: must name one input and one output file\n", progname); +// usage(); +// } +// if ((outfile = fopen(argv[argn + 1], WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open %s\n", progname, argv[argn + 1]); +// exit(EXIT_FAILURE); +// } +// #else +// /* Unix style: expect zero or one file name */ +// if (argn < argc - 1) { +// fprintf(stderr, "%s: only one input file\n", progname); +// usage(); +// } +// /* default output file is stdout */ +// #ifdef USE_SETMODE /* need to hack file mode? */ +// setmode(fileno(stdout), O_BINARY); +// #endif +// #ifdef USE_FDOPEN /* need to re-open in binary mode? */ +// if ((outfile = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) { +// fprintf(stderr, "%s: can't open stdout\n", progname); +// exit(EXIT_FAILURE); +// } +// #else +// outfile = stdout; +// #endif +// #endif /* TWO_FILE_COMMANDLINE */ + +// /* Collect comment text from comment_file or stdin, if necessary */ +// if (comment_arg == NULL) { +// FILE *src_file; +// int c; + +// comment_arg = (char *)malloc((size_t)MAX_COM_LENGTH); +// if (comment_arg == NULL) +// ERREXIT("Insufficient memory"); +// comment_length = 0; +// src_file = (comment_file != NULL ? comment_file : stdin); +// while ((c = getc(src_file)) != EOF) { +// if (comment_length >= (unsigned int)MAX_COM_LENGTH) { +// fprintf(stderr, "Comment text may not exceed %u bytes\n", +// (unsigned int)MAX_COM_LENGTH); +// exit(EXIT_FAILURE); +// } +// comment_arg[comment_length++] = (char)c; +// } +// if (comment_file != NULL) +// fclose(comment_file); +// } + +// /* Copy JPEG headers until SOFn marker; +// * we will insert the new comment marker just before SOFn. +// * This (a) causes the new comment to appear after, rather than before, +// * existing comments; and (b) ensures that comments come after any JFIF +// * or JFXX markers, as required by the JFIF specification. +// */ +// marker = scan_JPEG_header(keep_COM); +// /* Insert the new COM marker, but only if nonempty text has been supplied */ +// if (comment_length > 0) { +// write_marker(M_COM); +// write_2_bytes(comment_length + 2); +// while (comment_length > 0) { +// write_1_byte(*comment_arg++); +// comment_length--; +// } +// } +// /* Duplicate the remainder of the source file. +// * Note that any COM markers occurring after SOF will not be touched. +// */ +// write_marker(marker); +// copy_rest_of_file(); + +// /* All done. */ +// exit(EXIT_SUCCESS); +// return 0; /* suppress no-return-value warnings */ +// }