Skip to content

Commit

Permalink
JS Bindings for Essl Shader Generation (#1257)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdunkel authored Jul 6, 2021
1 parent 33a7005 commit 9b43691
Show file tree
Hide file tree
Showing 41 changed files with 951 additions and 1,729 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ if (MATERIALX_BUILD_GEN_OGSFX)
set(MATERIALX_BUILD_GEN_GLSL ON)
endif()

if (MATERIALX_BUILD_JS)
set(MATERIALX_BUILD_GEN_ESSL ON)
endif()

if (MATERIALX_BUILD_GEN_ESSL)
set(MATERIALX_BUILD_GEN_GLSL ON)
endif()
Expand Down
16 changes: 8 additions & 8 deletions documents/DeveloperGuide/CodeExamples.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ print str(roughness.getBoundValue(material))
#### JavaScript

~~~{.js}
import Module from './JsMaterialX.js';
import MaterialX from './JsMaterialXCore.js';
Module().then((_module) => {
MaterialX().then((_module) => {
// Get the MaterialX namespace.
const mx = _module.getMaterialX();
Expand Down Expand Up @@ -165,16 +165,16 @@ for elem in doc.traverseTree():
#### JavaScript

~~~{.js}
import Module from './JsMaterialX.js';
import MaterialX from './JsMaterialXCore.js';
Module().then((_module) => {
MaterialX().then(async (_module) => {
// Get the MaterialX namespace.
const mx = _module.getMaterialX();
// Read a document from disk.
const doc = mx.createDocument();
// Note: The xmlStr should be defined.
mx.readFromXmlString(doc, xmlStr);
await mx.readFromXmlString(doc, xmlStr);
// Traverse the document tree in depth-first order.
const elements = doc.traverseTree();
Expand Down Expand Up @@ -264,16 +264,16 @@ for material in doc.getMaterials():
#### JavaScript

~~~{.js}
import Module from './JsMaterialX.js';
import MaterialX from './JsMaterialXCore.js';
Module().then((_module) => {
MaterialX().then(async (_module) => {
// Get the MaterialX namespace.
const mx = _module.getMaterialX();
// Read a document from disk.
const doc = mx.createDocument();
// Note: The xmlStr should be defined.
mx.readFromXmlString(doc, xmlStr);
await mx.readFromXmlString(doc, xmlStr);
// Iterate through materials.
const materials = doc.getMaterials();
Expand Down
File renamed without changes.
69 changes: 54 additions & 15 deletions source/JsMaterialX/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
set(CORE ${CMAKE_CURRENT_SOURCE_DIR}/JsMaterialXCore/)
set(FORMAT ${CMAKE_CURRENT_SOURCE_DIR}/JsMaterialXFormat/)
set(GENSHADER ${CMAKE_CURRENT_SOURCE_DIR}/JsMaterialXGenShader/)
set(GENESSL ${CMAKE_CURRENT_SOURCE_DIR}/JsMaterialXGenEssl/)

set(SOURCE_FOLDER ${CMAKE_SOURCE_DIR}/source)

Expand All @@ -26,23 +28,32 @@ set(FORMAT_DEPS
${FORMAT}JsXmlExport.cpp
${FORMAT}JsEnviron.cpp)

set(GENSHADER_DEPS ${GENSHADER}JsGenContext.cpp
${GENSHADER}JsGenOptions.cpp
${GENSHADER}JsShader.cpp
${GENSHADER}JsShaderGenerator.cpp
${GENSHADER}JsUtil.cpp)

set(GENESSL_DEPS ${GENESSL}JsEsslShaderGenerator.cpp)

# Linker flags
set(JS_LINK_FLAGS "")
set(JS_LINK_FLAGS_CORE "")
if (EXTERNAL_LINK_FLAGS)
string(APPEND JS_LINK_FLAGS "${EXTERNAL_LINK_FLAGS} ")
string(APPEND JS_LINK_FLAGS_CORE "${EXTERNAL_LINK_FLAGS} ")
endif()

string(APPEND JS_LINK_FLAGS " -I${SOURCE_FOLDER} \
string(APPEND JS_LINK_FLAGS_CORE " -I${SOURCE_FOLDER} \
-s WASM=1 \
-s DISABLE_EXCEPTION_CATCHING=0 \
-s MODULARIZE=1 \
-s USE_ES6_IMPORT_META=0 \
-s EXPORT_NAME='MaterialX' \
-s MEMORY_GROWTH_LINEAR_STEP=32MB \
-s ALLOW_MEMORY_GROWTH=1 \
-s FORCE_FILESYSTEM=1 ")

# Add the post javascript files
string(APPEND JS_LINK_FLAGS "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/post.js \
string(APPEND JS_LINK_FLAGS_CORE "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/post.js \
--post-js ${CORE}post.js \
--post-js ${FORMAT}post.js ")

Expand All @@ -54,35 +65,63 @@ endif()

if (CMAKE_BUILD_TYPE MATCHES Debug)
message("JS: Building Debug")
string(APPEND JS_LINK_FLAGS "--bind ")
string(APPEND JS_LINK_FLAGS_CORE "--bind ")
else()
message("JS: Building Release")
string(APPEND JS_LINK_FLAGS "-flto -Os --bind ")
string(APPEND JS_LINK_FLAGS_CORE "-flto -Os --bind ")
string(APPEND JS_COMPILE_FLAGS "-flto -Os ")
endif()

add_executable(JsMaterialX MaterialXLib.cpp

set(JS_LINK_FLAGS_GENSHADER "${JS_LINK_FLAGS_CORE} --preload-file ${CMAKE_SOURCE_DIR}/libraries@libraries ")

add_executable(JsMaterialXCore MaterialXLib.cpp
${CORE_DEPS}
${FORMAT_DEPS})

set_target_properties(JsMaterialX
add_executable(JsMaterialXGenShader MaterialXLib.cpp
${CORE_DEPS}
${FORMAT_DEPS}
${GENSHADER_DEPS}
${GENESSL_DEPS})

set_target_properties(JsMaterialXCore
PROPERTIES
OUTPUT_NAME JsMaterialX
OUTPUT_NAME JsMaterialXCore
COMPILE_FLAGS "${JS_COMPILE_FLAGS}"
LINK_FLAGS "${JS_LINK_FLAGS}"
LINK_FLAGS "${JS_LINK_FLAGS_CORE}"
SOVERSION "${MATERIALX_MAJOR_VERSION}")

target_link_libraries(JsMaterialX
set_target_properties(JsMaterialXGenShader
PROPERTIES
OUTPUT_NAME JsMaterialXGenShader
COMPILE_FLAGS "${JS_COMPILE_FLAGS}"
LINK_FLAGS "${JS_LINK_FLAGS_GENSHADER}"
SOVERSION "${MATERIALX_MAJOR_VERSION}")

target_link_libraries(JsMaterialXCore
PUBLIC MaterialXCore
PUBLIC MaterialXFormat
PRIVATE ${CMAKE_DL_LIBS})

target_link_libraries(JsMaterialXGenShader
PUBLIC MaterialXCore
PUBLIC MaterialXFormat
PUBLIC MaterialXGenShader
PUBLIC MaterialXGenEssl
PRIVATE ${CMAKE_DL_LIBS})

# Install the JavaScript output
install(TARGETS JsMaterialX DESTINATION "${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX")
install(TARGETS JsMaterialXCore DESTINATION "${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX")
install(TARGETS JsMaterialXGenShader DESTINATION "${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX")

# Copy the wasm output
install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialX.wasm DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/)
install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialXCore.wasm DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/)
install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialXGenShader.wasm ${CMAKE_BINARY_DIR}/bin/JsMaterialXGenShader.data DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/)

# Copy the JavaScript files with the version appended to them.
install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialX.js DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ RENAME JsMaterialX-${MATERIALX_LIBRARY_VERSION}.js)
install(FILES ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/JsMaterialX.js DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/ RENAME JsMaterialX-${MATERIALX_LIBRARY_VERSION}.js)
install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialXCore.js DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ RENAME JsMaterialXCore-${MATERIALX_LIBRARY_VERSION}.js)
install(FILES ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/JsMaterialXCore.js DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/ RENAME JsMaterialXCore-${MATERIALX_LIBRARY_VERSION}.js)

install(FILES ${CMAKE_BINARY_DIR}/bin/JsMaterialXGenShader.js DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ RENAME JsMaterialXGenShader-${MATERIALX_LIBRARY_VERSION}.js)
install(FILES ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/JsMaterialXGenShader.js DESTINATION ${CMAKE_INSTALL_PREFIX}/JavaScript/MaterialX/ RENAME JsMaterialXGenShader-${MATERIALX_LIBRARY_VERSION}.js)
33 changes: 33 additions & 0 deletions source/JsMaterialX/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,4 +346,37 @@ API(JSNAME, ems::optional_override([](SELF) { \
#define BIND_0_0(...) \
BIND_0(__VA_ARGS__)


/* Creates a wrapper converting a member function returning a reference to one returning
a pointer. Emscripten converts references to copies and the wrapper emulates
the expected behavior */
template<typename RetTypeRef, RetTypeRef method> struct ptrReturnHelper;
template<
typename Class,
typename RetType,
typename... ArgType,
RetType &(Class::*method)(ArgType...)
> struct ptrReturnHelper<RetType &(Class::*)(ArgType...), method> {
auto getWrapper()->auto(*)(Class &, ArgType...)->RetType * {
return [](Class &obj, ArgType ...arg) -> RetType * {
return &(obj.*method)(arg...);
};
}
};

/**
* Creates a wrapper converting a non-overloaded member function returning a reference to one returning a pointer.
* @param METHOD Function pointer to the member function
*/
#define PTR_RETURN(METHOD) \
(ptrReturnHelper<decltype(METHOD),METHOD>().getWrapper())

/**
* Creates a wrapper converting an overloaded member function returning a reference to one returning a pointer.
* @param DECL Declaration of the function to wrap
* @param METHOD Function pointer to the member function
*/
#define PTR_RETURN_OVERLOAD(DECL, METHOD) \
(ptrReturnHelper<DECL,METHOD>().getWrapper())

#endif // JSMATERIALX_HELPERS_H
12 changes: 10 additions & 2 deletions source/JsMaterialX/JsMaterialXCore/JsUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
namespace ems = emscripten;
namespace mx = MaterialX;

mx::LinearUnitConverterPtr LinearUnitConverterCreate(mx::UnitTypeDefPtr unitTypeDef) {
return mx::LinearUnitConverter::create(unitTypeDef);
}

mx::UnitConverterPtr UnitConverterRegistryGetUnitConverter(mx::UnitConverterRegistry& registry,mx::UnitTypeDefPtr def){
return registry.getUnitConverter(def);
}

EMSCRIPTEN_BINDINGS(unit)
{

Expand All @@ -30,7 +38,7 @@ EMSCRIPTEN_BINDINGS(unit)
ems::class_<mx::LinearUnitConverter, ems::base<mx::UnitConverter>>("LinearUnitConverter")
.smart_ptr<std::shared_ptr<mx::LinearUnitConverter>>("LinearUnitConverter")
.smart_ptr<std::shared_ptr<const mx::LinearUnitConverter>>("LinearUnitConverter")
.class_function("create", &mx::LinearUnitConverter::create)
.class_function("create", &LinearUnitConverterCreate)
.function("getUnitType", &mx::LinearUnitConverter::getUnitType)
.function("write", &mx::LinearUnitConverter::write)
.function("getUnitScale", &mx::LinearUnitConverter::getUnitScale)
Expand All @@ -48,7 +56,7 @@ EMSCRIPTEN_BINDINGS(unit)
.class_function("create", &mx::UnitConverterRegistry::create)
.function("addUnitConverter", &mx::UnitConverterRegistry::addUnitConverter)
.function("removeUnitConverter", &mx::UnitConverterRegistry::removeUnitConverter)
.function("getUnitConverter", &mx::UnitConverterRegistry::getUnitConverter)
.function("getUnitConverter", &UnitConverterRegistryGetUnitConverter)
.function("clearUnitConverters", &mx::UnitConverterRegistry::clearUnitConverters)
.function("getUnitAsInteger", &mx::UnitConverterRegistry::getUnitAsInteger)
.function("write", &mx::UnitConverterRegistry::write)
Expand Down
55 changes: 55 additions & 0 deletions source/JsMaterialX/JsMaterialXGenEssl/JsEsslShaderGenerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// TM & (c) 2021 Lucasfilm Entertainment Company Ltd. and Lucasfilm Ltd.
// All rights reserved. See LICENSE.txt for license.
//

#include <MaterialXGenEssl/EsslShaderGenerator.h>
#include <MaterialXGenShader/Shader.h>
#include <MaterialXGenShader/ShaderStage.h>
#include <MaterialXGenShader/Util.h>

#include <emscripten/bind.h>

namespace ems = emscripten;
namespace mx = MaterialX;

/// Returns the first renderable element from the given document. This element can be used to generate a shader.
mx::ElementPtr findRenderableElement(mx::DocumentPtr doc)
{
mx::StringVec renderablePaths;
std::vector<mx::TypedElementPtr> elems;
mx::findRenderableElements(doc, elems);

for (mx::TypedElementPtr elem : elems)
{
mx::TypedElementPtr renderableElem = elem;
mx::NodePtr node = elem->asA<mx::Node>();
if (node && node->getType() == mx::MATERIAL_TYPE_STRING)
{
std::vector<mx::NodePtr> shaderNodes = getShaderNodes(node, mx::SURFACE_SHADER_TYPE_STRING);
if (!shaderNodes.empty())
{
renderableElem = *shaderNodes.begin();
}
}

const auto& renderablePath = renderableElem->getNamePath();
mx::ElementPtr renderableElement = doc->getDescendant(renderablePath);
mx::TypedElementPtr typedElem = renderableElement ? renderableElement->asA<mx::TypedElement>() : nullptr;
if (typedElem)
{
return renderableElement;
}
}

return nullptr;
}

EMSCRIPTEN_BINDINGS(EsslShaderGenerator)
{
ems::class_<mx::EsslShaderGenerator, ems::base<mx::ShaderGenerator>>("EsslShaderGenerator")
.smart_ptr_constructor("EsslShaderGenerator", &std::make_shared<mx::EsslShaderGenerator>)
;

ems::function("findRenderableElement", &findRenderableElement);
}
Loading

0 comments on commit 9b43691

Please sign in to comment.