Skip to content

Commit 4177b2c

Browse files
authored
Unrecognized colorspace should throw rather than warn to stderr (#2954)
Currently, if an unrecognized colorspace string is encountered in MaterialXGenShader, it prints a warning to std::cerr. This is not ideal for several reasons: - The render proceeds and will have incorrect colors - Printing to stderr is difficult for applications to deal with - Raising an exception would be more in line with how MaterialX usually handles this type of situation This PR changes the behavior to raise ExceptionShaderGenError. This change required omitting the test file ocio_color_management.mtlx from the MaterialXGenMdl tests. The test was previously succeeding (when compiled with MATERIALX_BUILD_OCIO=ON), although it should not have. In addition, a change was made to improve the name of the color space conversion functions generated by the OcioColorManagementSystem. Previously the names only used the cacheIDs of the OCIO Processors, which was not very friendly to troubleshooting. Now the names are more similar to the "srcColorSpace_to_dstColorSpace" naming used by the DefaultColorManagmentSystem. This avoids a problem when MaterialX is compiled with the current OCIO main branch due to a change in the cacheID formatting. While testing, I noticed that the MaterialX createValidName function sometimes creates names with double underscores. OCIO's shader generator avoids this since (although some drivers accept it) it is technically undefined behavior. I added a sanitizeName function locally to work around this. As I worked further, I noticed that the GenShader tests were not actually testing color management, even though MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp explicitly tries to enable color management. The problem was that it was not ensuring that a targetColorSpace was set (as the rendering tests do). If that is empty, the color management shaders are never generated or tested. I ensured that is now being set. As a result, I needed to make sure the ocio_color_management.mtlx test file was omitted from the GenShader tests when OCIO is not enabled. Finally, I fixed a bug with the DefaultColorManagementSystem where the conversion from "lin_rec709_scene" to "lin_rec709" was not handled properly as a no-op. I added a test case for this in color_management.mtlx.
1 parent 2210beb commit 4177b2c

12 files changed

Lines changed: 83 additions & 7 deletions

File tree

resources/Materials/TestSuite/stdlib/color_management/color_management.mtlx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,5 +188,15 @@
188188
<input name="base_color" type="color3" nodename="color_lin_displayp3_color3" />
189189
</standard_surface>
190190
<output name="color_lin_displayp3_out" type="surfaceshader" nodename="color_lin_displayp3_standard_surface5" />
191+
<constant name="color_lin_rec709_scene" type="color4">
192+
<input name="value" type="color4" value="0.5, 0.0, 0.0, 1.0" colorspace="lin_rec709_scene" />
193+
</constant>
194+
<convert name="color_lin_rec709_scene_color3" type="color3">
195+
<input name="in" type="color4" nodename="color_lin_rec709_scene" />
196+
</convert>
197+
<standard_surface name="color_lin_rec709_scene_standard_surface" type="surfaceshader">
198+
<input name="base_color" type="color3" nodename="color_lin_rec709_scene_color3" />
199+
</standard_surface>
200+
<output name="color_lin_rec709_scene_out" type="surfaceshader" nodename="color_lin_rec709_scene_standard_surface" />
191201
</nodegraph>
192202
</materialx>

source/MaterialXGenShader/DefaultColorManagementSystem.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ NodeDefPtr DefaultColorManagementSystem::getNodeDef(const ColorSpaceTransform& t
6767

6868
string sourceSpace = COLOR_SPACE_REMAP.count(transform.sourceSpace) ? COLOR_SPACE_REMAP.at(transform.sourceSpace) : transform.sourceSpace;
6969
string targetSpace = COLOR_SPACE_REMAP.count(transform.targetSpace) ? COLOR_SPACE_REMAP.at(transform.targetSpace) : transform.targetSpace;
70+
71+
// After remapping, the transform may be a no-op (e.g. lin_rec709_scene -> lin_rec709).
72+
if (sourceSpace == targetSpace)
73+
{
74+
return _document->getNodeDef("ND_dot_" + transform.type.getName());
75+
}
76+
7077
string nodeName = sourceSpace + "_to_" + targetSpace;
7178

7279
for (NodeDefPtr nodeDef : _document->getMatchingNodeDefs(nodeName))

source/MaterialXGenShader/OcioColorManagementSystem.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,35 @@ NodeDefPtr OcioColorManagementSystemImpl::getNodeDef(const ColorSpaceTransform&
154154
return {};
155155
}
156156

157+
// Build a function name from the source/target color space names and the first
158+
// six characters of the cache ID. Each name component is sanitized individually:
159+
// invalid characters are replaced with underscores and consecutive underscores are
160+
// collapsed to one so that OCIO's own identifier normalizer cannot produce a
161+
// different name than the one we register on the node def.
162+
auto sanitizeName = [](const string& s) -> string
163+
{
164+
string result = createValidName(s);
165+
string collapsed;
166+
bool prevUnderscore = false;
167+
for (char c : result)
168+
{
169+
if (c == '_')
170+
{
171+
if (!prevUnderscore)
172+
collapsed += c;
173+
prevUnderscore = true;
174+
}
175+
else
176+
{
177+
collapsed += c;
178+
prevUnderscore = false;
179+
}
180+
}
181+
return collapsed;
182+
};
157183
static const auto NODE_NAME = string{ "ocio_color_conversion" };
158-
const auto functionName = NODE_NAME + "_" + processor->getCacheID();
184+
const string cacheID = processor->getCacheID();
185+
const auto functionName = NODE_NAME + "_" + sanitizeName(sourceColorSpace) + "_to_" + sanitizeName(targetColorSpace) + "_" + cacheID.substr(0, 6);
159186
const auto implName = OcioColorManagementSystem::IMPL_PREFIX + functionName + "_" + transform.type.getName();
160187
const auto nodeDefName = ND_PREFIX + functionName + "_" + transform.type.getName();
161188
auto nodeDef = document->getNodeDef(nodeDefName);

source/MaterialXGenShader/ShaderGraph.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
#include <MaterialXTrace/Tracing.h>
1414

15-
#include <iostream>
1615
#include <queue>
1716

1817
MATERIALX_NAMESPACE_BEGIN
@@ -1227,8 +1226,8 @@ void ShaderGraph::populateColorTransformMap(ColorManagementSystemPtr colorManage
12271226
}
12281227
else
12291228
{
1230-
std::cerr << "Unsupported color space transform from " <<
1231-
sourceColorSpace << " to " << targetColorSpace << std::endl;
1229+
throw ExceptionShaderGenError("Unsupported color space transform from '" +
1230+
sourceColorSpace + "' to '" + targetColorSpace + "'.");
12321231
}
12331232
}
12341233
}

source/MaterialXGraphEditor/RenderView.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@ void RenderView::reloadShaders()
587587
std::cerr << error << std::endl;
588588
}
589589
}
590+
catch (std::exception& e) // ExceptionShaderGenError, etc.
591+
{
592+
std::cerr << e.what() << std::endl;
593+
}
590594

591595
_materials.clear();
592596
}

source/MaterialXTest/MaterialXGenMdl/GenMdl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ class MdlShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
7676
// Ignore certain .mtlx files
7777
void addSkipFiles() override
7878
{
79-
// no additional files are skipped
79+
// ocio_color_management.mtlx uses color spaces which require OCIO and is not supported by MDL.
80+
_skipFiles.insert("ocio_color_management.mtlx");
8081
ShaderGeneratorTester::addSkipFiles();
8182
}
8283

source/MaterialXTest/MaterialXGenMsl/GenMsl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class MslShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
4545
{
4646
// To skip specific files for this render target, add them as below:
4747
// _skipFiles.insert("example.mtlx");
48+
ParentClass::addSkipFiles();
4849
}
4950

5051
void setupDependentLibraries() override

source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,12 @@ void ShaderGeneratorTester::validate(const mx::GenOptions& generateOptions, cons
741741
context.getOptions().targetDistanceUnit = _defaultDistanceUnit;
742742
}
743743

744+
// Define target color space if required
745+
if (context.getOptions().targetColorSpaceOverride.empty())
746+
{
747+
context.getOptions().targetColorSpaceOverride = "lin_rec709";
748+
}
749+
744750
// Check if a binding context has been set.
745751
bool bindingContextUsed = _userData.count(mx::HW::USER_DATA_BINDING_CONTEXT) > 0;
746752

source/MaterialXTest/MaterialXGenShader/GenShaderUtil.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,13 @@ class ShaderGeneratorTester
199199
virtual void setTestStages() = 0;
200200

201201
// Add files in to not examine
202-
virtual void addSkipFiles() { };
202+
virtual void addSkipFiles()
203+
{
204+
#ifndef MATERIALX_BUILD_OCIO
205+
// ocio_color_management.mtlx uses color spaces which require OCIO.
206+
_skipFiles.insert("ocio_color_management.mtlx");
207+
#endif
208+
};
203209

204210
// Add nodedefs to not examine
205211
virtual void addSkipNodeDefs() { };

source/MaterialXTest/MaterialXGenSlang/GenSlang.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class SlangShaderGeneratorTester : public GenShaderUtil::ShaderGeneratorTester
3030
}
3131

3232
// Ignore trying to create shader code for displacementshaders
33+
void addSkipFiles() override
34+
{
35+
// ocio_color_management.mtlx uses color spaces which require OCIO and is not supported by Slang.
36+
_skipFiles.insert("ocio_color_management.mtlx");
37+
ParentClass::addSkipFiles();
38+
}
39+
3340
void addSkipNodeDefs() override
3441
{
3542
_skipNodeDefs.insert("ND_displacement_float");

0 commit comments

Comments
 (0)