Starting and shutting down the Iray API
This topic introduces:
-
The neuray object, which is your access point to the system
-
The required interfaces and methods:
-
mi::neuraylib::INeuray interface, which is used to start and shutdown the Iray API
-
mi_neuray_factory() call, which is used to create the neuray object
-
mi::neuraylib::INeuray::get_status(), which is used to query the status of the Iray API
-
-
example_start_shutdown.cpp, which demonstrates how to start up and shut down the Iray API
-
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:
- 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.
- 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