192 lines
7.4 KiB
C++
192 lines
7.4 KiB
C++
// SPDX-License-Identifier: BSD-3-Clause
|
|
// Copyright Contributors to the OpenColorIO Project.
|
|
|
|
|
|
#ifndef OPENCOLORIO_GPU_UNITTEST_H
|
|
#define OPENCOLORIO_GPU_UNITTEST_H
|
|
|
|
#include <functional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class OCIOGPUTest;
|
|
|
|
using OCIOTestFuncCallback = std::function<void(OCIOGPUTest & test)>;
|
|
|
|
|
|
// Test harness for comparing GPU results to CPU results.
|
|
//
|
|
// By default, the framework compares the GPU results to the CPU results
|
|
// using an automatically generated neutral ramp for the standard range [0, 1].
|
|
//
|
|
class OCIOGPUTest
|
|
{
|
|
public:
|
|
// The structure holds color values to check.
|
|
struct CustomValues
|
|
{
|
|
typedef std::vector<float> Values;
|
|
Values m_inputValues;
|
|
|
|
// Keeping the original input value size allows
|
|
// to avoid manipulating padded values added to fit
|
|
// the predefined GPU texture size.
|
|
size_t m_originalInputValueSize{ 0 };
|
|
};
|
|
|
|
public:
|
|
OCIOGPUTest(const std::string& testgroup, const std::string& testname, OCIOTestFuncCallback test);
|
|
|
|
~OCIOGPUTest() = default;
|
|
|
|
inline const std::string& group() const { return m_group; }
|
|
inline const std::string& name() const { return m_name; }
|
|
|
|
void setProcessor(OCIO_NAMESPACE::ConstConfigRcPtr config,
|
|
OCIO_NAMESPACE::TransformRcPtr transform);
|
|
|
|
void setProcessor(OCIO_NAMESPACE::TransformRcPtr transform);
|
|
|
|
void setProcessor(OCIO_NAMESPACE::ConstProcessorRcPtr processor);
|
|
|
|
void setShadingLanguage(OCIO_NAMESPACE::GpuLanguage gpuShadingLanguage)
|
|
{
|
|
m_gpuShadingLanguage = gpuShadingLanguage;
|
|
}
|
|
|
|
inline OCIO_NAMESPACE::ConstProcessorRcPtr & getProcessor() { return m_processor; }
|
|
OCIO_NAMESPACE::GpuShaderDescRcPtr & getShaderDesc();
|
|
|
|
// Set TestWideRange to true to use test values on [-1,2] rather than [0,1].
|
|
inline bool getTestWideRange() const { return m_testWideRange; }
|
|
inline void setTestWideRange(bool use) { m_testWideRange = use; }
|
|
|
|
// Set TestNaN to true to include NaNs in each channel of the test values.
|
|
inline bool getTestNaN() const { return m_testNaN; }
|
|
inline void setTestNaN(bool use) { m_testNaN = use; }
|
|
|
|
// Set TestInfinity to true to include positive and negative infinity
|
|
// in each channel of the test values.
|
|
inline bool getTestInfinity() const { return m_testInfinity; }
|
|
inline void setTestInfinity(bool use) { m_testInfinity = use; }
|
|
|
|
// Provide a set of RGBA values to test (otherwise a neutral ramp will be used).
|
|
// TestWideRange, TestNaN & TestInfinity are used when m_inputValues is empty.
|
|
inline void setCustomValues(CustomValues & values) { m_values = values; }
|
|
inline CustomValues & getCustomValues() { return m_values; }
|
|
|
|
inline float getErrorThreshold() const { return m_errorThreshold; }
|
|
inline void setErrorThreshold(float error) { m_errorThreshold = error; }
|
|
|
|
inline bool getRelativeComparison() const { return m_performRelativeComparison; }
|
|
inline void setRelativeComparison(bool relCompare) { m_performRelativeComparison = relCompare; }
|
|
|
|
// This is the lower bound for the value that is divided into the absolute error
|
|
// to obtain the relative error.
|
|
inline float getExpectedMinimalValue() const { return m_expectedMinimalValue; }
|
|
inline void setExpectedMinimalValue(float minValue) { m_expectedMinimalValue = minValue; }
|
|
|
|
// Dump or not the gpu shader program
|
|
inline void setVerbose(bool verbose) { m_verbose = verbose; }
|
|
inline bool isVerbose() const { return m_verbose; }
|
|
|
|
inline void setLegacyShader(bool legacy) { m_legacyShader = legacy; }
|
|
inline bool isLegacyShader() const { return m_legacyShader; }
|
|
|
|
inline void setLegacyShaderLutEdge(unsigned lutEdge) { m_legacyShaderLutEdge = lutEdge; }
|
|
inline unsigned getLegacyShaderLutEdge() const { return m_legacyShaderLutEdge; }
|
|
|
|
inline void setup() { m_function(*this); }
|
|
|
|
inline bool isValid() { return (bool)m_processor; }
|
|
|
|
inline void disable() { m_enabled = false; }
|
|
inline bool isEnabled() const { return m_enabled; }
|
|
|
|
// Testing dynamic properties requires to run several times the same
|
|
// unit test with the same shader code with some dynamic property
|
|
// value changes. Registering n callbacks (i.e. each callback changing
|
|
// a value for example) would run 1+n times the unit test.
|
|
// Test runs, then for each callback, it is called and test runs again.
|
|
// See ECOps_test.cpp for an example.
|
|
typedef std::function<void()> RetestSetupCallback;
|
|
inline void addRetest(RetestSetupCallback & retest)
|
|
{
|
|
m_retests.push_back(retest);
|
|
}
|
|
|
|
inline size_t getNumRetests() const
|
|
{
|
|
return m_retests.size();
|
|
}
|
|
|
|
void retestSetup(size_t idx);
|
|
|
|
inline void updateMaxDiff(float maxDiff, size_t idxDiff)
|
|
{
|
|
if (maxDiff > m_maxDiff)
|
|
{
|
|
m_maxDiff = maxDiff;
|
|
m_idxDiff = idxDiff;
|
|
}
|
|
}
|
|
inline float getMaxDiff() const
|
|
{
|
|
return m_maxDiff;
|
|
}
|
|
inline size_t getMaxDiffIndex() const
|
|
{
|
|
return m_idxDiff;
|
|
}
|
|
|
|
private:
|
|
const std::string m_group, m_name;
|
|
OCIOTestFuncCallback m_function;
|
|
OCIO_NAMESPACE::ConstProcessorRcPtr m_processor;
|
|
OCIO_NAMESPACE::GpuShaderDescRcPtr m_shaderDesc;
|
|
float m_errorThreshold;
|
|
float m_expectedMinimalValue{ 1e-6f };
|
|
float m_maxDiff{ 0.f };
|
|
size_t m_idxDiff{ 0 };
|
|
bool m_testWideRange{ true };
|
|
bool m_testNaN{ true };
|
|
bool m_testInfinity{ true };
|
|
bool m_performRelativeComparison{ false };
|
|
bool m_verbose{ false };
|
|
bool m_enabled{ true };
|
|
bool m_legacyShader{ false };
|
|
unsigned m_legacyShaderLutEdge{ 32 };
|
|
CustomValues m_values;
|
|
OCIO_NAMESPACE::GpuLanguage m_gpuShadingLanguage {OCIO_NAMESPACE::GPU_LANGUAGE_GLSL_1_2};
|
|
|
|
std::vector<RetestSetupCallback> m_retests;
|
|
|
|
};
|
|
|
|
typedef std::shared_ptr<OCIOGPUTest> OCIOGPUTestRcPtr;
|
|
typedef std::vector<OCIOGPUTestRcPtr> UnitTests;
|
|
|
|
UnitTests& GetUnitTests();
|
|
|
|
struct AddTest { explicit AddTest(OCIOGPUTestRcPtr test); };
|
|
|
|
|
|
// Use this macro to declare a test and provide a setup function for the test.
|
|
// Note: Add a SonarCloud tag to suppress all warnings for the following method.
|
|
#define OCIO_ADD_GPU_TEST(group, name) \
|
|
static void ocio_gputest_##group##_##name(OCIOGPUTest & test); \
|
|
AddTest ocio_##group##_##name( \
|
|
std::make_shared<OCIOGPUTest>(#group, \
|
|
#name, \
|
|
ocio_gputest_##group##_##name)); \
|
|
/* @SuppressWarnings('all') */ \
|
|
static void ocio_gputest_##group##_##name(OCIOGPUTest & test)
|
|
|
|
// Use this macro inside OCIO_ADD_GPU_TEST function to disable the test.
|
|
// The remaining of the function implementation will be skipped.
|
|
#define OCIO_DISABLE_GPU_TEST() \
|
|
test.disable(); \
|
|
if (!test.isEnabled()) return; // Test to avoid unreachable code warning.
|
|
|
|
#endif /* OPENCOLORIO_GPU_UNITTEST_H */
|