neuray API Programmer's Manual

Example for Starting and Shutting Down the neuray API

[Next] [Up]

This example accesses the main neuray interface, queries the API version, and then starts and shuts down the neuray 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 neuray API.

Detailed Description

Naming conventions

The neuray library 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/neuraylib.h provides all the functionality of the neuray API.

Main API access point

The mi_neuray_factory() function is the only public access point to all algorithms and data structures in the API (see Library Design for an explanation why.) The factory function tries to access the neuray API. If the access succeeds, it returns a pointer to an instance of the main mi::neuraylib::INeuray interface. The mi_neuray_factory() function may be called only once per process.

Before you are able to call the mi_neuray_factory() function, you need to load the neuray 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 neuray DSO and to locate the factory function. In such cases, you call mi_neuray_factory() directly. For simplicity, the examples will use the convenience function load_and_get_ineuray() instead of mi_neuray_factory().

Interfaces and handles

Except for trivial classes, such as the math vector class, all classes in the neuray API are implemented using interfaces. See Library Design for an explanation. Interfaces are created and destroyed by the neuray 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::tr1::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::tr1::shared_ptr<T> p (mi_neuray_factory(), std::mem_fun (&T::release));

Starting and shutting down the neuray API

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

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

Finally, you have to shut down the neuray 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/example_shared.h

‎/******************************************************************************
 * Copyright 1986, 2011 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/

// examples/example_shared.h
//
// Code shared by all examples

#ifndef EXAMPLE_SHARED_H
#define EXAMPLE_SHARED_H

#include <cstdio>
#include <cstdlib>

#include <mi/neuraylib.h>

#ifdef MI_PLATFORM_WINDOWS
#include <mi/base/miwindows.h>
#else
#include <dlfcn.h>
#include <unistd.h>
#endif

#include "authentication.h"

// Pointer to the DSO handle. Cached here for unload().
void* g_dso_handle = 0;
// Pointer to the DSO filename. Cached here for unload().
const char* g_filename = 0;

// Helper macro. Checks whether the expression is true and if not prints a message and exits.
#define check_success( expr) \
    { if( !(expr)) { fprintf( stderr, "Error in file %s, line %d.\n", __FILE__, __LINE__); \
        exit( EXIT_FAILURE); } }

// printf() format specifier for arguments of type LPTSTR (Windows only).
#ifdef MI_PLATFORM_WINDOWS
#ifdef UNICODE
#define FMT_LPTSTR "%ls"
#else // UNICODE
#define FMT_LPTSTR "%s"
#endif // UNICODE
#endif // MI_PLATFORM_WINDOWS

// Loads the neuray library and calls the main factory function.
//
// This convenience function loads the neuray DSO, locates and calls the #mi_neuray_factory()
// function. It returns an instance of the main #mi::neuraylib::INeuray interface. It also
// supplies a authentication key (only needed by some variants of the neuray library).
// The function may be called only once.
//
// \param filename    The file name of the DSO. It is feasible to pass \c NULL, which uses a
//                    built-in default value.
// \return            A pointer to an instance of the main #mi::neuraylib::INeuray interface
mi::neuraylib::INeuray* load_and_get_ineuray( const char* filename = 0)
{
#ifdef MI_PLATFORM_WINDOWS
    if( !filename)
        filename = "libneuray.dll";
    g_filename = filename;
    void* handle = LoadLibraryA((LPSTR) filename);
    if( !handle) {
        LPTSTR buffer = 0;
        LPTSTR message = TEXT("unknown failure");
        int error_code = GetLastError();
        if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
            message = buffer;
        printf( "Failed to load library (%d): " FMT_LPTSTR, error_code, message);
        if( buffer)
            LocalFree( buffer);
        return 0;
    }
    void* symbol = GetProcAddress((HMODULE) handle, "mi_neuray_factory");
    if( !symbol) {
        LPTSTR buffer = 0;
        LPTSTR message = TEXT("unknown failure");
        int error_code = GetLastError();
        if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
            message = buffer;
        printf( "GetProcAddress error (%d): " FMT_LPTSTR, error_code, message);
        if( buffer)
            LocalFree( buffer);
        return 0;
    }
#else // MI_PLATFORM_WINDOWS
    if( !filename)
        filename = "libneuray.so";
    g_filename = filename;
#ifdef MI_PLATFORM_MACOSX
    void* handle = dlopen( filename, RTLD_LAZY);
#else // MI_PLATFORM_MACOSX
    void* handle = dlopen( filename, RTLD_LAZY|RTLD_DEEPBIND);
#endif // MI_PLATFORM_MACOSX
    if( !handle) {
        printf( "%s\n", dlerror());
        return 0;
    }
    void* symbol = dlsym( handle, "mi_neuray_factory");
    if( !symbol) {
        printf( "%s\n", dlerror());
        return 0;
    }
#endif // MI_PLATFORM_WINDOWS
    g_dso_handle = handle;

    typedef mi::neuraylib::INeuray* (INeuray_factory)
        (mi::neuraylib::IAllocator*, mi::Uint32);
    INeuray_factory* factory = (INeuray_factory*) symbol;
    mi::neuraylib::INeuray* neuray = factory( 0, MI_NEURAYLIB_API_VERSION);
    if( neuray)
        check_success( authenticate( neuray) == 0);
    return neuray;
}

// Unloads the neuray library.
bool unload()
{
#ifdef MI_PLATFORM_WINDOWS
    int result = FreeLibrary( (HMODULE)g_dso_handle);
    if( result == 0) {
        LPTSTR buffer = 0;
        LPTSTR message = TEXT("unknown failure");
        int error_code = GetLastError();
        if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS, 0, error_code,
            MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buffer, 0, 0))
            message = buffer;
        printf( "Failed to unload library (%d): " FMT_LPTSTR, error_code, message);
        if( buffer)
            LocalFree( buffer);
        return false;
    }
    return true;
#else
    int result = dlclose( g_dso_handle);
    if( result != 0)
        printf( "%s\n", dlerror());
#ifdef MI_PLATFORM_MACOSX
    void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD);
#else // MI_PLATFORM_MACOSX
    void* handle = dlopen( g_filename, RTLD_LAZY|RTLD_NOLOAD|RTLD_DEEPBIND);
#endif // MI_PLATFORM_MACOSX
    return handle == 0;
#endif
}

// Sleep the indicated number of seconds.
void sleep_seconds( int seconds)
{
#ifdef MI_PLATFORM_WINDOWS
    Sleep( seconds * 1000);
#else
    sleep( seconds);
#endif
}

#endif // MI_EXAMPLE_SHARED_H

Source Code Location: examples/example_start_shutdown.cpp

‎/******************************************************************************
 * Copyright 1986, 2011 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/

// examples/example_start_shutdown.cpp
//
// Obtain an INeuray interface, start neuray and shut it down.

#include <mi/neuraylib.h>

// Include code shared by all examples.
#include "example_shared.h"

// The main function initializes the neuray library, starts it, and shuts
// it down after waiting for user input.
int main( int argc, char* argv[])
{
    // Get the INeuray interface in a suitable smart pointer.
    mi::base::Handle< mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
    if ( ! neuray.is_valid_interface()) {
        fprintf( stderr, "Error: The neuray library failed to load and to provide "
                 "the mi::neuraylib::INeuray interface for the API version %d.\n",
                 MI_NEURAYLIB_API_VERSION);
        return EXIT_FAILURE;
    }

    // Access API and library version numbers.
    mi::Uint32 interface_version = neuray->get_interface_version();
    const char *version = neuray->get_version();
    printf( "neuray header  API interface version = %d\n", MI_NEURAYLIB_API_VERSION);
    printf( "neuray header  API version           = %s\n",
         MI_NEURAYLIB_VERSION_QUALIFIED_STRING);
    printf( "neuray library API interface version = %d\n", interface_version);
    printf( "neuray library build version string  = \"%s\".\n", version);

    // configuration settings go here, none in this example

    // After all configurations, neuray is started. An exit code of 0
    // says that neuray started successfully. Otherwise the log, which
    // in this example is not configured and prints to the console
    // by default, will contain error diagnostics.
    //    The neuray start can be blocking or non-blocking. Here the
    // blocking mode is used so that you know that neuray 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.
    check_success( neuray->start( true) == 0);

    // scene graph manipulations and rendering calls go here, none in this example.

    // Instead we ask for a user input before shutting down. You can connect to
    // the admin console while the program is waiting here.
    printf( "Hit <return> to quit neuray.\n");
    std::getchar();

    // Shutting down without setting a timeout. The return result must be 0
    // indicating success.
    check_success( neuray->shutdown( true) == 0);
    neuray = 0;

    // Unload the neuray library
    check_success( unload());

    return EXIT_SUCCESS;
}

[Next] [Up]