| DSO shaders

Pixie supports the use of DSO functions. That means, you can call regular C/C++ functions implemented in a dll/so from the shading language as if they were built in functions. This is a very powerful mechanism allowing you to use C/C++ functions from your shaders. The mechanism is quite simple:

### In DLL / SO

You need to include shadeop.h which contains the necessary macros. For each function you implemented as a DSO, you need to create a SHADEOP table:

#include <shadeop.h>
//This is the shadeop dispatch table
//The renderer and the shading language compiler will
// check this table to figure out what function in the
// dll/so implements what.
//
//Each line in the table designates a function
SHADEOP_TABLE(myfun) = {
{"float myfun_f(vector)","myinit_f","mycleanup_f"},
{"vector myfun_v(float,float,float)","",""},
{""} // End the table with an empty entry
};
// This is the function that implements
// float myfun(vector)
SHADEOP(myfun_f) {
float *result = (float *) argv[0];
float *input = (float *) argv[1];
result[0] = (input[0] + input[1] + input[2]) / (float) 3;
}
// This is the init function for the previous function
SHADEOP_INIT(myiniy_f) {
return NULL;
}
// This is the cleanup function for the previous function
SHADEUP_CLEANUP(mycleanup_f) { }
// This is the function that implements
// vector myfun(float,float,float)
SHADEOP(myfun_v) {
float *result = (float *) argv[0];
float *input1 = (float *) argv[1];
float *input2 = (float *) argv[2];
float *input3 = (float *) argv[3];
result[0] = input1[0];
result[1] = input2[0];
result[2] = input3[0];
}

The macro SHADEOP_TABLE(name) defines a table that contains the prototype for the DSO function and the names of the init and cleanup functions for that function for each different polymorphic occurrence of the function name in the DSO. The init function is called when the dll/so is first loaded into the memory. It must accept two arguments: a thread ID and a texture context pointer both of which are 0 with PIXIE. These parameters are provided for compatibility reasons. The init function must return a void * pointer to a transparent handle for the function. This handle will be passed to the DSO function and the cleanup functions. The cleanup function must do any cleanup required by the DSO (for example, de-allocating the memory that the init function allocates). The only parameter that this cleanup function accepts is the transparent handle that the init function returns. Finally, the actual DSO function executes the function. This function receives 3 arguments:

- void *initdata
  This is the handle that the init function returns.
- int argc
  This is the number of arguments passed to the DSO. Note that this is a redundant argument as you can clearly see the number of arguments at the prototype of the function. For example, for float myfun(vector) it will always be 2 (includes the return value).
- void *argv[]
  This is the array of pointers that contains the arguments. The argv[0] always points to the return value. If there is no return value (void function), this argument is not used.

For example, "float myfun_f(vector)","myinit_f","mycleanup_f" means that the function myfun_f implements the function float myfun(vector). So whenever, the renderer needs to execute this particular function, myfun_f will be called. The init and cleanup functions for this function are myinit_f and mycleanup. These functions are called only once before the first usage of the myfun_f and after the last usage of myfun_f. The code provided above also contains another form of "myfun" which is polymorphic to the first one: "vector myfun_v(float,float,float)","","". This means, that myfun_v implements vector myfun(float,float,float). This version of the function myfun does not have any init or cleanup functions (as indicated by ""), so the initdata parameter with be NULL all the time. The DSO shaders prepared for the PrMan, Entrophy and RenderDotC should be compatible with Pixie although I did not test it yet.

### In SL

In your shader code, you can now use vector myfun(float,float,float) and float myfun(vector) without any trouble. The dll/so that contains the implementation must be in the include directory (indicated by -I parameter). Similarly, the dll/so that has the implementation must be in the procedural search path. One important thing that you need to be careful about is that Pixie assumes all the parameters passed to a DSO function are defined as output. That means if DSO changes an argument, the change will stick !!!. One last note: a single dll/so may have multiple DSO's. The Pixie will automatically search all the dll/so's in the input directory for the correct DSO.

##