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, 2015 NVIDIA ARC GmbH. 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     check_success( neuray->start( true) == 0);
048 
049     // scene graph manipulations and rendering calls go here, none in this example.
050 
051     // Shutting down in blocking mode. Again, a return code of 0 indicates success.
052     check_success( neuray->shutdown( true) == 0);
053     neuray = 0;
054 
055     // Unload the neuray library
056     check_success( unload());
057 
058     keep_console_open();
059     return EXIT_SUCCESS;
060 }

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, 2015 NVIDIA ARC GmbH. 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     { if( !(expr)) { \
046         fprintf( stderr, "Error in file %s, line %u: \"%s\".\n", __FILE__, __LINE__, #expr); \
047         keep_console_open(); \
048         exit( EXIT_FAILURE); } }
049 
050 // printf() format specifier for arguments of type LPTSTR (Windows only).
051 #ifdef MI_PLATFORM_WINDOWS
052 #ifdef UNICODE
053 #define FMT_LPTSTR "%ls"
054 #else // UNICODE
055 #define FMT_LPTSTR "%s"
056 #endif // UNICODE
057 #endif // MI_PLATFORM_WINDOWS
058 
059 // Loads the neuray library and calls the main factory function.
060 //
061 // This convenience function loads the neuray DSO, locates and calls the #mi_neuray_factory()
062 // function. It returns an instance of the main #mi::neuraylib::INeuray interface. It also
063 // supplies a authentication key (only needed by some variants of the neuray library).
064 // The function may be called only once.
065 //
066 // \param filename    The file name of the DSO. It is feasible to pass \c NULL, which uses a
067 //                    built-in default value.
068 // \return            A pointer to an instance of the main #mi::neuraylib::INeuray interface
069 mi::neuraylib::INeuray* load_and_get_ineuray( const char* filename = 0)
070 {
071 #ifdef MI_PLATFORM_WINDOWS
072     if( !filename)
073         filename = "libneuray.dll";
074     g_filename = filename;
075     void* handle = LoadLibraryA((LPSTR) filename);
076     if( !handle) {
077         LPTSTR buffer = 0;
078         LPTSTR message = TEXT("unknown failure");
079         DWORD error_code = GetLastError();
080         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
081             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
082             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
083             message = buffer;
084         fprintf( stderr, "Failed to load library (%u): " FMT_LPTSTR, error_code, message);
085         if( buffer)
086             LocalFree( buffer);
087         return 0;
088     }
089     void* symbol = GetProcAddress((HMODULE) handle, "mi_neuray_factory");
090     if( !symbol) {
091         LPTSTR buffer = 0;
092         LPTSTR message = TEXT("unknown failure");
093         DWORD error_code = GetLastError();
094         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
095             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
096             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
097             message = buffer;
098         fprintf( stderr, "GetProcAddress error (%u): " FMT_LPTSTR, error_code, message);
099         if( buffer)
100             LocalFree( buffer);
101         return 0;
102     }
103 #else // MI_PLATFORM_WINDOWS
104     if( !filename)
105         filename = "libneuray.so";
106     g_filename = filename;
107 #ifdef MI_PLATFORM_MACOSX
108     void* handle = dlopen( filename, RTLD_LAZY);
109 #else // MI_PLATFORM_MACOSX
110     void* handle = dlopen( filename, RTLD_LAZY|RTLD_DEEPBIND);
111 #endif // MI_PLATFORM_MACOSX
112     if( !handle) {
113         fprintf( stderr, "%s\n", dlerror());
114         return 0;
115     }
116     void* symbol = dlsym( handle, "mi_neuray_factory");
117     if( !symbol) {
118         fprintf( stderr, "%s\n", dlerror());
119         return 0;
120     }
121 #endif // MI_PLATFORM_WINDOWS
122     g_dso_handle = handle;
123 
124     typedef mi::neuraylib::INeuray* (INeuray_factory)
125         (mi::neuraylib::IAllocator*, mi::Uint32);
126     INeuray_factory* factory = (INeuray_factory*) symbol;
127     mi::neuraylib::INeuray* neuray = factory( 0, MI_NEURAYLIB_API_VERSION);
128     if( neuray)
129         check_success( authenticate( neuray) == 0);
130     return neuray;
131 }
132 
133 // Unloads the neuray library.
134 bool unload()
135 {
136 #ifdef MI_PLATFORM_WINDOWS
137     int result = FreeLibrary( (HMODULE)g_dso_handle);
138     if( result == 0) {
139         LPTSTR buffer = 0;
140         LPTSTR message = TEXT("unknown failure");
141         DWORD error_code = GetLastError();
142         if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
143             FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
144             MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
145             message = buffer;
146         fprintf( stderr, "Failed to unload library (%u): " FMT_LPTSTR, error_code, message);
147         if( buffer)
148             LocalFree( buffer);
149         return false;
150     }
151     return true;
152 #else
153     int result = dlclose( g_dso_handle);
154     if( result != 0)
155         fprintf( stderr, "%s\n", dlerror());
156 #ifdef MI_PLATFORM_MACOSX
157     void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD);
158 #else // MI_PLATFORM_MACOSX
159     void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD|RTLD_DEEPBIND);
160 #endif // MI_PLATFORM_MACOSX
161     return handle == 0;
162 #endif
163 }
164 
165 // Sleep the indicated number of seconds.
166 void sleep_seconds( mi::Uint32 seconds)
167 {
168 #ifdef MI_PLATFORM_WINDOWS
169     Sleep( seconds * 1000);
170 #else
171     sleep( seconds);
172 #endif
173 }
174 
175 // Map snprintf to _snprintf on Windows.
176 #ifdef MI_PLATFORM_WINDOWS
177 #define snprintf _snprintf
178 #endif
179 
180 #endif // MI_EXAMPLE_SHARED_H