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:
- A 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.
- A 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, 2014 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 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, 2014 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 { 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( int 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