Iray Programmer's Manual

Starting and shutting down the Iray API

This topic introduces:

  1. The neuray object, which is your access point to the system

  2. The required interfaces and methods:

  3. example_start_shutdown.cpp, which demonstrates how to start up and shut down the Iray API

  4. example_shared.h, a shared example header file, which provides common functionality for all example programs

Overview

To access the Iray API, you create a neuray object using a factory function. This object is your only access point to the system. You use it to authenticate your application against the neuray library, configure the system, start it up and shut it down. Only one instance of this object can exist at any time.

When startup is completed, you can build scenes and initiate renderings. Before you can shut down the Iray API, all render jobs must be finished and all transactions must be closed.

See Runtime configuration for available configurations and Logging configuration for an example configuring the log output.

Loading and accessing the neuray library

The factory function, which is used to create the neuray object, is a C function which returns an interface pointer to the neuray object. This C function is the only exported global function of the neuray library:

This function has actually two parameters, one to configure a memory allocator and one to guarantee the correct API version. Both parameters have default values and the examples use this function without special arguments.

This allows you to easily use neuray as a shared library, which can be loaded on demand without requiring to statically link an interface library to the application. The details of loading a shared library on demand and calling this factory function are operating system specific. Since this functionality is needed in all examples, it has been factored into a separate convenience function, load_and_get_ineuray(), and placed in the shared header file example_shared.h, described below.

In addition, this convenience function handles authentication and error situations with some rudimentary reporting. This function can serve as a starting point for applications, but should be reviewed and customized to the particular needs of an application where needed.

To unload the neuray library at the end of a program, you can use the unload() function provided in the same header file.

Authenticating an application against the neuray library

The use of the neuray library requires a valid license. Depending on the license some functionality might not be available. A missing or invalid license might cause rendered images to show a watermark. The example programs will work without a license to the extent that they might show the watermark in images or indicate with a message that functionality is missing.

For most versions of the neuray library, an application needs to authenticate itself against the neuray library that it is in the possession of a license. This authentication is also handled in the load_and_get_ineuray() convenience function. For it to work, you need to place your license key next to the example programs. The license key can come in one of two forms:

  1. An authentication.h file, which you can drop as a replacement of the same file in the examples source directory and recompile. This is also the recommended way for applications to compile the license into the application.
  2. An examples.lic file, which you can drop into the compiled example programs directory and it will be picked up at runtime. This is only recommended for demo or otherwise limited licenses.

After you have obtained successfully the neuray object and authenticated the application, you can move on to configure the API if needed, which is skipped here, and finally start the Iray API.

Start and shutdown

The mi::neuraylib::INeuray interface is used to start and shut down the Iray API. Most of 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_neuray_factory() call because you might want to configure the behavior of the API, which for certain configurations has to happen before startup. For details, see Runtime configuration and Logging configuration.

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

Finally, you have to shut down the Iray 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 program

This example program accesses the main neuray interface, queries the API interface version, prints diagnostic information about the API interface version, API version and build version string, and then starts and shuts down the neuray API. The example illustrates also the necessary places for error checking.

See also How to compile a program and How to run a program.

example_start_shutdown.cpp

001 /******************************************************************************
002  * © 1986, 2016 NVIDIA Corporation. All rights reserved.
003  *****************************************************************************/
004 
005 // examples/example_start_shutdown.cpp
006 //
007 // Obtain an INeuray interface, start neuray and shut it down.
008 
009 #include <mi/neuraylib.h>
010 
011 // Include code shared by all examples.
012 #include "example_shared.h"
013 
014 // The main function initializes the neuray library, starts it, and shuts it down after waiting for
015 // user input.
016 int main( int /*argc*/, char* /*argv*/[])
017 {
018     // Get the INeuray interface in a suitable smart pointer.
019     mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
020     if( !neuray.is_valid_interface()) {
021         fprintf( stderr, "Error: The neuray library failed to load and to provide "
022                  "the mi::neuraylib::INeuray interface for the API version %d.\n",
023                  MI_NEURAYLIB_API_VERSION);
024         keep_console_open();
025         return EXIT_FAILURE;
026     }
027 
028     // Access API and library version numbers.
029     mi::Uint32 interface_version = neuray->get_interface_version();
030     const char* version = neuray->get_version();
031     fprintf( stderr, "neuray header  API interface version = %d\n", MI_NEURAYLIB_API_VERSION);
032     fprintf( stderr, "neuray header  API version           = %s\n",
033          MI_NEURAYLIB_VERSION_QUALIFIED_STRING);
034     fprintf( stderr, "neuray library API interface version = %d\n", interface_version);
035     fprintf( stderr, "neuray library build version string  = \"%s\".\n", version);
036 
037     // configuration settings go here, none in this example
038 
039     // After all configurations, neuray is started. A return code of 0 implies success. The start
040     // can be blocking or non-blocking. Here the blocking mode is used so that you know that neuray
041     // is up and running after the function call. You can use a non-blocking call to do other tasks
042     // in parallel and check with
043     //
044     //      neuray->get_status() == mi::neuraylib::INeuray::STARTED
045     //
046     // if startup is completed.
047     mi::Sint32 result = neuray->start( true);
048     check_start_success( result);
049 
050     // scene graph manipulations and rendering calls go here, none in this example.
051 
052     // Shutting down in blocking mode. Again, a return code of 0 indicates success.
053     check_success( neuray->shutdown( true) == 0);
054     neuray = 0;
055 
056     // Unload the neuray library
057     check_success( unload());
058 
059     keep_console_open();
060     return EXIT_SUCCESS;
061 }

Shared example header file

The shared example header file provides the following common functionality for all example programs:

  • load_and_get_ineuray() function, which is described in Loading and accessing the neuray library
  • unload() function, which unloads the neuray library.
  • keep_console_open() function, which prevents the terminal to close when the program is executed with an attached debugger under Windows, most notably, from within Visual Studio. It is void on other platforms.
  • check_success(expr) macro, which, similar to an assertion, checks the conditional expression expr and exits the program with a diagnostic message if this expression does not evaluate to true.
  • sleep_seconds(int seconds) function, which waits for the indicated time.
  • A provision that snprintf() can be used across platforms without warnings.

example_shared.h

001 /******************************************************************************
002  * © 1986, 2016 NVIDIA Corporation. All rights reserved.
003  *****************************************************************************/
004 
005 // examples/example_shared.h
006 //
007 // Code shared by all examples
008 
009 #ifndef EXAMPLE_SHARED_H
010 #define EXAMPLE_SHARED_H
011 
012 #include <cstdio>
013 #include <cstdlib>
014 
015 #include <mi/neuraylib.h>
016 
017 #ifdef MI_PLATFORM_WINDOWS
018 #include <mi/base/miwindows.h>
019 #else
020 #include <dlfcn.h>
021 #include <unistd.h>
022 #endif
023 
024 #include "authentication.h"
025 
026 // Pointer to the DSO handle. Cached here for unload().
027 void* g_dso_handle = 0;
028 // Pointer to the DSO filename. Cached here for unload().
029 const char* g_filename = 0;
030 
031 // Ensures that the console with the log messages does not close immediately. On Windows, the user
032 // is asked to press enter. On other platforms, nothing is done as the examples are most likely
033 // started from the console anyway.
034 void keep_console_open() {
035 #ifdef MI_PLATFORM_WINDOWS
036     if( IsDebuggerPresent()) {
037         fprintf( stderr, "Press enter to continue . . . \n");
038         fgetc( stdin);
039     }
040 #endif // MI_PLATFORM_WINDOWS
041 }
042 
043 // Helper macro. Checks whether the expression is true and if not prints a message and exits.
044 #define check_success( expr) \
045     do { \
046         if( !(expr)) { \
047             fprintf( stderr, "Error in file %s, line %u: \"%s\".\n", __FILE__, __LINE__, #expr); \
048             keep_console_open(); \
049             exit( EXIT_FAILURE); \
050         } \
051     } while( false)
052 
053 // Helper function similar to check_success(), but specifically for the result of
054 // #mi::neuraylib::INeuray::start().
055 void check_start_success( mi::Sint32 result)
056 {
057     if( result == 0)
058         return;
059     fprintf( stderr, "mi::neuraylib::INeuray::start() failed with return code %d.\n", result);
060     fprintf( stderr, "Typical failure reasons are related to authentication, see the\n");
061     fprintf( stderr, "documentation of this method for details.\n");
062     keep_console_open();
063     exit( EXIT_FAILURE);
064 }
065 
066 // printf() format specifier for arguments of type LPTSTR (Windows only).
067 #ifdef MI_PLATFORM_WINDOWS
068 #ifdef UNICODE
069 #define FMT_LPTSTR "%ls"
070 #else // UNICODE
071 #define FMT_LPTSTR "%s"
072 #endif // UNICODE
073 #endif // MI_PLATFORM_WINDOWS
074 
075 // Loads the neuray library and calls the main factory function.
076 //
077 // This convenience function loads the neuray DSO, locates and calls the #mi_neuray_factory()
078 // function. It returns an instance of the main #mi::neuraylib::INeuray interface. It also
079 // supplies a authentication key (only needed by some variants of the neuray library).
080 // The function may be called only once.
081 //
082 // \param filename    The file name of the DSO. It is feasible to pass \c NULL, which uses a
083 //                    built-in default value.
084 // \return            A pointer to an instance of the main #mi::neuraylib::INeuray interface
085 mi::neuraylib::INeuray* load_and_get_ineuray( const char* filename = 0)
086 {
087 #ifdef MI_PLATFORM_WINDOWS
088     if( !filename)
089         filename = "libneuray.dll";
090     g_filename = filename;
091     void* handle = LoadLibraryA((LPSTR) filename);
092     if( !handle) {
093         LPTSTR buffer = 0;
094         LPTSTR message = TEXT("unknown failure");
095         DWORD error_code = GetLastError();
096         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
097             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
098             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
099             message = buffer;
100         fprintf( stderr, "Failed to load library (%u): " FMT_LPTSTR, error_code, message);
101         if( buffer)
102             LocalFree( buffer);
103         return 0;
104     }
105     void* symbol = GetProcAddress((HMODULE) handle, "mi_neuray_factory");
106     if( !symbol) {
107         LPTSTR buffer = 0;
108         LPTSTR message = TEXT("unknown failure");
109         DWORD error_code = GetLastError();
110         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
111             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
112             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
113             message = buffer;
114         fprintf( stderr, "GetProcAddress error (%u): " FMT_LPTSTR, error_code, message);
115         if( buffer)
116             LocalFree( buffer);
117         return 0;
118     }
119 #else // MI_PLATFORM_WINDOWS
120     if( !filename)
121         filename = "libneuray.so";
122     g_filename = filename;
123 #ifdef MI_PLATFORM_MACOSX
124     void* handle = dlopen( filename, RTLD_LAZY);
125 #else // MI_PLATFORM_MACOSX
126     void* handle = dlopen( filename, RTLD_LAZY|RTLD_DEEPBIND);
127 #endif // MI_PLATFORM_MACOSX
128     if( !handle) {
129         fprintf( stderr, "%s\n", dlerror());
130         return 0;
131     }
132     void* symbol = dlsym( handle, "mi_neuray_factory");
133     if( !symbol) {
134         fprintf( stderr, "%s\n", dlerror());
135         return 0;
136     }
137 #endif // MI_PLATFORM_WINDOWS
138     g_dso_handle = handle;
139 
140     typedef mi::neuraylib::INeuray* (INeuray_factory)
141         (mi::neuraylib::IAllocator*, mi::Uint32);
142     INeuray_factory* factory = (INeuray_factory*) symbol;
143     mi::neuraylib::INeuray* neuray = factory( 0, MI_NEURAYLIB_API_VERSION);
144     if( neuray)
145         check_success( authenticate( neuray) == 0);
146     return neuray;
147 }
148 
149 // Unloads the neuray library.
150 bool unload()
151 {
152 #ifdef MI_PLATFORM_WINDOWS
153     int result = FreeLibrary( (HMODULE)g_dso_handle);
154     if( result == 0) {
155         LPTSTR buffer = 0;
156         LPTSTR message = TEXT("unknown failure");
157         DWORD error_code = GetLastError();
158         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
159             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
160             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
161             message = buffer;
162         fprintf( stderr, "Failed to unload library (%u): " FMT_LPTSTR, error_code, message);
163         if( buffer)
164             LocalFree( buffer);
165         return false;
166     }
167     return true;
168 #else
169     int result = dlclose( g_dso_handle);
170     if( result != 0)
171         fprintf( stderr, "%s\n", dlerror());
172 #ifdef MI_PLATFORM_MACOSX
173     void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD);
174 #else // MI_PLATFORM_MACOSX
175     void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD|RTLD_DEEPBIND);
176 #endif // MI_PLATFORM_MACOSX
177     return handle == 0;
178 #endif
179 }
180 
181 // Sleep the indicated number of seconds.
182 void sleep_seconds( mi::Uint32 seconds)
183 {
184 #ifdef MI_PLATFORM_WINDOWS
185     Sleep( seconds * 1000);
186 #else
187     sleep( seconds);
188 #endif
189 }
190 
191 // Map snprintf to _snprintf on Windows.
192 #ifdef MI_PLATFORM_WINDOWS
193 #define snprintf _snprintf
194 #endif
195 
196 #endif // MI_EXAMPLE_SHARED_H