opencolorio/tests/gpu/Lut1DOp_test.cpp

397 lines
11 KiB
C++

// SPDX-License-Identifier: BSD-3-Clause
// Copyright Contributors to the OpenColorIO Project.
#include <stdio.h>
#include <sstream>
#include <string>
#include <OpenColorIO/OpenColorIO.h>
#include "GPUUnitTest.h"
#include "GPUHelpers.h"
namespace OCIO = OCIO_NAMESPACE;
const int LUT3D_EDGE_SIZE = 32;
#ifndef OCIO_UNIT_TEST_FILES_DIR
#error Expecting OCIO_UNIT_TEST_FILES_DIR to be defined for tests. Check relevant CMakeLists.txt
#endif
// For explanation, refer to https://gcc.gnu.org/onlinedocs/cpp/Stringizing.html
#define _STR(x) #x
#define STR(x) _STR(x)
static const std::string ocioTestFilesDir(STR(OCIO_UNIT_TEST_FILES_DIR));
namespace
{
OCIO::FileTransformRcPtr GetFileTransform(const std::string & filename)
{
const std::string filepath(ocioTestFilesDir + std::string("/") + filename);
OCIO::FileTransformRcPtr file = OCIO::FileTransform::Create();
file->setSrc(filepath.c_str());
return file;
}
}
// The LUTs below are identities unless otherwise noted.
// Various sizes are used to test different 1D LUT texture packings on the GPU.
// lut1d_1.spi1d has 512 entries
// lut1d_2.spi1d has 8192 entries
// lut1d_3.spi1d has 131072 entries
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_1_small_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_1.spi1d");
test.setProcessor(file);
test.setLegacyShader(true);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_1_small_inverse_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_1.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setLegacyShader(true);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_1_small_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_1.spi1d");
test.setProcessor(file);
test.setErrorThreshold(5e-6f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_1_small_inverse_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_1.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_2_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_2.spi1d");
test.setProcessor(file);
test.setLegacyShader(true);
test.setLegacyShaderLutEdge(2 * LUT3D_EDGE_SIZE);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_2_inverse_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_2.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setLegacyShader(true);
test.setLegacyShaderLutEdge(2 * LUT3D_EDGE_SIZE);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_2_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_2.spi1d");
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
// TODO: Would like to be able to remove the setTestNaN(false) and
// setTestInfinity(false) from all of these tests.
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_2_inverse_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_2.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setErrorThreshold(1e-4f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_3_big_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_3.spi1d");
test.setProcessor(file);
test.setLegacyShader(true);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_3_big_inverse_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_3.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setLegacyShader(true);
test.setErrorThreshold(2e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_3_big_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_3.spi1d");
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_3_big_inverse_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_3.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_3_big_nearest_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_3.spi1d");
file->setInterpolation(OCIO::INTERP_NEAREST);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, scale_lut1d_4_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_4.spi1d");
test.setProcessor(file);
test.setLegacyShader(true);
test.setLegacyShaderLutEdge(2 * LUT3D_EDGE_SIZE);
test.setErrorThreshold(2e-4f);
// lut1d_4.spi1d has values outside [0, 1]. Legacy shader is baking ops
// into a 3D LUT and would clamp outside of [0, 1].
test.setTestWideRange(false);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, scale_lut1d_4_inverse_legacy_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_4.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setLegacyShader(true);
test.setLegacyShaderLutEdge(2 * LUT3D_EDGE_SIZE);
test.setErrorThreshold(5e-5f);
test.setTestWideRange(false);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, scale_lut1d_4_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_4.spi1d");
test.setProcessor(file);
// TODO: Should be smaller.
test.setErrorThreshold(1e-4f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, scale_lut1d_4_inverse_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_4.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, not_linear_lut1d_5_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_5.spi1d");
test.setProcessor(file);
test.setErrorThreshold(5e-4f); // Good value for a relative error threshold.
test.setRelativeComparison(true); // LUT contains values from 0.0f to 64.0f
// explaining why an absolute error could not be used.
}
OCIO_ADD_GPU_TEST(Lut1DOp, not_linear_lut1d_5_inverse_generic_shader)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_5.spi1d");
file->setDirection(OCIO::TRANSFORM_DIR_INVERSE);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_half_domain_unequal_channels)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_halfdom.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_file2_test)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_green.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
// LUT has just 32 entries and thus requires a larger tolerance due to
// index quantization on GPUs.
test.setErrorThreshold(1e-4f);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_hue_adjust_test)
{
// Note: This LUT has 1024 entries so it tests the "small LUT" path.
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_1024_hue_adjust_test.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
// NB: This test has required a tolerance of 0.1 on older graphics cards.
test.setErrorThreshold(1e-5f);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_half_domain_hue_adjust_test)
{
// Note: This LUT is half domain and also a "big LUT" so it tests that path.
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_hd_hue_adjust.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
// NB: This test has required a tolerance of 0.1 on older graphics cards.
test.setErrorThreshold(1e-6f);
// LUT range is 0.0001 -> 10000.0.
test.setRelativeComparison(true);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_inverse_file1_test)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_inv.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
// Inverse LUT leads bigger errors.
test.setErrorThreshold(1e-4f);
test.setTestNaN(false);
test.setTestInfinity(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_inverse_file2_test)
{
// This LUT has an extended domain (entries outside [0,1]) and hence the fast LUT
// that gets built from it must have a halfDomain for both CPU and GPU.
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_inverse_gpu.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_inverse_half_file1_test)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_inverse_halfdom_slog_fclut.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
test.setErrorThreshold(1e-4f);
test.setRelativeComparison(true);
test.setExpectedMinimalValue(1e-3f);
test.setTestNaN(false);
}
OCIO_ADD_GPU_TEST(Lut1DOp, lut1d_inverse_half_hue_adjust_file1_test)
{
OCIO::FileTransformRcPtr file = GetFileTransform("lut1d_inverse_hd_hueAdjust.ctf");
file->setDirection(OCIO::TRANSFORM_DIR_FORWARD);
test.setProcessor(file);
test.setErrorThreshold(1e-6f);
test.setTestNaN(false);
test.setTestInfinity(false);
}
// TODO: Add tests with LUTs with Inf and NaN values.
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_8i_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_16i_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_16f_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_16f_half_domain_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_32f_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1DTooManyTextures_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_File1_test
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_too_small
// TODO: Port syncolor test: renderer\test\GPURenderer_cases.cpp_inc - GPURendererLut1D_half_domain_test