diff --git a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp index d248211f75..7309982489 100644 --- a/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp +++ b/source/MaterialXGenShader/Nodes/SourceCodeNode.cpp @@ -71,11 +71,18 @@ void SourceCodeNode::emitFunctionDefinition(const ShaderNode&, GenContext& conte { BEGIN_SHADER_STAGE(stage, Stage::PIXEL) // Emit function definition for non-inlined functions - if (!_inlined && !_functionSource.empty()) + if (!_functionSource.empty()) { - const ShaderGenerator& shadergen = context.getShaderGenerator(); - shadergen.emitBlock(_functionSource, _sourceFilename, context, stage); - shadergen.emitLineBreak(stage); + if (!_sourceFilename.isEmpty()) + { + stage.addSourceDependency(_sourceFilename); + } + if (!_inlined) + { + const ShaderGenerator& shadergen = context.getShaderGenerator(); + shadergen.emitBlock(_functionSource, _sourceFilename, context, stage); + shadergen.emitLineBreak(stage); + } } END_SHADER_STAGE(stage, Stage::PIXEL) } diff --git a/source/MaterialXGenShader/ShaderStage.cpp b/source/MaterialXGenShader/ShaderStage.cpp index 34e2eb4b09..507092df58 100644 --- a/source/MaterialXGenShader/ShaderStage.cpp +++ b/source/MaterialXGenShader/ShaderStage.cpp @@ -340,6 +340,14 @@ void ShaderStage::addInclude(const FilePath& includeFilename, const FilePath& so } } +void ShaderStage::addSourceDependency(const FilePath& file) +{ + if (!_sourceDependencies.count(file)) + { + _sourceDependencies.insert(file); + } +} + void ShaderStage::addFunctionDefinition(const ShaderNode& node, GenContext& context) { const ShaderNodeImpl& impl = node.getImplementation(); diff --git a/source/MaterialXGenShader/ShaderStage.h b/source/MaterialXGenShader/ShaderStage.h index 395f847370..94401dc469 100644 --- a/source/MaterialXGenShader/ShaderStage.h +++ b/source/MaterialXGenShader/ShaderStage.h @@ -198,6 +198,18 @@ class MX_GENSHADER_API ShaderStage { return _outputs; } + + /// Return a set of all include files + const StringSet& getIncludes() const + { + return _includes; + } + + /// Return a set of all source dependencies + const StringSet& getSourceDependencies() const + { + return _sourceDependencies; + } /// Start a new scope using the given bracket type. void beginScope(Syntax::Punctuation punc = Syntax::CURLY_BRACKETS); @@ -229,6 +241,9 @@ class MX_GENSHADER_API ShaderStage /// Add the contents of an include file if not already present. void addInclude(const FilePath& includeFilename, const FilePath& sourceFilename, GenContext& context); + /// Add a source file dependency for dependency tracking purposes + void addSourceDependency(const FilePath& file); + /// Add a value. template void addValue(const T& value) @@ -272,6 +287,9 @@ class MX_GENSHADER_API ShaderStage /// Set of include files that has been included. StringSet _includes; + /// Set of source file dependencies from source code nodes + StringSet _sourceDependencies; + /// Set of hash ID's for functions that has been defined. std::set _definedFunctions; diff --git a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp index 00ecad1318..b46f66ce89 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShader.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShader.cpp @@ -321,3 +321,52 @@ TEST_CASE("GenShader: Deterministic Generation", "[genshader]") } #endif } + +void checkPixelDependencies(mx::DocumentPtr libraries, mx::GenContext& context) +{ + const mx::FilePath testFile = mx::FilePath::getCurrentPath() / mx::FilePath("resources/Materials/Examples/GltfPbr/gltf_pbr_boombox.mtlx"); + const mx::string testElement = "Material_boombox"; + + mx::DocumentPtr testDoc = mx::createDocument(); + mx::readFromXmlFile(testDoc, testFile); + testDoc->importLibrary(libraries); + + mx::ElementPtr element = testDoc->getChild(testElement); + CHECK(element); + + mx::ShaderPtr shader = context.getShaderGenerator().generate(testElement, element, context); + std::set dependencies = shader->getStage("pixel").getSourceDependencies(); + for (auto dependency : dependencies) { + mx::FilePath path(dependency); + REQUIRE(path.exists() == true); + } +} + +TEST_CASE("GenShader: Track Dependencies", "[genshader]") +{ + mx::DocumentPtr libraries = mx::createDocument(); + mx::FileSearchPath searchPath(mx::FilePath::getCurrentPath()); + mx::loadLibraries({ "libraries/targets", "libraries/stdlib", "libraries/pbrlib", "libraries/bxdf" }, searchPath, libraries); + +#ifdef MATERIALX_BUILD_GEN_GLSL + { + mx::GenContext context(mx::GlslShaderGenerator::create()); + context.registerSourceCodeSearchPath(searchPath); + checkPixelDependencies(libraries, context); + } +#endif +#ifdef MATERIALX_BUILD_GEN_OSL + { + mx::GenContext context(mx::OslShaderGenerator::create()); + context.registerSourceCodeSearchPath(searchPath); + checkPixelDependencies(libraries, context); + } +#endif +#ifdef MATERIALX_BUILD_GEN_MDL + { + mx::GenContext context(mx::MdlShaderGenerator::create()); + context.registerSourceCodeSearchPath(searchPath); + checkPixelDependencies(libraries, context); + } +#endif +} diff --git a/source/PyMaterialX/PyMaterialXGenShader/PyShaderStage.cpp b/source/PyMaterialX/PyMaterialXGenShader/PyShaderStage.cpp index eb27316697..ebb45737b0 100644 --- a/source/PyMaterialX/PyMaterialXGenShader/PyShaderStage.cpp +++ b/source/PyMaterialX/PyMaterialXGenShader/PyShaderStage.cpp @@ -42,5 +42,7 @@ void bindPyShaderStage(py::module& mod) .def("getConstantBlock", static_cast(&mx::ShaderStage::getConstantBlock)) .def("getUniformBlocks", &mx::ShaderStage::getUniformBlocks) .def("getInputBlocks", &mx::ShaderStage::getInputBlocks) + .def("getIncludes", &mx::ShaderStage::getIncludes) + .def("getSourceDependencies", &mx::ShaderStage::getSourceDependencies) .def("getOutputBlocks", &mx::ShaderStage::getOutputBlocks); }