From fbefa7ca36383bc425a8d40d6560f028d3e6302e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Achard?= Date: Mon, 28 Aug 2023 10:31:33 +0100 Subject: [PATCH 1/4] Add missing hasDynamicProperty and isDynamic methods to CPUProcessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Achard --- include/OpenColorIO/OpenColorIO.h | 4 ++ include/OpenColorIO/OpenColorTransforms.h | 2 +- src/OpenColorIO/CPUProcessor.cpp | 56 +++++++++++++++++++ src/OpenColorIO/CPUProcessor.h | 2 + src/OpenColorIO/Op.cpp | 5 ++ src/OpenColorIO/Op.h | 1 + .../ExposureContrastOpCPU.cpp | 7 ++- .../gradingprimary/GradingPrimaryOpCPU.cpp | 6 ++ .../gradingrgbcurve/GradingRGBCurveOpCPU.cpp | 6 ++ .../ops/gradingtone/GradingToneOpCPU.cpp | 6 ++ src/bindings/python/PyCPUProcessor.cpp | 7 +++ tests/cpu/CPUProcessor_tests.cpp | 21 +++++++ tests/python/CPUProcessorTest.py | 3 + tests/python/GradingPrimaryTransformTest.py | 3 + 14 files changed, 127 insertions(+), 2 deletions(-) diff --git a/include/OpenColorIO/OpenColorIO.h b/include/OpenColorIO/OpenColorIO.h index 29f1243ac0..86537bc623 100644 --- a/include/OpenColorIO/OpenColorIO.h +++ b/include/OpenColorIO/OpenColorIO.h @@ -2593,6 +2593,10 @@ class OCIOEXPORT CPUProcessor * there is one in the CPU processor. */ DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const; + /// True if at least one dynamic property of that type exists. + bool hasDynamicProperty(DynamicPropertyType type) const noexcept; + /// True if at least one dynamic property of any type exists and is dynamic. + bool isDynamic() const noexcept; /** * \brief Apply to an image with any kind of channel ordering while diff --git a/include/OpenColorIO/OpenColorTransforms.h b/include/OpenColorIO/OpenColorTransforms.h index d4587149ec..19bf1496a4 100644 --- a/include/OpenColorIO/OpenColorTransforms.h +++ b/include/OpenColorIO/OpenColorTransforms.h @@ -687,7 +687,7 @@ extern OCIOEXPORT std::ostream & operator<<(std::ostream &, const GradingTone &) * OCIO::DynamicPropertyValue::AsGradingPrimary(dynProp); * OCIO::GradingPrimary primary = primaryProp->getValue(); * primary.m_saturation += 0.1f; - * rgbCurveProp->setValue(primary); + * primaryProp->setValue(primary); * } * if (cpuProcessor->hasDynamicProperty(OCIO::DYNAMIC_PROPERTY_GRADING_RGBCURVE)) * { diff --git a/src/OpenColorIO/CPUProcessor.cpp b/src/OpenColorIO/CPUProcessor.cpp index bfe98b9f5c..033083aed3 100644 --- a/src/OpenColorIO/CPUProcessor.cpp +++ b/src/OpenColorIO/CPUProcessor.cpp @@ -239,6 +239,52 @@ case in: \ throw Exception("Unsupported bit-depths"); } +bool CPUProcessor::Impl::isDynamic() const noexcept +{ + if (m_inBitDepthOp->isDynamic()) + { + return true; + } + + for (const auto & op : m_cpuOps) + { + if (op->isDynamic()) + { + return true; + } + } + + if (m_outBitDepthOp->isDynamic()) + { + return true; + } + + return false; +} + +bool CPUProcessor::Impl::hasDynamicProperty(DynamicPropertyType type) const noexcept +{ + if (m_inBitDepthOp->hasDynamicProperty(type)) + { + return true; + } + + for (const auto & op : m_cpuOps) + { + if (op->hasDynamicProperty(type)) + { + return true; + } + } + + if (m_outBitDepthOp->hasDynamicProperty(type)) + { + return true; + } + + return false; +} + DynamicPropertyRcPtr CPUProcessor::Impl::getDynamicProperty(DynamicPropertyType type) const { if (m_inBitDepthOp->hasDynamicProperty(type)) @@ -472,6 +518,16 @@ BitDepth CPUProcessor::getOutputBitDepth() const return getImpl()->getOutputBitDepth(); } +bool CPUProcessor::isDynamic() const noexcept +{ + return getImpl()->isDynamic(); +} + +bool CPUProcessor::hasDynamicProperty(DynamicPropertyType type) const noexcept +{ + return getImpl()->hasDynamicProperty(type); +} + DynamicPropertyRcPtr CPUProcessor::getDynamicProperty(DynamicPropertyType type) const { return getImpl()->getDynamicProperty(type); diff --git a/src/OpenColorIO/CPUProcessor.h b/src/OpenColorIO/CPUProcessor.h index 319337f5fb..d5fcb43802 100644 --- a/src/OpenColorIO/CPUProcessor.h +++ b/src/OpenColorIO/CPUProcessor.h @@ -39,6 +39,8 @@ class CPUProcessor::Impl BitDepth getInputBitDepth() const noexcept { return m_inBitDepth; } BitDepth getOutputBitDepth() const noexcept { return m_outBitDepth; } + bool isDynamic() const noexcept; + bool hasDynamicProperty(DynamicPropertyType type) const noexcept; DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const; void apply(const ImageDesc & imgDesc) const; diff --git a/src/OpenColorIO/Op.cpp b/src/OpenColorIO/Op.cpp index 1ae607a701..e1bd564ff9 100755 --- a/src/OpenColorIO/Op.cpp +++ b/src/OpenColorIO/Op.cpp @@ -24,6 +24,11 @@ namespace OCIO_NAMESPACE { +bool OpCPU::isDynamic() const +{ + return false; +} + bool OpCPU::hasDynamicProperty(DynamicPropertyType /* type */) const { return false; diff --git a/src/OpenColorIO/Op.h b/src/OpenColorIO/Op.h index d48fe512db..d88d8a1f4b 100644 --- a/src/OpenColorIO/Op.h +++ b/src/OpenColorIO/Op.h @@ -45,6 +45,7 @@ class OpCPU // the 1D LUT CPU Op where the finalization depends on input and output bit depths. virtual void apply(const void * inImg, void * outImg, long numPixels) const = 0; + virtual bool isDynamic() const; virtual bool hasDynamicProperty(DynamicPropertyType type) const; virtual DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const; }; diff --git a/src/OpenColorIO/ops/exposurecontrast/ExposureContrastOpCPU.cpp b/src/OpenColorIO/ops/exposurecontrast/ExposureContrastOpCPU.cpp index 800fc4035d..08e94e7239 100644 --- a/src/OpenColorIO/ops/exposurecontrast/ExposureContrastOpCPU.cpp +++ b/src/OpenColorIO/ops/exposurecontrast/ExposureContrastOpCPU.cpp @@ -25,6 +25,7 @@ class ECRendererBase : public OpCPU explicit ECRendererBase(ConstExposureContrastOpDataRcPtr & ec); virtual ~ECRendererBase(); + bool isDynamic() const override; bool hasDynamicProperty(DynamicPropertyType type) const override; DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const override; @@ -64,6 +65,11 @@ ECRendererBase::~ECRendererBase() { } +bool ECRendererBase::isDynamic() const +{ + return m_exposure->isDynamic() || m_contrast->isDynamic() || m_gamma->isDynamic(); +} + bool ECRendererBase::hasDynamicProperty(DynamicPropertyType type) const { bool res = false; @@ -701,4 +707,3 @@ OpCPURcPtr GetExposureContrastCPURenderer(ConstExposureContrastOpDataRcPtr & ec) } } // namespace OCIO_NAMESPACE - diff --git a/src/OpenColorIO/ops/gradingprimary/GradingPrimaryOpCPU.cpp b/src/OpenColorIO/ops/gradingprimary/GradingPrimaryOpCPU.cpp index 5596794d0f..07a87201e9 100644 --- a/src/OpenColorIO/ops/gradingprimary/GradingPrimaryOpCPU.cpp +++ b/src/OpenColorIO/ops/gradingprimary/GradingPrimaryOpCPU.cpp @@ -25,6 +25,7 @@ class GradingPrimaryOpCPU : public OpCPU explicit GradingPrimaryOpCPU(ConstGradingPrimaryOpDataRcPtr & gp); + bool isDynamic() const override; bool hasDynamicProperty(DynamicPropertyType type) const override; DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const override; @@ -42,6 +43,11 @@ GradingPrimaryOpCPU::GradingPrimaryOpCPU(ConstGradingPrimaryOpDataRcPtr & gp) } } +bool GradingPrimaryOpCPU::isDynamic() const +{ + return m_gp->isDynamic(); +} + bool GradingPrimaryOpCPU::hasDynamicProperty(DynamicPropertyType type) const { bool res = false; diff --git a/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp b/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp index 90dcf1bba4..7dc2eab02d 100644 --- a/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp +++ b/src/OpenColorIO/ops/gradingrgbcurve/GradingRGBCurveOpCPU.cpp @@ -25,6 +25,7 @@ class GradingRGBCurveOpCPU : public OpCPU explicit GradingRGBCurveOpCPU(ConstGradingRGBCurveOpDataRcPtr & grgbc); + bool isDynamic() const override; bool hasDynamicProperty(DynamicPropertyType type) const override; DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const override; @@ -64,6 +65,11 @@ GradingRGBCurveOpCPU::GradingRGBCurveOpCPU(ConstGradingRGBCurveOpDataRcPtr & grg } } +bool GradingRGBCurveOpCPU::isDynamic() const +{ + return m_grgbcurve->isDynamic(); +} + bool GradingRGBCurveOpCPU::hasDynamicProperty(DynamicPropertyType type) const { bool res = false; diff --git a/src/OpenColorIO/ops/gradingtone/GradingToneOpCPU.cpp b/src/OpenColorIO/ops/gradingtone/GradingToneOpCPU.cpp index e84ef15923..8511dcdff3 100644 --- a/src/OpenColorIO/ops/gradingtone/GradingToneOpCPU.cpp +++ b/src/OpenColorIO/ops/gradingtone/GradingToneOpCPU.cpp @@ -25,6 +25,7 @@ class GradingToneOpCPU : public OpCPU explicit GradingToneOpCPU(ConstGradingToneOpDataRcPtr & gt); + bool isDynamic() const override; bool hasDynamicProperty(DynamicPropertyType type) const override; DynamicPropertyRcPtr getDynamicProperty(DynamicPropertyType type) const override; @@ -44,6 +45,11 @@ GradingToneOpCPU::GradingToneOpCPU(ConstGradingToneOpDataRcPtr & gt) } } +bool GradingToneOpCPU::isDynamic() const +{ + return m_gt->isDynamic(); +} + bool GradingToneOpCPU::hasDynamicProperty(DynamicPropertyType type) const { bool res = false; diff --git a/src/bindings/python/PyCPUProcessor.cpp b/src/bindings/python/PyCPUProcessor.cpp index 2b31cafd70..84b91427bf 100644 --- a/src/bindings/python/PyCPUProcessor.cpp +++ b/src/bindings/python/PyCPUProcessor.cpp @@ -36,6 +36,13 @@ void bindPyCPUProcessor(py::module & m) }, "type"_a, DOC(CPUProcessor, getDynamicProperty)) + .def("hasDynamicProperty", + (bool (CPUProcessor::*)(DynamicPropertyType) const noexcept) + &CPUProcessor::hasDynamicProperty, + "type"_a, + DOC(CPUProcessor, hasDynamicProperty)) + .def("isDynamic", &CPUProcessor::isDynamic, + DOC(CPUProcessor, isDynamic)) .def("apply", [](CPUProcessorRcPtr & self, PyImageDesc & imgDesc) { diff --git a/tests/cpu/CPUProcessor_tests.cpp b/tests/cpu/CPUProcessor_tests.cpp index bc7820f367..d5f092e48d 100644 --- a/tests/cpu/CPUProcessor_tests.cpp +++ b/tests/cpu/CPUProcessor_tests.cpp @@ -13,6 +13,27 @@ namespace OCIO = OCIO_NAMESPACE; +OCIO_ADD_TEST(CPUProcessor, dynamic_properties) +{ + OCIO::ExposureContrastTransformRcPtr ec = OCIO::ExposureContrastTransform::Create(); + + ec->setExposure(1.2); + ec->setPivot(0.5); + ec->makeContrastDynamic(); + + OCIO::ConfigRcPtr config = OCIO::Config::Create(); + auto cpuProc = config->getProcessor(ec)->getDefaultCPUProcessor(); + OCIO_CHECK_ASSERT(cpuProc->isDynamic()); + OCIO_CHECK_ASSERT(cpuProc->hasDynamicProperty(OCIO::DYNAMIC_PROPERTY_CONTRAST)); + OCIO_CHECK_ASSERT(!cpuProc->hasDynamicProperty(OCIO::DYNAMIC_PROPERTY_EXPOSURE)); + OCIO::DynamicPropertyRcPtr dpc; + OCIO_CHECK_NO_THROW(dpc = cpuProc->getDynamicProperty(OCIO::DYNAMIC_PROPERTY_CONTRAST)); + OCIO_CHECK_ASSERT(dpc); + OCIO_CHECK_THROW_WHAT(cpuProc->getDynamicProperty(OCIO::DYNAMIC_PROPERTY_EXPOSURE), + OCIO::Exception, + "Cannot find dynamic property; not used by CPU processor."); +} + OCIO_ADD_TEST(CPUProcessor, flag_composition) { // The test validates the build of a custom optimization flag. diff --git a/tests/python/CPUProcessorTest.py b/tests/python/CPUProcessorTest.py index f33b5448e6..4fc5e3c157 100644 --- a/tests/python/CPUProcessorTest.py +++ b/tests/python/CPUProcessorTest.py @@ -274,6 +274,9 @@ def test_dynamic_property(self): proc = self.config.getProcessor(tr) cpu_proc = proc.getDefaultCPUProcessor() + self.assertTrue(cpu_proc.isDynamic()) + self.assertTrue(cpu_proc.hasDynamicProperty(OCIO.DYNAMIC_PROPERTY_EXPOSURE)) + # Validate default +0 stops exposure self.assertEqual( cpu_proc.applyRGB([1.0, 1.0, 1.0]), diff --git a/tests/python/GradingPrimaryTransformTest.py b/tests/python/GradingPrimaryTransformTest.py index a4c80a1c90..9eb5928147 100644 --- a/tests/python/GradingPrimaryTransformTest.py +++ b/tests/python/GradingPrimaryTransformTest.py @@ -134,6 +134,9 @@ def test_apply_dynamic(self): proc = cfg.getProcessor(group) cpu = proc.getDefaultCPUProcessor() + self.assertTrue(cpu.isDynamic()) + self.assertTrue(cpu.hasDynamicProperty(OCIO.DYNAMIC_PROPERTY_GRADING_PRIMARY)) + dp = cpu.getDynamicProperty(OCIO.DYNAMIC_PROPERTY_GRADING_PRIMARY) self.assertEqual(dp.getType(), OCIO.DYNAMIC_PROPERTY_GRADING_PRIMARY) From 64e49edb4eec00d9dc98dd4188197ec023e20175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Achard?= Date: Mon, 28 Aug 2023 10:32:36 +0100 Subject: [PATCH 2/4] Fix cpu test run under address sanitizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Achard --- tests/cpu/CMakeLists.txt | 41 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/tests/cpu/CMakeLists.txt b/tests/cpu/CMakeLists.txt index 06ef8b2b83..9b59b12383 100755 --- a/tests/cpu/CMakeLists.txt +++ b/tests/cpu/CMakeLists.txt @@ -4,6 +4,21 @@ # Define used for tests in tests/cpu/Context_tests.cpp add_definitions("-DOCIO_SOURCE_DIR=${PROJECT_SOURCE_DIR}") + +macro(add_ocio_test_variant NAME BINARY) + add_test(NAME ${NAME} COMMAND ${BINARY} ${ARGN}) + + if(OCIO_ENABLE_SANITIZER) + # - Ignore odr-violation warning coming supposedly from compiling OCIO + # sources within the test target as well as linking to the library. + # - Provide better stack traces for malloc related leaks. + set_tests_properties(${NAME} PROPERTIES + ENVIRONMENT + "ASAN_OPTIONS=detect_odr_violation=0:fast_unwind_on_malloc=0" + ) + endif() +endmacro() + function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) set(TEST_BINARY "test_${NAME}_exec") set(TEST_NAME "test_${NAME}") @@ -72,37 +87,27 @@ function(add_ocio_test NAME SOURCES PRIVATE_INCLUDES) ) if(OCIO_ARCH_X86) - add_test(NAME ${TEST_NAME} COMMAND ${TEST_BINARY}) - add_test(NAME ${TEST_NAME}_no_accel COMMAND ${TEST_BINARY} --no_accel) + add_ocio_test_variant(${TEST_NAME} ${TEST_BINARY}) + add_ocio_test_variant(${TEST_NAME}_no_accel ${TEST_BINARY} --no_accel) if(${OCIO_USE_SSE2}) - add_test(NAME ${TEST_NAME}_sse2 COMMAND ${TEST_BINARY} --sse2) + add_ocio_test_variant(${TEST_NAME}_sse2 ${TEST_BINARY} --sse2) if(${OCIO_USE_F16C}) - add_test(NAME ${TEST_NAME}_sse2+f16c COMMAND ${TEST_BINARY} --sse2 --f16c) + add_ocio_test_variant(${TEST_NAME}_sse2+f16c ${TEST_BINARY} --sse2 --f16c) endif() endif() if(${OCIO_USE_AVX}) - add_test(NAME ${TEST_NAME}_avx COMMAND ${TEST_BINARY} --avx) + add_ocio_test_variant(${TEST_NAME}_avx ${TEST_BINARY} --avx) if(${OCIO_USE_F16C}) - add_test(NAME ${TEST_NAME}_avx+f16c COMMAND ${TEST_BINARY} --avx --f16c) + add_ocio_test_variant(${TEST_NAME}_avx+f16c ${TEST_BINARY} --avx --f16c) endif() endif() if(${OCIO_USE_AVX2}) - add_test(NAME ${TEST_NAME}_avx2 COMMAND ${TEST_BINARY} --avx2) + add_ocio_test_variant(${TEST_NAME}_avx2 ${TEST_BINARY} --avx2) endif() else() - add_test(NAME ${TEST_NAME} COMMAND ${TEST_BINARY}) - endif() - - if(OCIO_ENABLE_SANITIZER) - # Ignore odr-violation warning coming supposeddly from compiling OCIO - # sources within the test target as well as linking to the library. - # Provide better stack traces for malloc related leaks. - set_tests_properties(${TEST_NAME} PROPERTIES - ENVIRONMENT - "ASAN_OPTIONS=detect_odr_violation=0:fast_unwind_on_malloc=0" - ) + add_ocio_test_variant(${TEST_NAME} ${TEST_BINARY}) endif() endfunction(add_ocio_test) From 0d7183ff70fb53cd42a30e0e9de4efd46d7d5456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Achard?= Date: Mon, 28 Aug 2023 10:33:11 +0100 Subject: [PATCH 3/4] Add OSL to Python GpuLanguage enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Achard --- src/bindings/python/PyTypes.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bindings/python/PyTypes.cpp b/src/bindings/python/PyTypes.cpp index 70f0ec99dd..760d715587 100644 --- a/src/bindings/python/PyTypes.cpp +++ b/src/bindings/python/PyTypes.cpp @@ -527,6 +527,8 @@ void bindPyTypes(py::module & m) DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_HLSL_DX11)) .value("GPU_LANGUAGE_MSL_2_0", GPU_LANGUAGE_MSL_2_0, DOC(PyOpenColorIO, GpuLanguage, GPU_LANGUAGE_MSL_2_0)) + .value("LANGUAGE_OSL_1", LANGUAGE_OSL_1, + DOC(PyOpenColorIO, GpuLanguage, LANGUAGE_OSL_1)) .export_values(); py::enum_( From a0151cc4037b938539e6e20eef012264f6fe8a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Achard?= Date: Mon, 28 Aug 2023 10:33:45 +0100 Subject: [PATCH 4/4] Fix Analysis nightly workflow not running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémi Achard --- .github/workflows/analysis_workflow.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/analysis_workflow.yml b/.github/workflows/analysis_workflow.yml index 56a243bcd0..23c1151393 100644 --- a/.github/workflows/analysis_workflow.yml +++ b/.github/workflows/analysis_workflow.yml @@ -29,9 +29,7 @@ jobs: linux_sonarcloud: name: 'Linux CentOS 7 VFX CY2022 SonarCloud ' # Don't run on OCIO forks - if: | - github.repository == 'AcademySoftwareFoundation/OpenColorIO' && - github.event.pull_request.head.repo.full_name == github.repository + if: github.repository == 'AcademySoftwareFoundation/OpenColorIO' # GH-hosted VM. The build runs in CentOS 7 'container' defined below. runs-on: ubuntu-latest container: