Keywords: main

Next: 3.2 Coordinate Systems Up: 3. Using and Writing Previous: 3. Using and Writing

# 3.1 Dynamic Linking of Shaders

Shaders are written as C or C++ subroutines, stored in files with the extension ```.c`''. To use these shaders in a scene, they must be dynamically linked into mental ray at runtime. mental ray accepts shaders in three forms:

- Directly as source code. The .mi file offers the code statement and the standalone renderer has a `-code` option. Both accept a source file with a `.c` extension.

- In object format. Source files can be compiled to object code using Unix commands such as ```cc -O -c source.c`'' (assuming that the shader source is in a file named `source.c`). The command may vary on some platforms, consult the manual (see ```man cc`)''. On Windows NT systems, shared libraries are called DLLs. This is the most common form on systems that do not support DSOs; it is faster than source because mental ray does not have to compile the shader. The compilation leaves a `source.o` file with the extension `.o` in the current directory. This file can be passed to mental ray using the link statement in the .mi file, or with the `-link` option of the standalone renderer.

- In DSO format. DSO stands for Dynamic Shared Object. DSOs are supported on most platforms, such as SGI systems running IRIX 5.2 or higher. The operating system version can be found by running the Unix command ```uname -r`''. DSOs have the extension `.so` on SGI systems and other extensions on other systems, but it is highly recommended to use `.so` on all systems. This makes it possible to use the same name on all systems regardless of type. mental ray automatically substitutes `.dll` for `.so` on Windows NT platforms.

To create a DSO, first compile the shader source to object format using `cc` as described above, then run the Unix command ```ld -shared source.o`'', again assuming that the object file is called `source.o`. This `ld` command applies to SGI IRIX; refer to ```man ld`'' on other platforms. Using DSOs is the fastest way to load shaders, there is very little overhead. DSOs, like object files, are loaded using `link` statements or `-link` options.

The commands to create a DSO depend on the operating system type. To create a DSO named example.so from a source file example.c, use the following commands. Insert the `-g` command line option after `-c` to insert debugging information, or insert `-O` to compile an optimized version. On most systems `-g` and `-O` cannot be combined. Refer to the compiler documentation for details.

- Linux x86 `gcc -c -O2 -fPIC shader.c
  ld -export-dynamic -shared -o shader.so shader.o`

- Linux Alpha
  `gcc -c -O2 -fPIC -mieee shader.c
  ld -export-dynamic -shared -o shader.so shader.o`

- SGI IRIX
  `cc` opt `-shared -o example.so example.c`

- HP/UX
  `cc -c -Aa +z example.c
  ld -b -o example.so example.o`

- IBM AIX
  `cc -c example.c
  ld -o example.so example.o -bE:example.exp extra.so
  -bI:keep.exp -bM:SRE -T512 -H512 -lc`
  `example.exp` is a user supplied export file for the shader and must contain the names of the exported symbols, one per line. `keep.exp` is the list of symbols exported by mental ray, either for use by shaders or for internal linking purposes. It is supplied with mental ray and can be referenced using an absolute path name. `extra.so` must be supplied to allow linking with shader libraries that are preloaded during runtime (such as `physics.so`) if functions from that library are used directly.

- Sun Solaris 2
  `cc -c -D_REENTRANT example.c
  ld -G -o example.so example.o -ldl`
  (Using Sun CC; gcc can also be used.)

- Digital Unix V5.0
  `cc -c -newc -O2 -ieee_with_no_inexact -D_REENTRANT example.c
  ld -expect_unresolved '*' -shared -o example.so example.o`

- Windows NT
  `cl /c /O2 /MD /nologo example.c
  link /nologo /DLL /nodefaultlib:LIBC.LIB
  /OUT:example.dll example.obj shader.lib`
  (Using Visual C++ 6.x or up; earlier versions are too buggy.) `shader.lib` is a stub library that is provided with mental ray. It is necessary because Windows NT cannot automatically share symbols between modules sharing a process. Note that the Visual C++ optimizer may introduce bugs into your code, causing (possibly intermittent) malfunctions that are very hard to find. Always test without optimization (without `/O2`)! Or use Intel's Proton/Electron compilers.

Compiling and creating DSOs requires that a C development environment is installed on the system. If the `cc` and `ld` commands are not found, make sure that a development environment exists. On most platforms, it is a separate product that must be purchased separately. Dynamically loading a DSO does not require compilers or development options.

SGI offers a range of processors, with later processors having more instruction set features than earlier ones. While newer processors and newer operating system versions can execute older programs (as long as they all use the ELF object format), programs and shaders should be compiled for newer instruction sets to improve performance. Four instruction sets have been defined by MIPS, called mips1 through mips4. mips3 is about 30% faster than mips2 on the same system. mips4 should be used if a very large virtual address space (4 terabytes) is required to keep large numbers of large textures. Choose the opt options string according to the following table:

IRIX | instruction set | CPU | word size | opt
6.x | mips2 | R4000 and up | 32 bits | `-32`
6.x | mips3 | R4400 and up | 32 bits | `-n32`
6.x | mips4 | R8000 and up | 64 bits | `-64`

The first is obsolete. In any case, the options must agree with the version of mental ray. See the abi(5) manual page for more details. Use the Unix `file` command on mental ray and the shader library and make sure that they both report the same number of bits and the same MIPS version. If there is a mismatch, the run-time linker will print a message like:

        /my/shader.so: 1234:ray: rld: Fatal Error:
           cannot successfully map soname '/my/shader.so'
           under any of the filenames /my/shader.so

The run-time linker always tries to match executables and libraries, which allows multiple ABIs to reside on the same system without conflicts. If the filename of the DSO given as an absolute pathname mental ray only tries to load that particular file. If it is given as a relative path, mental ray searches the DSO in a list of paths that can be supplied via the command line parameter (`-ld_path`) or the environment variable (`MI_LIBRARY_PATH`). There is also a default search path (`/usr/local/mi/lib;.`). A search list is a colon-separated (Unix) or semicolon-separated (Unix or Windows NT) list of paths to be searched. (Windows NT uses colons for drive letters.)

Note that source code (`.c` extension) is normally portable, unless nonportable system features (such as fsqrt on SGIs) are used. This means that the shader will run on all other vendors' systems unchanged. If the compilation fails and the shaders therefore are undefined, mental ray will -- when calls of the undefined shaders are attempted -- return `miFALSE`, which will generally leave the pixel sample black.

Neither object files (`.o` extension) nor DSOs (`.so` extension) are portable. They must be compiled separately for each platform and, usually, for each major operating system release. For example, a Hewlett-Packard object file will not run on an SGI system, and an SGI IRIX 4.x object file cannot be used on an IRIX 6.x system, and vice versa. Also note that pointers are 32-bit values on some systems and 64-bit values on others, and that most but not all (IBM) processors require that 64-bit values such as `double`s are stored at memory addresses evenly divisible by 8.

On SGI systems, a shader can be debugged after it has been called for the first time, which attaches it to the program and makes its symbols available to the debugger. For this to work, the `-g` option must be given to the `cc` and `ld` commands in all stages -- compilation, linking, and shared-library building. Also, only DSO shaders are debuggable, not shaders loaded in object (`.o`) or source (`.c`) form.

On non-SGI systems, debugging shaders is, unfortunately, difficult. The reason is that most debuggers cannot deal with parts of a program that have been dynamically linked. In general, the debugger will refuse to set breakpoints in dynamically linked shaders, and will step over calls to these shaders as if they were a single operating system call. Some vendors are working on fixing these problems, but at this time the only option on non-SGI systems is using mi_info or mi_debug statements in the shader sources. Avoid printf because it is lost on slave hosts and because it can cause problems at runtime.

Windows NT shader libraries must use at least one shader interface call (any true C function beginning with mi_), or an error message ```DLL_SetModuleHandle not found`'' will occur.

When a shared library is loaded that contains a function module_init, that function is called just after the library was loaded, before the first shader in it is called. Conversely, if it contains a function module_exit, that function is called just before the library is unloaded, after the last call to a shader in this library. Note that in the case of irrecoverable errors at any time after the library was loaded module_exit is not guaranteed to be called. Neither module_init nor module_exit may rely on any shader interface services that assume that a rendering operation is in progress. Message functions such as mi_info are available. Note: this feature is not supported on IBM systems and should not be used for portable shaders.

Next: 3.2 Coordinate Systems Up: 3. Using and Writing Previous: 3. Using and Writing