Skip to content

Commit

Permalink
Track File Dependencies in ShaderStage (AcademySoftwareFoundation#1032)
Browse files Browse the repository at this point in the history
This change allows an application to retrieve file dependencies from generated shaders caused by shader includes (via ShaderStage::addInclude) and SourceCodeNode source blocks taken from a file.

We add ShaderStage::getIncludes, ShaderStage::addSourceDependency, and ShaderStage::getSourceDependencies. SourceCodeNode is modified to call addSourceDependency.
  • Loading branch information
solid-angle authored Jul 26, 2022
1 parent c517cf1 commit 79404a4
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 4 deletions.
15 changes: 11 additions & 4 deletions source/MaterialXGenShader/Nodes/SourceCodeNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
8 changes: 8 additions & 0 deletions source/MaterialXGenShader/ShaderStage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
18 changes: 18 additions & 0 deletions source/MaterialXGenShader/ShaderStage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<typename T>
void addValue(const T& value)
Expand Down Expand Up @@ -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<size_t> _definedFunctions;

Expand Down
49 changes: 49 additions & 0 deletions source/MaterialXTest/MaterialXGenShader/GenShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::string> 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
}
2 changes: 2 additions & 0 deletions source/PyMaterialX/PyMaterialXGenShader/PyShaderStage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,7 @@ void bindPyShaderStage(py::module& mod)
.def("getConstantBlock", static_cast<mx::VariableBlock& (mx::ShaderStage::*)()>(&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);
}

0 comments on commit 79404a4

Please sign in to comment.