// // Copyright Contributors to the MaterialX Project // SPDX-License-Identifier: Apache-2.0 // #include #include #include #include #include #include #include #include #include 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); }