MDL SDK API nvidia_logo_transpbg.gif Up
Example for Starting and Shutting Down the MDL SDK API
[Up] [Next]

This example accesses the main MDL SDK interface, queries the version interface, prints some version information and then starts and shuts down the MDL SDK API. See the Getting Started Section for a description of how the example programs can be compiled.

New Topics

  • Naming conventions.
  • Main include files.
  • Main API access point.
  • Interfaces and handles.
  • Starting and shutting down the MDL SDK API.

Detailed Description

Naming conventions

The MDL SDK is written in C++. It uses the mi and mi::neuraylib namespaces for its own identifiers, or the MI_NEURAYLIB_ prefix for macros.

Multiple words are concatenated with _ to form identifiers. Function names are all lower case, while types and classes start with one initial upper-case letter.

Main include files

The include file mi/mdl_sdk.h provides all the functionality of the MDL SDK API.

Main API access point

The mi_factory() function is the only public access point to all algorithms and data structures in the API (see Library Design for an explanation why). To obtain a pointer to the main interface mi::neuraylib::INeuray, call this function with the mi::neuraylib::INeuray::IID() as its iid parameter. If no compatible interface can be found in the library, a NULL pointer is returned. In this case, you can use mi::neuraylib::IVersion::IID() to request a mi::neuraylib::IVersion interface from the mi_factory() for diagnostics. The mi::neuraylib::INeuray interface can only be accessed once per process.

Before you are able to call the mi_factory() function, you need to load the MDL SDK DSO and to locate the factory function. The convenience function load_and_get_ineuray() abstracts these platform-dependent steps.

Note that it is not required to use load_and_get_ineuray(). In particular in larger setups you might want to write your own code to load the MDL SDK DSO and to locate the factory function. In such cases, you call mi_factory() directly. For simplicity, the examples will use the convenience function load_and_get_ineuray() instead of mi_factory().

Interfaces and handles

Except for trivial classes, such as the math vector class, all classes in the MDL SDK API are implemented using interfaces. See Library Design for an explanation. Interfaces are created and destroyed by the MDL SDK API. They implement reference counting for life-time control and cheap copying operations. Interface names start with an I prefix.

Whenever you do not need an interface any longer, you have to release it by calling its release() method. Omitting such calls leads to memory leaks. To simplify your life we provide a simple handle class mi::base::Handle. This handle class maintains a pointer semantic while supporting reference counting for interface pointers. For example, the -> operator acts on the underlying interface pointer, which means that you can use a handle to a particular interface pointer in a way very similar to the interface pointer itself. The destructor calls release() on the interface pointer, copy constructor and assignment operator take care of retaining and releasing the interface pointer as necessary.

Note that the handle class has two different constructors to deal with ownership of the interface pointer. See the mi::base::Handle documentation for details.

Note that it is also possible to use other handle class implementations, e.g., std::shared_ptr<T> (or boost::shared_ptr<T>). In case you prefer to use such handle classes, you have to ensure that their destructor calls the release() method of the interface pointer. This can be achieved by passing an appropriate argument as second parameter, e.g.,

std::shared_ptr<T> p ( load_and_get_ineuray(), std::mem_fun (&T::release));

Starting and shutting down the MDL SDK API

The mi::neuraylib::INeuray interface is used to start and shut down the MDL SDK API. The API can only be used after it has been started (and before it has been shut down). Startup does not happen during the mi_factory() call because you might want to configure the behavior of the API, which has to happen before startup.

The status of the API can be queried using the mi::neuraylib::INeuray::get_status() method.

Finally, you have to shut down the MDL SDK API. At this point, you should have released all interface pointers except the pointer to the main mi::neuraylib::INeuray interface. If you are using the handle class, make sure that all handles have gone out of scope.

Example Source

Source Code Location: examples/mdl_sdk/shared/example_shared.h

* Copyright 2024 NVIDIA Corporation. All rights reserved.
// examples/mdl_sdk/shared/example_shared.h
// Code shared by all examples
#include <chrono>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <tuple>
#include <vector>
#include "utils/io.h"
#include "utils/mdl.h"
#include "utils/os.h"
#include "utils/strings.h"
inline void exit_failure_(
const char* file, int line,
std::string message)
// print message
if (message.empty())
fprintf(stderr, "Fatal error in file: %s line: %d\n\nClosing the example.\n", file, line);
fprintf(stderr, "Fatal error in file: %s line: %d\n %s\n\nClosing the example.\n",
file, line, message.c_str());
// keep console open
if (IsDebuggerPresent()) {
fprintf(stderr, "Press enter to continue . . . \n");
// kill the application
inline void exit_failure_(const char* file, int line)
exit_failure_(file, line, "");
#define exit_failure(...) \
exit_failure_(__FILE__, __LINE__, mi::examples::strings::format(__VA_ARGS__))
// ------------------------------------------------------------------------------------------------
inline void exit_success_()
// keep console open
if (IsDebuggerPresent()) {
fprintf(stderr, "\nPress enter to continue . . . \n");
#define exit_success() exit_success_(); return EXIT_SUCCESS; // no warning about missing return
// ------------------------------------------------------------------------------------------------
// Helper macro. Checks whether the expression is true and if not prints a message and exits.
#define check_success( expr) \
do { \
if( !(expr)) \
exit_failure( "%s", #expr); \
} while( false)
inline void print_message(
const char* msg)
std::string s_kind = mi::examples::strings::to_string(kind);
if (mi::examples::mdl::g_logger) {
mi::examples::mdl::g_logger->message(severity, s_kind.c_str(), msg);
} else {
std::string s_severity = mi::examples::strings::to_string(severity);
fprintf(stderr, "%s: %s %s\n", s_severity.c_str(), s_kind.c_str(), msg);
inline bool print_messages(mi::neuraylib::IMdl_execution_context* context)
for (mi::Size i = 0, n = context->get_messages_count(); i < n; ++i) {
print_message(message->get_severity(), message->get_kind(), message->get_string());
return context->get_error_messages_count() == 0;
// ------------------------------------------------------------------------------------------------
// wrap the example entry point in order to support UTF8 arguments
#define MAIN_UTF8 main_utf8
int wmain(int argc, wchar_t* argv[]) { \
char** argv_utf8 = new char*[argc]; \
for (int i = 0; i < argc; i++) { \
LPWSTR warg = argv[i]; \
DWORD size = WideCharToMultiByte(CP_UTF8, 0, warg, -1, NULL, 0, NULL, NULL); \
check_success(size > 0); \
argv_utf8[i] = new char[size]; \
DWORD result = WideCharToMultiByte(CP_UTF8, 0, warg, -1, argv_utf8[i], size, NULL, NULL); \
check_success(result > 0); \
} \
SetConsoleOutputCP(CP_UTF8); \
int result = main_utf8(argc, argv_utf8); \
delete[] argv_utf8; \
return result; \
#define MAIN_UTF8 main
Handle class template for interfaces, automatizing the lifetime control via reference counting.
Definition: handle.h:113
The execution context can be used to query status information like error and warning messages concern...
Definition: imdl_execution_context.h:131
virtual Size get_error_messages_count() const =0
Returns the number of error messages.
virtual Size get_messages_count() const =0
Returns the number of messages.
virtual const IMessage * get_message(Size index) const =0
Returns the message at index or NULL, if no such index exists.
The possible kinds of messages.
Definition: imdl_execution_context.h:33
Constants for possible message severities.
Definition: enums.h:31
Uint64 Size
Unsigned integral type that is large enough to hold the size of all types.
Definition: types.h:112

Source Code Location: examples/mdl_sdk/start_shutdown/example_start_shutdown.cpp

* Copyright 2024 NVIDIA Corporation. All rights reserved.
// examples/mdl_sdk/start_shutdown/example_start_shutdown.cpp
// Obtain an INeuray interface, start the MDL SDK and shut it down.
// Include code shared by all examples.
#include "example_shared.h"
// The main function initializes the MDL SDK, starts it, and shuts it down after waiting for
// user input.
int MAIN_UTF8( int /*argc*/, char* /*argv*/[])
// Get the INeuray interface in a suitable smart pointer.
mi::base::Handle<mi::neuraylib::INeuray> neuray( mi::examples::mdl::load_and_get_ineuray());
if ( !neuray.is_valid_interface())
exit_failure("Error: The MDL SDK library failed to load and to provide "
"the mi::neuraylib::INeuray interface.");
// Print library version information.
neuray->get_api_component<const mi::neuraylib::IVersion>());
fprintf( stderr, "MDL SDK header version = %s\n",
fprintf( stderr, "MDL SDK library product name = %s\n", version->get_product_name());
fprintf( stderr, "MDL SDK library product version = %s\n", version->get_product_version());
fprintf( stderr, "MDL SDK library build number = %s\n", version->get_build_number());
fprintf( stderr, "MDL SDK library build date = %s\n", version->get_build_date());
fprintf( stderr, "MDL SDK library build platform = %s\n", version->get_build_platform());
fprintf( stderr, "MDL SDK library version string = \"%s\"\n", version->get_string());
mi::base::Uuid neuray_id_libraray = version->get_neuray_iid();
fprintf( stderr, "MDL SDK header interface ID = <%2x, %2x, %2x, %2x>\n",
fprintf( stderr, "MDL SDK library interface ID = <%2x, %2x, %2x, %2x>\n\n",
version = 0;
// configuration settings go here, none in this example,
// but for a standard initialization the other examples use this helper function:
// if ( !mi::examples::mdl::configure(neuray.get()))
// exit_failure("Failed to initialize the SDK.");
// After all configurations, the MDL SDK is started. A return code of 0 implies success. The
// start can be blocking or non-blocking. Here the blocking mode is used so that you know that
// the MDL SDK is up and running after the function call. You can use a non-blocking call to do
// other tasks in parallel and check with
// neuray->get_status() == mi::neuraylib::INeuray::STARTED
// if startup is completed.
mi::Sint32 result = neuray->start( true);
if ( result != 0)
exit_failure( "Failed to initialize the SDK. Result code: %d", result);
// scene graph manipulations and rendering calls go here, none in this example.
// ...
// Shutting the MDL SDK down in blocking mode. Again, a return code of 0 indicates success.
if (neuray->shutdown( true) != 0)
exit_failure( "Failed to shutdown the SDK.");
// Unload the MDL SDK
neuray = nullptr; // free the handles that holds the INeuray instance
if ( !mi::examples::mdl::unload())
exit_failure( "Failed to unload the SDK.");
// Convert command line arguments to UTF8 on Windows
Abstract interface for accessing version information.
Definition: iversion.h:19
Uint32 m_id1
First value.
Definition: uuid.h:27
Uuid_t< id1, ... > IID
Declares the interface ID (IID) of this interface.
Definition: interface_declare.h:49
Uint32 m_id2
Second value.
Definition: uuid.h:28
Uint32 m_id3
Third value.
Definition: uuid.h:29
Uint32 m_id4
Fourth value.
Definition: uuid.h:30
signed int Sint32
32-bit signed integer.
Definition: types.h:46
The MDL SDK product version number in a string representation, such as "2.0".
Definition: version.h:76
A 128 bit representation of a universally unique identifier (UUID or GUID).
Definition: uuid.h:26
[Up] [Next]