Skip to content

Commit 8dc5f6e

Browse files
authored
Adsk Contrib - Fix a bit depth optimization bug (#1446) (#1459)
* Adsk Contrib - Fix a bit-depth optimization bug Signed-off-by: Patrick Hodoul <[email protected]> * Add some explanations Signed-off-by: Patrick Hodoul <[email protected]>
1 parent eb8e338 commit 8dc5f6e

File tree

2 files changed

+152
-16
lines changed

2 files changed

+152
-16
lines changed

src/OpenColorIO/CPUProcessor.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -278,24 +278,12 @@ void FinalizeOpsForCPU(OpRcPtrVec & ops, const OpRcPtrVec & rawOps,
278278
ops.optimizeForBitdepth(in, out, oFlags);
279279
}
280280

281+
// The previous code could change the list of ops so an explicit check to empty is still needed.
281282
if(ops.empty())
282283
{
283-
// Support an empty list.
284-
285-
const double scale = GetBitDepthMaxValue(out) / GetBitDepthMaxValue(in);
286-
287-
if(scale==1.0f)
288-
{
289-
// Needs at least one op (even an identity one) as the input
290-
// and output buffers could be different.
291-
CreateIdentityMatrixOp(ops);
292-
}
293-
else
294-
{
295-
// Note: CreateScaleOp will not add an op if scale == 1.
296-
const double scale4[4] = {scale, scale, scale, scale};
297-
CreateScaleOp(ops, scale4, TRANSFORM_DIR_FORWARD);
298-
}
284+
// Needs at least one op (even an identity one) as the input and output buffers could be
285+
// different.
286+
CreateIdentityMatrixOp(ops);
299287
}
300288

301289
if (!((oFlags & OPTIMIZATION_NO_DYNAMIC_PROPERTIES) == OPTIMIZATION_NO_DYNAMIC_PROPERTIES))
@@ -310,6 +298,8 @@ void CPUProcessor::Impl::finalize(const OpRcPtrVec & rawOps,
310298
{
311299
AutoMutex lock(m_mutex);
312300

301+
// Get the ops of the color transformation without the bit-depth adjustments.
302+
313303
OpRcPtrVec ops;
314304
FinalizeOpsForCPU(ops, rawOps, in, out, oFlags);
315305

tests/cpu/Config_tests.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8198,3 +8198,149 @@ OCIO_ADD_TEST(Config, get_processor_alias)
81988198
OCIO::TRANSFORM_TYPE_FIXED_FUNCTION);
81998199
}
82008200
}
8201+
8202+
OCIO_ADD_TEST(Config, optimization_with_bitdepths)
8203+
{
8204+
// The unit test validates that the bit-depth conversion is correctly done for an empty list of
8205+
// ops i.e. the color transformation does nothing.
8206+
8207+
static constexpr char sFromSpace[] = "ACEScg";
8208+
static constexpr char sDiplay[] = "AdobeRGB";
8209+
static constexpr char sView[] = "raw";
8210+
8211+
static constexpr char CONFIG[] = { R"(ocio_profile_version: 2
8212+
environment: {}
8213+
search_path: "./"
8214+
roles:
8215+
data: Raw
8216+
default: Raw
8217+
scene_linear: ACEScg
8218+
8219+
file_rules:
8220+
- !<Rule> {name: Default, colorspace: default}
8221+
8222+
displays:
8223+
AdobeRGB:
8224+
- !<View> {name: Raw, colorspace: Raw}
8225+
8226+
colorspaces:
8227+
- !<ColorSpace>
8228+
name: ACEScg
8229+
to_reference: !<MatrixTransform> {matrix: [ 0.695452241357, 0.140678696470, 0.163869062172, 0, 0.044794563372, 0.859671118456, 0.095534318172, 0, -0.005525882558, 0.004025210306, 1.001500672252, 0, 0, 0, 0, 1 ]}
8230+
- !<ColorSpace>
8231+
name: Raw
8232+
isdata: true)" };
8233+
8234+
{
8235+
std::istringstream iss;
8236+
iss.str(CONFIG);
8237+
8238+
OCIO::ConstConfigRcPtr mOCIOCfg;
8239+
OCIO_CHECK_NO_THROW(mOCIOCfg = OCIO::Config::CreateFromStream(iss));
8240+
OCIO_CHECK_NO_THROW(mOCIOCfg->validate());
8241+
8242+
// Create the two processors.
8243+
8244+
OCIO::DisplayViewTransformRcPtr transform = OCIO::DisplayViewTransform::Create();
8245+
transform->setSrc(sFromSpace);
8246+
transform->setDisplay(sDiplay);
8247+
transform->setView(sView);
8248+
8249+
auto proc = mOCIOCfg->getProcessor(transform);
8250+
8251+
auto cpu1 = proc->getDefaultCPUProcessor();
8252+
auto cpu2 = proc->getOptimizedCPUProcessor(OCIO::BIT_DEPTH_F32, OCIO::BIT_DEPTH_UINT8, OCIO::OPTIMIZATION_DEFAULT);
8253+
8254+
// Declare all the buffers.
8255+
8256+
float inCol[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
8257+
float outCol1[4];
8258+
uint8_t outCol2[4];
8259+
8260+
// Wrap source and destination colors.
8261+
8262+
OCIO::PackedImageDesc descSrc(inCol, 1, 1, OCIO::CHANNEL_ORDERING_RGBA);
8263+
8264+
OCIO::PackedImageDesc descDst1(outCol1, 1, 1, OCIO::CHANNEL_ORDERING_RGBA);
8265+
OCIO::PackedImageDesc descDst2(outCol2, 1, 1, OCIO::CHANNEL_ORDERING_RGBA, OCIO::BIT_DEPTH_UINT8, 1, 4, 4);
8266+
8267+
cpu1->apply(descSrc, descDst1);
8268+
cpu2->apply(descSrc, descDst2);
8269+
8270+
// Check results.
8271+
8272+
OCIO_CHECK_EQUAL(outCol1[0], 0.5f);
8273+
OCIO_CHECK_EQUAL(outCol1[1], 0.5f);
8274+
OCIO_CHECK_EQUAL(outCol1[2], 0.5f);
8275+
OCIO_CHECK_EQUAL(outCol1[3], 1.0f);
8276+
8277+
OCIO_CHECK_EQUAL((uint32_t)outCol2[0], 128);
8278+
OCIO_CHECK_EQUAL((uint32_t)outCol2[1], 128);
8279+
OCIO_CHECK_EQUAL((uint32_t)outCol2[2], 128);
8280+
OCIO_CHECK_EQUAL((uint32_t)outCol2[3], 255);
8281+
}
8282+
8283+
{
8284+
std::istringstream iss;
8285+
iss.str(CONFIG);
8286+
8287+
OCIO::ConstConfigRcPtr mOCIOCfg;
8288+
OCIO_CHECK_NO_THROW(mOCIOCfg = OCIO::Config::CreateFromStream(iss));
8289+
OCIO_CHECK_NO_THROW(mOCIOCfg->validate());
8290+
8291+
// Setup viewing pipeline for proc1.
8292+
8293+
OCIO::DisplayViewTransformRcPtr transform = OCIO::DisplayViewTransform::Create();
8294+
transform->setSrc(sFromSpace);
8295+
transform->setDisplay(sDiplay);
8296+
transform->setView(sView);
8297+
OCIO::LegacyViewingPipelineRcPtr vp = OCIO::LegacyViewingPipeline::Create();
8298+
vp->setDisplayViewTransform(transform);
8299+
8300+
// Add Exposure / Contrast.
8301+
{
8302+
OCIO::ExposureContrastTransformRcPtr ex = OCIO::ExposureContrastTransform::Create();
8303+
ex->setStyle(OCIO::EXPOSURE_CONTRAST_LINEAR);
8304+
ex->setPivot(0.18);
8305+
ex->makeExposureDynamic();
8306+
ex->makeContrastDynamic();
8307+
ex->makeGammaDynamic();
8308+
vp->setLinearCC(ex);
8309+
}
8310+
8311+
// Create two processors 1: using viewing pipeline, 2: using just Display/View pair.
8312+
8313+
auto processor1 = vp->getProcessor(mOCIOCfg, mOCIOCfg->getCurrentContext());
8314+
auto processor2 = mOCIOCfg->getProcessor(sFromSpace, sDiplay, sView, OCIO::TRANSFORM_DIR_FORWARD);
8315+
8316+
// Get optimized processors.
8317+
8318+
auto cpu1 = processor1->getOptimizedCPUProcessor(OCIO::BIT_DEPTH_F32, OCIO::BIT_DEPTH_UINT8, OCIO::OPTIMIZATION_DEFAULT);
8319+
auto cpu2 = processor2->getOptimizedCPUProcessor(OCIO::BIT_DEPTH_F32, OCIO::BIT_DEPTH_UINT8, OCIO::OPTIMIZATION_DEFAULT);
8320+
8321+
// Declare all the buffers.
8322+
8323+
float inCol[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
8324+
uint8_t outCol1[3];
8325+
uint8_t outCol2[3];
8326+
8327+
// Wrap source and destination colors.
8328+
8329+
OCIO::PackedImageDesc descSrc(inCol, 1, 1, OCIO::CHANNEL_ORDERING_RGBA);
8330+
OCIO::PackedImageDesc descDst1(outCol1, 1, 1, OCIO::CHANNEL_ORDERING_RGB, OCIO::BIT_DEPTH_UINT8, 1, 3, 3);
8331+
OCIO::PackedImageDesc descDst2(outCol2, 1, 1, OCIO::CHANNEL_ORDERING_RGB, OCIO::BIT_DEPTH_UINT8, 1, 3, 3);
8332+
8333+
cpu1->apply(descSrc, descDst1);
8334+
cpu2->apply(descSrc, descDst2);
8335+
8336+
// Check results.
8337+
8338+
OCIO_CHECK_EQUAL((uint32_t)outCol1[0], 128);
8339+
OCIO_CHECK_EQUAL((uint32_t)outCol1[1], 128);
8340+
OCIO_CHECK_EQUAL((uint32_t)outCol1[2], 128);
8341+
8342+
OCIO_CHECK_EQUAL((uint32_t)outCol2[0], 128);
8343+
OCIO_CHECK_EQUAL((uint32_t)outCol2[1], 128);
8344+
OCIO_CHECK_EQUAL((uint32_t)outCol2[2], 128);
8345+
}
8346+
}

0 commit comments

Comments
 (0)