Skip to content

Commit 943b761

Browse files
committed
Update OSL Network generator to provide parity with OSL Source generator.
This is a pretty large commit, but most of it is all pretty intertwined, so I'll do my best to outline here all the different changes. ### LibsToOso * The tool now supports selecting using the NodeDef name or the Implementation name as the basis for the name of the new OSL Network generator implementation and corresponding OSO. * OSL code and corresponding OSO is now generated directly from the NodeDef element. * `implname` functionality added is used to define the renamed ports. * NodeGraph elements can now be skipped during processing. ### OSLNetworkGenerator * Generator now directly inherits from `ShaderGenerator` as there is no common functionality shared with the `OSLShaderGenerator`. * Provides API to compile OSL source, and also to generate a Shader from a NodeDef element, this is consolidated from the `LibsToOso` tool source. * The generator can now create a new ShaderNodeImpl object on demand (and the corresponding compiled OSO file) if a locally defined OSL Source Implementation element is discovered. This includes correctly constructing an OSL Source generator object with all the corresponding custom types defined to allow for the correct shader generation to occur. * `liboslcomp` can be optionally used for the on-demand compilation for better performance, and avoids writing the shader source to disk to compile. * New `ShaderGraph::flattenGraph()` function is used to correctly expand any locally defined NodeGraph elements in to the corresponding nodes. We do not on-demand compile non-functional NodeGraph elements in to OSOs as they do not have corresponding NodeDef elements to fully name and decorate the interface. Once the `ShaderGraph` is flattened then we are left with a fully expanded graph of individual nodes. * `OslNetworkSyntax` has been refactored. * It no longer has any reserved words, as the grammar used to describe the network has no restrictions on words that are used. * Parameter value emitting code has been refactored to better support the "built-in" struct types more cleanly, and removes dependency on the OSL Source syntax, as they are fundamentally two different exports. Including better error handling for types that do not have direct parameter export. ### MaterialXGenShader * New API method `GenContext::getSourceCodeSearchPath()`, needed to allow dynamic construction of derived generators that share the source code search path. * New `GenOptions` option `oslTempOsoPath` to allow control over where on-demand OSOs are compiled to. If unspecified the system will fallback to a uniquely generated temp directory in the system temporary directory. * Support added for `implname` attribute during shader generation. This is described in the specification, but not yet implemented. During OSL source generation when compiling the OSOs its possible input names such as `normal` may be modified to avoid clashes with reserved words. Adding `implname` support allows this to be described in the generated Implementation elements and respected during OSL Network generation. New `getPortName()` function is added in support for the implementation of this feature. This is also needs to be stored in two separate classes, the actual implementation can be either a `ShaderGraph` or a `ShaderNodeImpl`. * New API method `ShaderGraph::flattenGraph()` will walk the graph and expand any `CompoundNode` entities discovered. Care is taken to generate unique names for newly generated nodes by prefixing the names with the name of the prior parent `CompoundNode`, and also to ensure all connections are retained. * `ShaderGraph::create()` can now accept and populate the created graph directly from a NodeDef element, which is simpler than the current Node source, as there are no local modifications. * `Syntax` base class now tracks custom registered syntaxes so they can be easily queried. This is necessary to support dynamic creation of a derived generator, specifically to allow the OSL Network generator to create the OSL Source generator for on-demand compilation of locally defined nodes. Other supporting changes are outlined below. ### Cmake * Add CMake option to control if NodeGraph implementations are compiled down to OSOs, or left as NodeGraphs. ### MaterialXFormat * Add optional `recursive` argument to FilePath::createDirectory(), to allow for recursive directory creation if necessary. * Add API to FilePath to return the system temporary directory, as well as create a new temporary directory. This is used for on-the-fly compilation of OSL source implementation to OSOs if defined locally in a document and not in a pre-compiled standard library. * Add a new `createDirectories` option to XmlWriteOptions to allow for any necessary directories to be created while writing a new file. ### MaterialXTest/MaterialXRenderOsl * Add new test specific implementations for tangent and bitangent nodes for the OSL Network generator. These may become obsolete if the OSL render testing moves to using the OBJ file (see XXXX). * Update the OSL Network scene template to align the cameras after the OSL Source template was changed. * Remove the OSL Network specific tests that were skipped - we now have complete one-to-one parity with OSL Source generator. * Write fully expanded paths in to the template file for easier testing. * Introduce string processing to the command string that needs to be embedded in a legal XML file to replace illegal XML characters `<` and `>`.
1 parent 3bd5fa9 commit 943b761

33 files changed

Lines changed: 1296 additions & 565 deletions

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ option(MATERIALX_BUILD_OCIO "Build OpenColorIO support for shader generators." O
5151
option(MATERIALX_BUILD_TESTS "Build unit tests." OFF)
5252
option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF)
5353
option(MATERIALX_BUILD_OSOS "Build OSL .oso's of standard library shaders for the OSL Network generator" OFF)
54+
option(MATERIALX_BUILD_NODEGRAPH_OSOS "Build NodeGraphs as OSOs, if disabled then NodeGraphs are not compiled as OSOs " OFF)
5455

5556
option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF)
5657
option(MATERIALX_BUILD_DATA_LIBRARY "Build generated products from the MaterialX data library." OFF)

libraries/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ if(MATERIALX_BUILD_DATA_LIBRARY)
3535

3636
set(SENTINEL_FILE ${CMAKE_CURRENT_BINARY_DIR}/buildosos.sentinel)
3737

38+
set(SKIP_BUILDING_NODEGRAPHS "")
39+
if (NOT MATERIALX_BUILD_NODEGRAPH_OSOS)
40+
set(SKIP_BUILDING_NODEGRAPHS "--skipConvertingNodegraphs")
41+
endif()
42+
3843
add_custom_command(
3944
OUTPUT ${SENTINEL_FILE}
4045
COMMAND touch ${SENTINEL_FILE}
@@ -46,7 +51,7 @@ if(MATERIALX_BUILD_DATA_LIBRARY)
4651
--oslCompilerPath ${MATERIALX_OSL_BINARY_OSLC}
4752
--oslIncludePath ${MATERIALX_OSL_INCLUDE_PATH}
4853
--libraryRelativeOsoPath libraries/targets/genoslnetwork/osos
49-
--removeNdPrefix true
54+
${SKIP_BUILDING_NODEGRAPHS}
5055
DEPENDS ${MATERIALX_DATA_LIBRARY_SOURCE_FILES} MaterialXGenOsl_LibsToOso
5156
)
5257

resources/Materials/TestSuite/_options.mtlx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
<!-- List of document paths for render tests -->
6565
<input name="renderTestPaths" type="string" value="resources/Materials/Examples/StandardSurface,resources/Materials/TestSuite/stdlib/convolution,resources/Materials/TestSuite/stdlib/color_management,resources/Materials/TestSuite/stdlib/procedural,resources/Materials/TestSuite/pbrlib/surfaceshader,resources/Materials/TestSuite/nprlib,resources/Materials/TestSuite/pbrlib/bsdf" />
66+
<!-- <input name="renderTestPaths" type="string" value="resources/Materials/Examples,resources/Materials/TestSuite" />-->
6667

6768
<!-- Enable reference quality rendering.
6869
This option enables higher sample counts and supersampling in render tests,

source/MaterialXFormat/File.cpp

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
#include <array>
3131
#include <cctype>
3232
#include <cerrno>
33-
#include <cstring>
33+
// #include <cstring>
34+
#include <random>
35+
#include <filesystem>
3436

3537
MATERIALX_NAMESPACE_BEGIN
3638

@@ -278,8 +280,12 @@ FilePathVec FilePath::getSubDirectories() const
278280
return dirs;
279281
}
280282

281-
void FilePath::createDirectory() const
283+
void FilePath::createDirectory(bool recursive) const
282284
{
285+
if (recursive && !getParentPath().isDirectory())
286+
{
287+
getParentPath().createDirectory(recursive);
288+
}
283289
#if defined(_WIN32)
284290
_mkdir(asString().c_str());
285291
#else
@@ -377,4 +383,58 @@ FileSearchPath getEnvironmentPath(const string& sep)
377383
return FileSearchPath(searchPathEnv, sep);
378384
}
379385

386+
FilePath FilePath::createTemporaryDirectory(const FilePath& parentDir)
387+
{
388+
// Get the parent directory - use system temp if empty
389+
FilePath tempParent = parentDir;
390+
if (tempParent.isEmpty())
391+
{
392+
tempParent = getSystemTemporaryDirectory();
393+
}
394+
395+
// Ensure parent directory exists
396+
if (!tempParent.exists())
397+
{
398+
tempParent.createDirectory(true);
399+
}
400+
401+
if (!tempParent.isDirectory())
402+
{
403+
throw Exception("Parent path is not a directory: " + tempParent.asString());
404+
}
405+
406+
// Generate a unique temporary directory name using std::filesystem
407+
std::random_device rd;
408+
std::mt19937 gen(rd());
409+
std::uniform_int_distribution<> dis(100000, 999999);
410+
411+
constexpr int maxAttempts = 1000;
412+
for (int attempt = 0; attempt < maxAttempts; ++attempt)
413+
{
414+
string tempDirName = "materialx_tmp_" + std::to_string(dis(gen));
415+
FilePath tempDirPath = tempParent / tempDirName;
416+
417+
if (!tempDirPath.isDirectory())
418+
{
419+
tempDirPath.createDirectory(true);
420+
return tempDirPath;
421+
}
422+
}
423+
424+
throw Exception("Failed to create temporary directory after " + std::to_string(maxAttempts) + " attempts");
425+
}
426+
427+
FilePath FilePath::getSystemTemporaryDirectory()
428+
{
429+
try
430+
{
431+
std::filesystem::path tempPath = std::filesystem::temp_directory_path();
432+
return FilePath(tempPath.string());
433+
}
434+
catch (const std::filesystem::filesystem_error& ex)
435+
{
436+
throw Exception("Error getting system temporary directory: " + string(ex.what()));
437+
}
438+
}
439+
380440
MATERIALX_NAMESPACE_END

source/MaterialXFormat/File.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,11 @@ class MX_FORMAT_API FilePath
195195
FilePathVec getSubDirectories() const;
196196

197197
/// Create a directory on the file system at the given path.
198-
void createDirectory() const;
198+
/// @param recursive If true, creates parent directories as needed.
199+
/// If false (default), only creates the final directory.
200+
/// @note Succeeds silently if directory already exists. Does not return
201+
/// error status - use exists() or isDirectory() to verify success.
202+
void createDirectory(bool recursive=false) const;
199203

200204
/// Set the current working directory of the file system.
201205
bool setCurrentPath();
@@ -208,6 +212,18 @@ class MX_FORMAT_API FilePath
208212
/// Return the directory containing the executable module.
209213
static FilePath getModulePath();
210214

215+
/// Create a temporary directory with a unique name.
216+
/// @param parentDir The parent directory for the temporary directory.
217+
/// If empty, uses the system's default temporary directory.
218+
/// @return A FilePath to the created temporary directory.
219+
/// @throws Exception if the temporary directory cannot be created.
220+
static FilePath createTemporaryDirectory(const FilePath& parentDir = FilePath());
221+
222+
/// Return the system's default temporary directory.
223+
/// @return A FilePath to the system temporary directory.
224+
/// @throws Exception if the system temporary directory cannot be determined.
225+
static FilePath getSystemTemporaryDirectory();
226+
211227
private:
212228
StringVec _vec;
213229
Type _type;

source/MaterialXFormat/XmlIo.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,13 @@ void writeToXmlStream(DocumentPtr doc, std::ostream& stream, const XmlWriteOptio
355355

356356
void writeToXmlFile(DocumentPtr doc, const FilePath& filename, const XmlWriteOptions* writeOptions)
357357
{
358+
if (writeOptions && writeOptions->createDirectories)
359+
{
360+
if (!filename.getParentPath().isDirectory())
361+
{
362+
filename.getParentPath().createDirectory(true);
363+
}
364+
}
358365
std::ofstream ofs(filename.asString());
359366
writeToXmlStream(doc, ofs, writeOptions);
360367
}

source/MaterialXFormat/XmlIo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ class MX_FORMAT_API XmlWriteOptions
7373
/// If provided, this function will be used to exclude specific elements
7474
/// (those returning false) from the write operation. Defaults to nullptr.
7575
ElementPredicate elementPredicate;
76+
77+
/// If true, any necessary directories will be created to write the
78+
/// file.
79+
bool createDirectories = false;
7680
};
7781

7882
/// @class ExceptionParseError

source/MaterialXGenOsl/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ mx_add_library(MaterialXGenOsl
1414
EXPORT_DEFINE
1515
MATERIALX_GENOSL_EXPORTS)
1616

17+
if (OSL_FOUND)
18+
target_link_libraries(${TARGET_NAME}
19+
PRIVATE
20+
OSL::oslcomp)
21+
target_compile_definitions(${TARGET_NAME}
22+
PRIVATE
23+
USE_OSLCOMP)
24+
endif()
25+
26+
target_compile_definitions(${TARGET_NAME} PRIVATE
27+
MATERIALX_OSL_BINARY_OSLC=\"${MATERIALX_OSL_BINARY_OSLC}\"
28+
MATERIALX_OSL_INCLUDE_PATH=\"${MATERIALX_OSL_INCLUDE_PATH}\"
29+
)
30+
1731
if (MATERIALX_BUILD_OSOS)
1832
file(GLOB GenNodes_SRC "${CMAKE_CURRENT_SOURCE_DIR}/LibsToOso.cpp")
1933

0 commit comments

Comments
 (0)