From 15bd005b1485c453707856316c67f4e61062ac1b Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:49:50 +0200 Subject: [PATCH 1/7] Mark unused source-template inputs Detect whether graph inputs are referenced by inline MDL source expressions, and annotate unused root and compound parameters. Reduces C183 warning count from 74 to 56. --- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 16 +++++++++++++++- source/MaterialXGenMdl/MdlShaderGenerator.h | 3 +++ source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 3 ++- .../MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp | 6 ++++++ source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h | 3 +++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index def8c52a1e..c2bd784769 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -583,6 +583,20 @@ void disconnectTransmissionIor(ShaderGraph* g) } // anonymous namespace +bool MdlShaderGenerator::isInputUsed(const ShaderGraphInputSocket& input) const +{ + for (const ShaderInput* connection : input.getConnections()) + { + const ShaderNodeImpl& implementation = connection->getNode()->getImplementation(); + const SourceCodeNodeMdl* sourceCode = dynamic_cast(&implementation); + if (!sourceCode || sourceCode->isInputUsed(*connection)) + { + return true; + } + } + return false; +} + ShaderPtr MdlShaderGenerator::createShader(const string& name, ElementPtr element, GenContext& context) const { // Create the root shader graph @@ -690,7 +704,7 @@ void emitInputAnnotations(const MdlShaderGenerator& _this, const ShaderPort* var _this.emitString(_this.getSyntax().getIndentation() + mtlxParameterPathAnno, stage); const ShaderGraphInputSocket* input = static_cast(variable); - if (input->getConnections().empty()) + if (!_this.isInputUsed(*input)) { _this.emitString(",", stage); _this.emitLineEnd(stage, false); diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.h b/source/MaterialXGenMdl/MdlShaderGenerator.h index bbf96030ee..046245b2f5 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.h +++ b/source/MaterialXGenMdl/MdlShaderGenerator.h @@ -109,6 +109,9 @@ class MX_GENMDL_API MdlShaderGenerator : public ShaderGenerator /// Emit type definitions for all data types that need them. void emitTypeDefinitions(GenContext& context, ShaderStage& stage) const override; + /// Return whether a graph input is referenced by generated MDL code. + bool isInputUsed(const ShaderGraphInputSocket& input) const; + protected: // Create and initialize a new MDL shader for shader generation. ShaderPtr createShader(const string& name, ElementPtr element, GenContext& context) const; diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index ea15eca7c2..842536e170 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -181,6 +181,7 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& context, ShaderStage& stage) const { const ShaderGenerator& shadergen = context.getShaderGenerator(); + const MdlShaderGenerator& mdlShadergen = static_cast(shadergen); const MdlSyntax& syntax = static_cast(shadergen.getSyntax()); if (!_returnStruct.empty()) @@ -256,7 +257,7 @@ void CompoundNodeMdl::emitFunctionSignature(const ShaderNode&, GenContext& conte shadergen.emitLineBegin(stage); shadergen.emitString(qualifier + type + " " + input->getVariable() + " = " + value, stage); - if (input->getConnections().empty()) + if (!mdlShadergen.isInputUsed(*input)) { shadergen.emitLineEnd(stage, false); shadergen.emitLine("[[", stage, false); diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index b89c319aec..58c6ab13ab 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -24,6 +24,12 @@ ShaderNodeImplPtr SourceCodeNodeMdl::create() return std::make_shared(); } +bool SourceCodeNodeMdl::isInputUsed(const ShaderInput& input) const +{ + const string marker = "{{" + input.getName() + "}}"; + return _functionSource.find(marker) != string::npos; +} + void SourceCodeNodeMdl::resolveSourceCode(const InterfaceElement& /*element*/, GenContext& /*context*/) { // Initialize without fetching the source code from file. diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h index 7f595704cc..234d5ec312 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h @@ -24,6 +24,9 @@ class MX_GENMDL_API SourceCodeNodeMdl : public SourceCodeNode void emitFunctionDefinition(const ShaderNode&, GenContext&, ShaderStage&) const override; void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; + /// Return whether an input is referenced by the inline source expression. + bool isInputUsed(const ShaderInput& input) const; + protected: void resolveSourceCode(const InterfaceElement& element, GenContext& context) override; string _returnStruct; From 773d66c3a089e6f6b78c65a4ece620ef58e75e6b Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:00:29 +0200 Subject: [PATCH 2/7] Annotate unused unrolled material outputs Compound material outputs must be unrolled into separate MDL calls. Annotate result temporaries whose corresponding output is disconnected. Reduces C350 warning count from 129 to 127. --- source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp index 842536e170..66755e4556 100644 --- a/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/CompoundNodeMdl.cpp @@ -122,6 +122,7 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte continue; const std::string& fieldName = outputSocket->getName(); + const ShaderOutput* nodeOutput = node.getOutput(fieldName); // Emit the struct field. const string& outputType = syntax.getTypeName(outputSocket->getType()); @@ -142,6 +143,10 @@ void CompoundNodeMdl::emitFunctionCall(const ShaderNode& node, GenContext& conte // End function call shadergen.emitString(")", stage); + if (!nodeOutput || nodeOutput->getConnections().empty()) + { + shadergen.emitString(" [[ anno::unused() ]]", stage); + } shadergen.emitLineEnd(stage); } From d16b9b371064c86e9c090488e1a5c53fa7d6ec2a Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:12:50 +0200 Subject: [PATCH 3/7] Omit convolution weights for height-to-normal Height-to-normal uses a fixed Sobel kernel and does not require the generic box and Gaussian filter-weight arrays. Reduces C350 warning count from 127 to 119. --- source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp | 4 ++++ source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp index 12b38a33db..f38cceb517 100644 --- a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.cpp @@ -32,6 +32,10 @@ ShaderNodeImplPtr HeightToNormalNodeMdl::create() return std::make_shared(); } +void HeightToNormalNodeMdl::createVariables(const ShaderNode&, GenContext&, Shader&) const +{ +} + void HeightToNormalNodeMdl::computeSampleOffsetStrings(const string& sampleSizeName, const string& offsetTypeString, unsigned int, StringVec& offsetStrings) const { diff --git a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h index 1c00c2a20e..6b084f88fd 100644 --- a/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/HeightToNormalNodeMdl.h @@ -18,6 +18,9 @@ class MX_GENMDL_API HeightToNormalNodeMdl : public ConvolutionNode public: static ShaderNodeImplPtr create(); + /// Height-to-normal uses a fixed Sobel kernel and needs no filter-weight variables. + void createVariables(const ShaderNode&, GenContext&, Shader&) const override; + void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; protected: From f06df74c1a315cee55e6897a3b26937f1508739a Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:44:14 +0200 Subject: [PATCH 4/7] Limit unrolled closures to upstream texture nodes When emitting an unrolled compound output, traverse that output's dependencies and emit only its upstream texture nodes. Reduces C350 warnings count from 119 to ~117. --- .../Nodes/ClosureCompoundNodeMdl.cpp | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp index b5c16456c0..822fd5406a 100644 --- a/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ClosureCompoundNodeMdl.cpp @@ -11,6 +11,8 @@ #include +#include + MATERIALX_NAMESPACE_BEGIN ShaderNodeImplPtr ClosureCompoundNodeMdl::create() @@ -38,7 +40,7 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC if (!_returnStruct.empty() && _unrollReturnStructMembers) { // make sure the upstream definitions are known - for (const ShaderGraphOutputSocket* outputSocket : _rootGraph->getOutputSockets()) + for (ShaderGraphOutputSocket* outputSocket : _rootGraph->getOutputSockets()) { if (!outputSocket->getConnection()) continue; @@ -65,9 +67,20 @@ void ClosureCompoundNodeMdl::emitFunctionDefinition(const ShaderNode& node, GenC // Function body. shadergen.emitScopeBegin(stage); - // Emit all texturing nodes. These are inputs to the - // closure nodes and need to be emitted first. - shadergen.emitFunctionCalls(*_rootGraph, context, stage, ShaderNode::Classification::TEXTURE); + // Emit only texturing nodes upstream of this output field. + std::set upstreamNodes; + for (ShaderGraphEdge edge : ShaderGraph::traverseUpstream(outputSocket->getConnection())) + { + upstreamNodes.insert(edge.upstream->getNode()); + } + for (const ShaderNode* child : _rootGraph->getNodes()) + { + if (upstreamNodes.count(child) && + child->hasClassification(ShaderNode::Classification::TEXTURE)) + { + shadergen.emitFunctionCall(*child, context, stage); + } + } // Emit function calls for internal closures nodes connected to the graph sockets. // These will in turn emit function calls for any dependent closure nodes upstream. From de93c856e7f2470cc8f52dd63eb11d41f2336d51 Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:51:25 +0200 Subject: [PATCH 5/7] Skip redundant height-to-normal image samples Omit the ordinary image sample when all consumers are height-to-normal nodes, while retaining the explicitly offset samples used by the Sobel filter. Reduces C350 warnings count from ~117 to ~114. The cumulative warning count is reduced from 203 to 20. --- source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp index 502711fe01..24087241d0 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp @@ -4,6 +4,7 @@ // #include +#include #include #include #include @@ -37,6 +38,28 @@ void ImageNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& context DEFINE_SHADER_STAGE(stage, Stage::PIXEL) { ShaderNode& node = const_cast(_node); + + ShaderOutput* output = node.getOutput(); + string outputSuffix; + context.getOutputSuffix(output, outputSuffix); + if (outputSuffix.empty() && output && !output->getConnections().empty()) + { + bool sampledOnly = true; + for (const ShaderInput* connection : output->getConnections()) + { + const ShaderNodeImpl& downstreamImpl = connection->getNode()->getImplementation(); + if (!dynamic_cast(&downstreamImpl)) + { + sampledOnly = false; + break; + } + } + if (sampledOnly) + { + return; + } + } + ShaderInput* flipUInput = node.getInput(ImageNodeMdl::FLIP_V); ValuePtr value = TypedValue::createValue(context.getOptions().fileTextureVerticalFlip); if (flipUInput) From 74a8a0fc87bf63de6c03ad2aeb204c2249a5043b Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 15 Sep 2026 10:52:59 +0200 Subject: [PATCH 6/7] Fix crash with shader graphs. Fix handling of non-inlined source code nodes. --- source/MaterialXGenMdl/MdlShaderGenerator.cpp | 11 ++++++++--- source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp | 5 +++++ source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h | 2 +- source/MaterialXGenShader/ShaderNodeImpl.h | 6 ++++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/source/MaterialXGenMdl/MdlShaderGenerator.cpp b/source/MaterialXGenMdl/MdlShaderGenerator.cpp index c2bd784769..f50dd7fddc 100644 --- a/source/MaterialXGenMdl/MdlShaderGenerator.cpp +++ b/source/MaterialXGenMdl/MdlShaderGenerator.cpp @@ -587,9 +587,14 @@ bool MdlShaderGenerator::isInputUsed(const ShaderGraphInputSocket& input) const { for (const ShaderInput* connection : input.getConnections()) { - const ShaderNodeImpl& implementation = connection->getNode()->getImplementation(); - const SourceCodeNodeMdl* sourceCode = dynamic_cast(&implementation); - if (!sourceCode || sourceCode->isInputUsed(*connection)) + const ShaderNode* node = connection->getNode(); + if (node->isAGraph()) + { + return true; + } + + const ShaderNodeImpl& implementation = node->getImplementation(); + if (implementation.isInputUsed(*connection)) { return true; } diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp index 58c6ab13ab..38895870a7 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.cpp @@ -26,6 +26,11 @@ ShaderNodeImplPtr SourceCodeNodeMdl::create() bool SourceCodeNodeMdl::isInputUsed(const ShaderInput& input) const { + if (!_inlined) + { + return true; + } + const string marker = "{{" + input.getName() + "}}"; return _functionSource.find(marker) != string::npos; } diff --git a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h index 234d5ec312..9af681e585 100644 --- a/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h +++ b/source/MaterialXGenMdl/Nodes/SourceCodeNodeMdl.h @@ -25,7 +25,7 @@ class MX_GENMDL_API SourceCodeNodeMdl : public SourceCodeNode void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage) const override; /// Return whether an input is referenced by the inline source expression. - bool isInputUsed(const ShaderInput& input) const; + bool isInputUsed(const ShaderInput& input) const override; protected: void resolveSourceCode(const InterfaceElement& element, GenContext& context) override; diff --git a/source/MaterialXGenShader/ShaderNodeImpl.h b/source/MaterialXGenShader/ShaderNodeImpl.h index 1a365a2862..89bf64da2e 100644 --- a/source/MaterialXGenShader/ShaderNodeImpl.h +++ b/source/MaterialXGenShader/ShaderNodeImpl.h @@ -79,6 +79,12 @@ class MX_GENSHADER_API ShaderNodeImpl /// or returns nullptr otherwise. virtual ShaderGraph* getGraph() const; + /// Return whether an input is referenced by the generated source code. + virtual bool isInputUsed(const ShaderInput& /*input*/) const + { + return true; + } + /// Returns true if an input is editable by users. /// Editable inputs are allowed to be published as shader uniforms /// and hence must be presentable in a user interface. From fbb2dd0f07ea6b30ec32ca70defbd75386138ae3 Mon Sep 17 00:00:00 2001 From: Joachim Reichel <43646584+jreichel-nvidia@users.noreply.github.com> Date: Tue, 15 Sep 2026 14:37:02 +0200 Subject: [PATCH 7/7] Fix another crash with shader graphs. --- source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp index 24087241d0..872ada63bf 100644 --- a/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp +++ b/source/MaterialXGenMdl/Nodes/ImageNodeMdl.cpp @@ -47,8 +47,9 @@ void ImageNodeMdl::emitFunctionCall(const ShaderNode& _node, GenContext& context bool sampledOnly = true; for (const ShaderInput* connection : output->getConnections()) { - const ShaderNodeImpl& downstreamImpl = connection->getNode()->getImplementation(); - if (!dynamic_cast(&downstreamImpl)) + const ShaderNode* downstreamNode = connection->getNode(); + if (downstreamNode->isAGraph() || + !dynamic_cast(&downstreamNode->getImplementation())) { sampledOnly = false; break;