Files
2025-05-18 13:04:45 +08:00

143 lines
4.9 KiB
C++

//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//
#include <MaterialXTest/External/Catch/catch.hpp>
#include <MaterialXTest/MaterialXGenShader/GenShaderUtil.h>
#include <MaterialXCore/Document.h>
#include <MaterialXFormat/File.h>
#include <MaterialXFormat/Util.h>
#include <MaterialXGenShader/ShaderStage.h>
#include <MaterialXGenOsl/OslShaderGenerator.h>
#include <MaterialXGenOsl/OslSyntax.h>
#include <MaterialXRenderOsl/OslRenderer.h>
namespace mx = MaterialX;
TEST_CASE("GenReference: OSL Reference", "[genreference]")
{
mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath();
mx::DocumentPtr stdlib = mx::createDocument();
loadLibraries({ "libraries/targets", "libraries/stdlib" }, searchPath, stdlib);
// Create renderer if requested.
bool runCompileTest = !std::string(MATERIALX_OSL_BINARY_OSLC).empty();
mx::OslRendererPtr oslRenderer = nullptr;
if (runCompileTest)
{
oslRenderer = mx::OslRenderer::create();
oslRenderer->setOslCompilerExecutable(MATERIALX_OSL_BINARY_OSLC);
mx::FileSearchPath oslIncludePaths;
mx::FilePath oslStandardIncludePath = mx::FilePath(MATERIALX_OSL_INCLUDE_PATH);
if (!oslStandardIncludePath.isEmpty())
{
oslIncludePaths.append(oslStandardIncludePath);
}
// Add in library include path for compile testing as the generated
// shader's includes are not added with absolute paths.
oslIncludePaths.append(searchPath.find("libraries/stdlib/genosl/include"));
oslRenderer->setOslIncludePath(oslIncludePaths);
}
// Create shader generator.
mx::ShaderGeneratorPtr generator = mx::OslShaderGenerator::create();
// Register types from the library.
generator->registerTypeDefs(stdlib);
mx::GenContext context(generator);
context.getOptions().addUpstreamDependencies = false;
context.registerSourceCodeSearchPath(searchPath);
context.getOptions().fileTextureVerticalFlip = true;
// Create output directory.
mx::FilePath outputPath = searchPath.find("reference/osl");
outputPath.getParentPath().createDirectory();
outputPath.createDirectory();
// Create log file.
const mx::FilePath logPath("genosl_reference_generate_test.txt");
std::ofstream logFile;
logFile.open(logPath);
// Generate reference shaders.
// Ignore the following nodes:
const mx::StringSet ignoreNodeList = { "surfacematerial", "volumematerial",
"constant_filename", "dot_filename",
"geompropvalueuniform_filename" };
bool failedGeneration = false;
for (const mx::NodeDefPtr& nodedef : stdlib->getNodeDefs())
{
std::string nodeName = nodedef->getName();
std::string nodeNode = nodedef->getNodeString();
if (nodeName.size() > 3 && nodeName.substr(0, 3) == "ND_")
{
nodeName = nodeName.substr(3);
}
if (nodeName == mx::MATERIAL_TYPE_STRING ||
ignoreNodeList.find(nodeName) != ignoreNodeList.end() ||
ignoreNodeList.find(nodeNode) != ignoreNodeList.end())
{
logFile << "Skip generating reference for'" << nodeName << "'" << std::endl;
continue;
}
mx::InterfaceElementPtr interface = nodedef->getImplementation(generator->getTarget());
if (!interface)
{
logFile << "Skip generating reference for unimplemented node '" << nodeName << "'" << std::endl;
continue;
}
mx::NodePtr node = stdlib->addNodeInstance(nodedef, nodeName);
REQUIRE(node);
const std::string filename = nodeName + ".osl";
try
{
mx::ShaderPtr shader = generator->generate(node->getName(), node, context);
std::ofstream file;
const std::string filepath = (outputPath / filename).asString();
file.open(filepath);
REQUIRE(file.is_open());
file << shader->getSourceCode();
file.close();
if (oslRenderer)
{
oslRenderer->compileOSL(filepath);
}
}
catch (mx::ExceptionRenderError& e)
{
logFile << "Error compiling OSL reference for '" << nodeName << "' : " << std::endl;
logFile << e.what() << std::endl;
for (const std::string& error : e.errorLog())
{
logFile << error << std::endl;
}
failedGeneration = true;
}
catch (mx::Exception& e)
{
logFile << "Error generating OSL reference for '" << nodeName << "' : " << std::endl;
logFile << e.what() << std::endl;
failedGeneration = true;
}
stdlib->removeChild(node->getName());
}
logFile.close();
CHECK(failedGeneration == false);
}