Iray Programmer's Manual

Extending neuray with plugins

This topic introduces:

  1. Important interfaces and the required steps to add functionality and package it as a plugin:
  2. The programs plugin.cpp and example_plugins.cpp, which demonstrate how to provide additional functionality as plugins. This example extends the user-defined classes described in Extending the database with user-defined classes. The functionality of the IMy_class interface is provided to the main application by using a plugin. Therefore, the main application only needs the definition of the interface IMy_class and the compiled plugin, but not the source code of the implementation.

Implementing a plugin

To implement a plugin you need to provide an implementation of the mi::neuraylib::IPlugin interface. An example implementation of such a class is shown in the code below. The most important part is the implementation of the mi::neuraylib::IPlugin::init() method which has to register all user-defined classes.

Finally you need to provide a factory function called mi_plugin_factory() that creates an instance of your implementation of mi::neuraylib::IPlugin. Again, using the example implementation as shown in the code below is fine.

You need to compile the implementation of your interfaces, your implementation of mi::neuraylib::IPlugin, and the factory function, and to create a DSO from the object code. Using g++ you can use commands similar to the following:

g++ -I$NEURAY_ROOT/include -fPIC -c plugin.cpp -o plugin.o
g++ -shared -export-dynamic --whole-archive plugin.o -o libplugin.so

Loading a plugin

You can load plugins by passing the filename to the method mi::neuraylib::IPlugin_configuration::load_plugin_library(). After the plugin has been loaded (in a way similar to the loading of the DSO for the Iray API itself), the method mi::neuraylib::IPlugin::init() is called. In this method you need to register all user-defined classes.

Using the user-defined class works the same way as for all other classes. In particular there is no difference to user-defined classes defined in the main application as described in Extending the database with user-defined classes.

plugin.cpp

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 #include <mi/neuraylib.h>
006 #include "my_class.h"
007 
008 // Implementation of the IPlugin interface
009 class Plugin_impl : public mi::neuraylib::IPlugin
010 {
011 public:
012     // Virtual destructor
013     virtual ~Plugin_impl() { }
014 
015     // Returns the name of the plugin
016     const char* get_name() const { return "example plugin"; }
017 
018     // Returns the type of the plugin
019     const char* get_type() const { return MI_NEURAYLIB_PLUGIN_TYPE; }
020 
021     // Returns the version of the plugin
022     mi::Sint32 get_version() const { return 1; }
023 
024     // Returns the compiler used to compile the plugin
025     const char* get_compiler() const { return "unknown"; }
026 
027     // Releases the plugin giving back all allocated resources
028     void release() { delete this; }
029 
030     // Initializes the plugin
031     bool init( mi::neuraylib::IPlugin_api* plugin_api)
032     {
033         mi::base::Handle<mi::neuraylib::ILogging_configuration> logging_configuration(
034             plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>());
035         mi::base::Handle<mi::base::ILogger> logger(
036             logging_configuration->get_forwarding_logger());
037         logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN",
038             "Plugin_impl::init() called");
039         mi::base::Handle<mi::neuraylib::IExtension_api> extension_api(
040             plugin_api->get_api_component<mi::neuraylib::IExtension_api>());
041         if( ! extension_api.is_valid_interface())
042             return false;
043         return extension_api->register_class<My_class>( "My_class") == 0;
044     }
045 
046     // Exits the plugin
047     bool exit( mi::neuraylib::IPlugin_api* plugin_api)
048     {
049         mi::base::Handle<mi::neuraylib::ILogging_configuration> logging_configuration(
050             plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>());
051         mi::base::Handle<mi::base::ILogger> logger(
052             logging_configuration->get_forwarding_logger());
053         logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN",
054             "Plugin_impl::exit() called");
055         return true;
056     }
057 };
058 
059 // Factory to create an instance of Plugin_impl
060 extern "C"
061 MI_DLL_EXPORT
062 mi::base::Plugin* mi_plugin_factory(
063     mi::Sint32 index,         // index of the plugin
064     void* context)            // context given to the library, ignore
065 {
066     if( index != 0)
067         return 0;
068     return new Plugin_impl;
069 }

example_plugins.cpp

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 // examples/example_plugins.cpp
006 //
007 // Demonstrates providing additional functionality via plugins
008 
009 #include <mi/neuraylib.h>
010 
011 // Include code shared by all examples.
012 #include "example_shared.h"
013 
014 // Include header file for the interface of the user-defined class.
015 #include "imy_class.h"
016 
017 void test_plugin( mi::base::Handle<mi::neuraylib::INeuray> neuray)
018 {
019 
020     // Get the database, the global scope of the database, and create a transaction in the global
021     // scope.
022     mi::base::Handle<mi::neuraylib::IDatabase> database(
023         neuray->get_api_component<mi::neuraylib::IDatabase>());
024     check_success( database.is_valid_interface());
025     mi::base::Handle<mi::neuraylib::IScope> scope(
026         database->get_global_scope());
027     mi::base::Handle<mi::neuraylib::ITransaction> transaction(
028         scope->create_transaction());
029     check_success( transaction.is_valid_interface());
030 
031     // Create instance of My_class and call a method on it.
032     mi::base::Handle<IMy_class> my_class( transaction->create<IMy_class>( "My_class"));
033     check_success( my_class.is_valid_interface());
034     my_class->set_foo( 42);
035 
036     // Store instance of My_class in the database and release the handle
037     transaction->store( my_class.get(), "some_name");
038     my_class = 0;
039 
040     // Get the instance of My_class from the database again
041     my_class = transaction->edit<IMy_class>( "some_name");
042     check_success( my_class.is_valid_interface());
043     check_success( my_class->get_foo() == 42);
044     my_class = 0;
045 
046     transaction->commit();
047 }
048 
049 int main( int /*argc*/, char* /*argv*/[])
050 {
051     // Access the neuray library
052     mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
053     check_success( neuray.is_valid_interface());
054 
055     // Load the plugin
056     mi::base::Handle<mi::neuraylib::IPlugin_configuration> plugin_configuration(
057         neuray->get_api_component<mi::neuraylib::IPlugin_configuration>());
058     check_success( plugin_configuration.is_valid_interface());
059 #ifndef MI_PLATFORM_WINDOWS
060     check_success( plugin_configuration->load_plugin_library( "./libplugin.so") == 0);
061 #else
062     check_success( plugin_configuration->load_plugin_library( "./plugin.dll") == 0);
063 #endif
064     plugin_configuration = 0;
065 
066     // Start the neuray library
067     check_success( neuray->start() == 0);
068 
069     // Interact with the loaded plugin
070     test_plugin( neuray);
071 
072     // Shut down the neuray library
073     check_success( neuray->shutdown() == 0);
074     neuray = 0;
075 
076     // Unload the neuray library
077     check_success( unload());
078 
079     keep_console_open();
080     return EXIT_SUCCESS;
081 }