Material Definition Language API nvidia_logo_transpbg.gif Up
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Example for Compilation of MDL materials
[Previous] [Up] [Next]

This example introduces compiled materials and highlights differences between different compilation modes.

New Topics

  • Compiled materials
  • Different compilation modes
  • Target code generation

Detailed Description

Compiled materials


A compiled material is a compact, optimized representation of a material instance including all call expressions in its arguments. In this optimization step call expressions for arguments are inlined (similar to function calls in programming languages), constant expressions are folded, common subexpression elimination is taking place, etc.

Different compilation modes


Please refer to Instance-compilation and class-compilation for an introduction into instance and class compilation modes.

In the output of this example, compare the difference between instance and class compilation mode of the initially created material instance. In class compilation mode, the expression for "surface.scattering.tint" is no longer a constant, but a parameter reference.

Now compare the changes in both representations when an argument like "tint" is changed. In instance compilation mode, the constant changes its value accordingly, and consequently, the hash over all temporaries and fields changes, too. In class compilation mode, only the value of argument 0 changes. All temporaries and fields of the compiled material, and consequently the hash value, remain unchanged.

Target code generation


Compiler backends allow to generate code from the abstract representation of compiled materials. There are different backends, e.g., for LLVM IR or CUDA PTX code. These backends can be obtained from mi::neuraylib::IMdl_compiler::get_backend().

Backends support general and backend-specific options to influence the code generation. See mi::neuraylib::IMdl_backend for details.

Note that target code is not generated for an entire compiled material, but for specific subexpressions of the compiled material, like "surface.scattering.tint".

Example Source

Source Code Location: examples/mdl_sdk/example_compilation.cpp

/******************************************************************************
* Copyright 2018 NVIDIA Corporation. All rights reserved.
*****************************************************************************/
// examples/example_compilation.cpp
//
// Introduces compiled materials and highlights differences between different compilation modes.
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <mi/mdl_sdk.h>
#include "example_shared.h"
// Utility function to dump the hash, arguments, temporaries, and fields of a compiled material.
void dump_compiled_material(
{
mdl_factory->create_value_factory( transaction));
mdl_factory->create_expression_factory( transaction));
mi::base::Uuid hash = cm->get_hash();
char buffer[36];
snprintf( buffer, sizeof( buffer),
"%08x %08x %08x %08x", hash.m_id1, hash.m_id2, hash.m_id3, hash.m_id4);
s << " hash overall = " << buffer << std::endl;
snprintf( buffer, sizeof( buffer),
"%08x %08x %08x %08x", hash.m_id1, hash.m_id2, hash.m_id3, hash.m_id4);
s << " hash slot " << std::setw( 2) << i << " = " << buffer << std::endl;
}
mi::Size parameter_count = cm->get_parameter_count();
for( mi::Size i = 0; i < parameter_count; ++i) {
name << i;
value_factory->dump( argument.get(), name.str().c_str(), 1));
s << " argument " << result->get_c_str() << std::endl;
}
mi::Size temporary_count = cm->get_temporary_count();
for( mi::Size i = 0; i < temporary_count; ++i) {
name << i;
expression_factory->dump( temporary.get(), name.str().c_str(), 1));
s << " temporary " << result->get_c_str() << std::endl;
}
mi::base::Handle<const mi::IString> result( expression_factory->dump( body.get(), 0, 1));
s << " body " << result->get_c_str() << std::endl;
s << std::endl;
}
// Creates an instance of "mdl::example::compilation_material".
void create_material_instance(
const char* instance_name)
{
// Load the "example" module.
check_success( mdl_compiler->load_module(
transaction, "::nvidia::sdk_examples::tutorials", context) >= 0);
print_messages( context);
// Create a material instance from the material definition
// "mdl::nvidia::sdk_examples::tutorials::compilation_material" with the default arguments.
"mdl::nvidia::sdk_examples::tutorials::example_compilation"));
mi::Sint32 result;
material_definition->create_material_instance( 0, &result));
check_success( result == 0);
transaction->store( material_instance.get(), instance_name);
}
// Compiles the given material instance in the given compilation modes, dumps the result, and stores
// it in the DB.
void compile_material_instance(
const char* instance_name,
const char* compiled_material_name,
bool class_compilation)
{
transaction->access<mi::neuraylib::IMaterial_instance>( instance_name));
mi::Uint32 flags = class_compilation
material_instance->create_compiled_material( flags, context));
check_success( print_messages( context));
std::cout << "Dumping compiled material (" << ( class_compilation ? "class" : "instance")
<< " compilation) for \"" << instance_name << "\":" << std::endl << std::endl;
dump_compiled_material( transaction, mdl_factory, compiled_material.get(), std::cout);
transaction->store( compiled_material.get(), compiled_material_name);
}
// Changes the tint parameter of the given material instance to green.
void change_arguments(
const char* instance_name)
{
mdl_factory->create_value_factory( transaction));
mdl_factory->create_expression_factory( transaction));
// Edit the instance of the material definition "compilation_material".
transaction->edit<mi::neuraylib::IMaterial_instance>( instance_name));
check_success( material_instance.is_valid_interface());
// Create the new argument for the "tint" parameter from scratch with the new value, and set it.
value_factory->create_color( 0.0f, 1.0f, 0.0f));
expression_factory->create_constant( tint_value.get()));
check_success( material_instance->set_argument( "tint", tint_expr.get()) == 0);
}
// Generates LLVM IR target code for a subexpression of a given compiled material.
void generate_llvm_ir(
const char* compiled_material_name,
const char* path,
const char* fname)
{
transaction->edit<mi::neuraylib::ICompiled_material>( compiled_material_name));
check_success( be_llvm_ir->set_option( "num_texture_spaces", "16") == 0);
check_success( be_llvm_ir->set_option( "enable_simd", "on") == 0);
be_llvm_ir->translate_material_expression(
transaction, compiled_material.get(), path, fname, context));
check_success( print_messages( context));
check_success( code_llvm_ir);
std::cout << "Dumping LLVM IR code for \"" << path << "\" of \"" << compiled_material_name
<< "\":" << std::endl << std::endl;
std::cout << code_llvm_ir->get_code() << std::endl;
}
// Generates CUDA PTX target code for a subexpression of a given compiled material.
void generate_cuda_ptx(
const char* compiled_material_name,
const char* path,
const char* fname)
{
transaction->edit<mi::neuraylib::ICompiled_material>( compiled_material_name));
check_success( be_cuda_ptx->set_option( "num_texture_spaces", "16") == 0);
check_success( be_cuda_ptx->set_option( "sm_version", "50") == 0);
be_cuda_ptx->translate_material_expression(
transaction, compiled_material.get(), path, fname, context));
check_success( print_messages( context));
check_success( code_cuda_ptx);
std::cout << "Dumping CUDA PTX code for \"" << path << "\" of \"" << compiled_material_name
<< "\":" << std::endl << std::endl;
std::cout << code_cuda_ptx->get_code() << std::endl;
}
#ifndef MDL_SOURCE_RELEASE
// Generates GLSL target code for a subexpression of a given compiled material.
void generate_glsl(
const char* compiled_material_name,
const char* path,
const char* fname)
{
transaction->edit<mi::neuraylib::ICompiled_material>( compiled_material_name));
check_success( be_glsl->set_option( "glsl_version", "450") == 0);
be_glsl->translate_material_expression(
transaction, compiled_material.get(), path, fname, context));
check_success( print_messages( context));
check_success( code_glsl);
std::cout << "Dumping GLSL code for \"" << path << "\" of \"" << compiled_material_name
<< "\":" << std::endl << std::endl;
std::cout << code_glsl->get_code() << std::endl;
}
#endif // MDL_SOURCE_RELEASE
int main( int /*argc*/, char* /*argv*/[])
{
// Access the MDL SDK
mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
check_success( neuray.is_valid_interface());
// Configure the MDL SDK
configure( neuray.get());
// Start the MDL SDK
mi::Sint32 result = neuray->start();
check_start_success( result);
{
neuray->get_api_component<mi::neuraylib::IMdl_compiler>());
neuray->get_api_component<mi::neuraylib::IMdl_factory>());
neuray->get_api_component<mi::neuraylib::IDatabase>());
mi::base::Handle<mi::neuraylib::IScope> scope( database->get_global_scope());
mi::base::Handle<mi::neuraylib::ITransaction> transaction( scope->create_transaction());
{
// Create an execution context for options and error message handling
mdl_factory->create_execution_context());
// Load the "example" module and create a material instance
std::string instance_name = "instance of compilation_material";
create_material_instance( transaction.get(), mdl_compiler.get(), context.get(), instance_name.c_str());
// Compile the material instance in instance compilation mode
std::string instance_compilation_name
= std::string( "instance compilation of ") + instance_name;
compile_material_instance(
transaction.get(), mdl_factory.get(), context.get(), instance_name.c_str(),
instance_compilation_name.c_str(), false);
// Compile the material instance in class compilation mode
std::string class_compilation_name
= std::string( "class compilation of ") + instance_name;
compile_material_instance(
transaction.get(), mdl_factory.get(), context.get(), instance_name.c_str(),
class_compilation_name.c_str(), true);
// Change some material argument and compile again in both modes. Note the differences
// in instance compilation mode, whereas only the referenced parameter itself changes in
// class compilation mode.
change_arguments( transaction.get(), mdl_factory.get(), instance_name.c_str());
compile_material_instance(
transaction.get(), mdl_factory.get(), context.get(), instance_name.c_str(),
instance_compilation_name.c_str(), false);
compile_material_instance(
transaction.get(), mdl_factory.get(), context.get(), instance_name.c_str(),
class_compilation_name.c_str(), true);
// Use the various backends to generate target code for some material expression.
generate_llvm_ir(
transaction.get(), mdl_compiler.get(), context.get(), instance_compilation_name.c_str(),
"backface.scattering.tint", "tint");
generate_cuda_ptx(
transaction.get(), mdl_compiler.get(), context.get(), instance_compilation_name.c_str(),
"backface.scattering.tint", "tint");
generate_cuda_ptx(
transaction.get(), mdl_compiler.get(), context.get(), class_compilation_name.c_str(),
"backface.scattering.tint", "tint");
#ifndef MDL_SOURCE_RELEASE
generate_glsl(
transaction.get(), mdl_compiler.get(), context.get(), instance_compilation_name.c_str(),
"backface.scattering.tint", "tint");
generate_glsl(
transaction.get(), mdl_compiler.get(), context.get(), class_compilation_name.c_str(),
"backface.scattering.tint", "tint");
#endif /*MDL_SOURCE_RELEASE*/
}
transaction->commit();
}
// Shut down the MDL SDK
check_success( neuray->shutdown() == 0);
neuray = 0;
// Unload the MDL SDK
check_success( unload());
keep_console_open();
return EXIT_SUCCESS;
}
[Previous] [Up] [Next]