Skip to content

Commit

Permalink
MaterialXOCIO backported to MaterialX
Browse files Browse the repository at this point in the history
  • Loading branch information
JGamache-autodesk committed Jul 3, 2024
1 parent 30f694f commit 00ee41c
Show file tree
Hide file tree
Showing 13 changed files with 546 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ option(MATERIALX_BUILD_GEN_MSL "Build the MSL shader generator back-end." ON)
option(MATERIALX_BUILD_RENDER "Build the MaterialX Render modules." ON)
option(MATERIALX_BUILD_OIIO "Build OpenImageIO support for MaterialXRender." OFF)
option(MATERIALX_BUILD_TESTS "Build unit tests." OFF)
option(MATERIALX_BUILD_OCIO "Build OpenColorIO support for shader generators." OFF)
option(MATERIALX_BUILD_BENCHMARK_TESTS "Build benchmark tests." OFF)

option(MATERIALX_BUILD_SHARED_LIBS "Build MaterialX libraries as shared rather than static." OFF)
Expand Down Expand Up @@ -135,6 +136,7 @@ mark_as_advanced(MATERIALX_BUILD_GEN_MDL)
mark_as_advanced(MATERIALX_BUILD_GEN_MSL)
mark_as_advanced(MATERIALX_BUILD_RENDER)
mark_as_advanced(MATERIALX_BUILD_OIIO)
mark_as_advanced(MATERIALX_BUILD_OCIO)
mark_as_advanced(MATERIALX_BUILD_BENCHMARK_TESTS)
mark_as_advanced(MATERIALX_BUILD_SHARED_LIBS)
mark_as_advanced(MATERIALX_BUILD_MONOLITHIC)
Expand Down
8 changes: 6 additions & 2 deletions source/MaterialXGenGlsl/GlslShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,12 @@ ShaderNodeImplPtr GlslShaderGenerator::getImplementation(const NodeDef& nodedef,
}
else if (implElement->isA<Implementation>())
{
// Try creating a new in the factory.
impl = _implFactory.create(name);
if (getColorManagementSystem() && getColorManagementSystem()->hasImplementation(name)) {
impl = getColorManagementSystem()->createImplementation(name);
} else {
// Try creating a new in the factory.
impl = _implFactory.create(name);
}
if (!impl)
{
// Fall back to source code implementation.
Expand Down
8 changes: 6 additions & 2 deletions source/MaterialXGenMdl/MdlShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,12 @@ ShaderNodeImplPtr MdlShaderGenerator::getImplementation(const NodeDef& nodedef,
}
else if (implElement->isA<Implementation>())
{
// Try creating a new in the factory.
impl = _implFactory.create(name);
if (getColorManagementSystem() && getColorManagementSystem()->hasImplementation(name)) {
impl = getColorManagementSystem()->createImplementation(name);
} else {
// Try creating a new in the factory.
impl = _implFactory.create(name);
}
if (!impl)
{
// Fall back to source code implementation.
Expand Down
8 changes: 6 additions & 2 deletions source/MaterialXGenMsl/MslShaderGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1269,8 +1269,12 @@ ShaderNodeImplPtr MslShaderGenerator::getImplementation(const NodeDef& nodedef,
}
else if (implElement->isA<Implementation>())
{
// Try creating a new in the factory.
impl = _implFactory.create(name);
if (getColorManagementSystem() && getColorManagementSystem()->hasImplementation(name)) {
impl = getColorManagementSystem()->createImplementation(name);
} else {
// Try creating a new in the factory.
impl = _implFactory.create(name);
}
if (!impl)
{
// Fall back to source code implementation.
Expand Down
16 changes: 16 additions & 0 deletions source/MaterialXGenShader/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
file(GLOB_RECURSE materialx_source "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
file(GLOB_RECURSE materialx_headers "${CMAKE_CURRENT_SOURCE_DIR}/*.h*")

set(optionalLibraries "")

if(MATERIALX_BUILD_OCIO)
find_package(OpenColorIO REQUIRED)
list(APPEND optionalLibraries OpenColorIO::OpenColorIO)
endif()

mx_add_library(MaterialXGenShader
SOURCE_FILES
${materialx_source}
Expand All @@ -9,5 +16,14 @@ mx_add_library(MaterialXGenShader
LIBRARIES
MaterialXFormat
MaterialXCore
${optionalLibraries}
EXPORT_DEFINE
MATERIALX_GENSHADER_EXPORTS)

if(MATERIALX_BUILD_OCIO)
if (NOT MATERIALX_BUILD_MONOLITHIC)
target_compile_definitions(MaterialXGenShader PUBLIC MATERIALX_BUILD_OCIO)
else()
target_compile_definitions(${MATERIALX_MONOLITHIC_TARGET} PUBLIC MATERIALX_BUILD_OCIO)
endif()
endif()
6 changes: 6 additions & 0 deletions source/MaterialXGenShader/ColorManagementSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ class MX_GENSHADER_API ColorManagementSystem
ShaderNodePtr createNode(const ShaderGraph* parent, const ColorSpaceTransform& transform, const string& name,
GenContext& context) const;

/// Returns true if the CMS can create a shader node implementation for a locally managed CMS transform
virtual bool hasImplementation(const string& /*implName*/) const { return false; }

/// Create an CMS node implementation for a locally managed transform
virtual ShaderNodeImplPtr createImplementation(const string& /*implName*/) const { return {}; }

protected:
/// Protected constructor
ColorManagementSystem();
Expand Down
151 changes: 151 additions & 0 deletions source/MaterialXGenShader/Nodes/OpenColorIONode.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//

#ifdef MATERIALX_BUILD_OCIO

#include <MaterialXGenShader/Nodes/OpenColorIONode.h>
#include <MaterialXGenShader/OpenColorIOManagementSystem.h>

#include <MaterialXCore/Interface.h>
#include <MaterialXGenGlsl/GlslShaderGenerator.h>
#include <MaterialXGenShader/GenContext.h>
#include <MaterialXGenShader/Library.h>
#include <MaterialXGenShader/ShaderNode.h>
#include <MaterialXGenShader/Shader.h>
#include <MaterialXGenShader/ShaderStage.h>

#include <OpenColorIO/OpenColorIO.h>
#include <OpenColorIO/OpenColorTypes.h>

#include <cstring>
#include <functional>
#include <memory>
#include <string>

MATERIALX_NAMESPACE_BEGIN

namespace
{
// Internal OCIO strings:
constexpr const char OCIO_COLOR3[] = "color3";

// Lengths where needed:
constexpr auto OCIO_COLOR3_LEN = sizeof(OCIO_COLOR3) / sizeof(OCIO_COLOR3[0]);

} // namespace

ShaderNodeImplPtr OpenColorIONode::create()
{
return std::make_shared<OpenColorIONode>();
}

void OpenColorIONode::initialize(const InterfaceElement& element, GenContext& context)
{
ShaderNodeImpl::initialize(element, context);

// Single function shared between color3 and color4 nodes, use a custom hash with only the function name.
_hash = std::hash<string>{}(getFunctionName());
}

void OpenColorIONode::emitFunctionDefinition(
const ShaderNode& /*node*/,
GenContext& context,
ShaderStage& stage) const
{
if (stage.getName() == Stage::PIXEL)
{
auto ocioManager = std::dynamic_pointer_cast<OpenColorIOManagementSystem>(context.getShaderGenerator().getColorManagementSystem());

auto gpuProcessor = ocioManager->getGpuProcessor(getName());
OCIO::GpuShaderDescRcPtr shaderDesc = OCIO::GpuShaderDesc::CreateShaderDesc();

// TODO: Extend to essl and MDL and possibly SLang.
if (context.getShaderGenerator().getTarget() == "genglsl") {
shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_GLSL_4_0);
} else if (context.getShaderGenerator().getTarget() == "genmsl") {
shaderDesc->setLanguage(OCIO::GPU_LANGUAGE_MSL_2_0);
} else if (context.getShaderGenerator().getTarget() == "genosl") {
shaderDesc->setLanguage(OCIO::LANGUAGE_OSL_1);
}

auto functionName = getFunctionName();

shaderDesc->setFunctionName(functionName.c_str());

gpuProcessor->extractGpuShaderInfo(shaderDesc);

stage.addString(shaderDesc->getShaderText());
stage.endLine(false);
}
}

void OpenColorIONode::emitFunctionCall(
const ShaderNode& node,
GenContext& context,
ShaderStage& stage) const
{
if (stage.getName() == Stage::PIXEL)
{
auto functionName = getFunctionName();

// TODO: Adjust syntax for other languages.

// The OCIO function uses a vec4 parameter, so:
// Function call for color4: vec4 res = func(in);
// Function call for color3: vec3 res = func(vec4(in, 1.0)).rgb;
// TODO: Handle LUT samplers.
bool isColor3 = getName().back() == '3';

const auto& shadergen = context.getShaderGenerator();
shadergen.emitLineBegin(stage);

const auto* output = node.getOutput();
const auto* colorInput = node.getInput(0);

shadergen.emitOutput(output, true, false, context, stage);
shadergen.emitString(" = ", stage);

shadergen.emitString(functionName + "(", stage);
if (isColor3)
{
if (context.getShaderGenerator().getTarget() == "genglsl") {
shadergen.emitString("vec4(", stage);
} else if (context.getShaderGenerator().getTarget() == "genmsl") {
shadergen.emitString("float4(", stage);
} else if (context.getShaderGenerator().getTarget() == "genosl") {
shadergen.emitString("color4(", stage);
}
}
shadergen.emitInput(colorInput, context, stage);
if (isColor3)
{
shadergen.emitString(", 1.0)", stage);
}

shadergen.emitString(")", stage);

if (isColor3)
{
shadergen.emitString(".rgb", stage);
}

shadergen.emitLineEnd(stage);
}
}

string OpenColorIONode::getFunctionName() const
{
auto name = getName();

// Strip _color3 and _color4 suffixes and impl prefix:
size_t startPos = OpenColorIOManagementSystem::IMPL_PREFIX.size();
size_t length = name.size() - OCIO_COLOR3_LEN - 1 - startPos;

return name.substr(startPos, length);
}

MATERIALX_NAMESPACE_END

#endif
44 changes: 44 additions & 0 deletions source/MaterialXGenShader/Nodes/OpenColorIONode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//
// Copyright Contributors to the MaterialX Project
// SPDX-License-Identifier: Apache-2.0
//

#ifndef MATERIALX_OCIO_NODE_H
#define MATERIALX_OCIO_NODE_H

#ifdef MATERIALX_BUILD_OCIO
/// @file
/// OCIO node implementation

#include <MaterialXGenShader/ShaderNodeImpl.h>
#include <MaterialXCore/Interface.h>
#include <MaterialXGenShader/GenContext.h>
#include <MaterialXGenShader/Library.h>
#include <MaterialXGenShader/ShaderNode.h>
#include <MaterialXGenShader/ShaderStage.h>

MATERIALX_NAMESPACE_BEGIN

/// OCIO node implementation. Takes an OCIO GpuProcessor and
/// uses it to inject shadergen code.
class OpenColorIONode : public ShaderNodeImpl
{
public:
static ShaderNodeImplPtr create();

void initialize(const InterfaceElement& element, GenContext& context) override;

void emitFunctionDefinition(const ShaderNode& node, GenContext& context, ShaderStage& stage)
const override;

void emitFunctionCall(const ShaderNode& node, GenContext& context, ShaderStage& stage)
const override;

private:
string getFunctionName() const;
};

MATERIALX_NAMESPACE_END

#endif
#endif
Loading

0 comments on commit 00ee41c

Please sign in to comment.