Dynamic network of callable programs for materials

Hey,

I want to create a material network of callable programs to use for shading in a raytracer, similar to what is shown in the Pixar Flow demo, and I’m wondering what the best way to go about it is.

I’ve had two separate general ideas for how to go about it but I’m not sure of the efficiency of either.

User struct for node values and input connections.
Use a struct containing the default values, and possible input connections using an buffer location for the next node in the network, and it’s type to know in what buffer to look in. These struct would form the network and passed to the callable program as an arg to drive the actual shader math.
This is kind of similar to how the advanced sample single shader works, just with more driving structs and programs.

Use instances of the callable program and bind custom variables.
The callable program itself would have no arguments, a single instance for use in a network would be generated and variables set for both the defalt values or programIDs representing connections to unique nodes.
There however have been several warnings about too many variables in scoped mode on an object, does that also apply to bindless callable programs. The docs say they only can see their own scope.

Anyone have an idea between these, or a better way altogether?

See this thread as well: https://devtalk.nvidia.com/default/topic/1030935/?comment=5245078

I do not know the runtime performance impact of a full blown shader graph with bindless callable programs over a more monolithic implementation with a pre-compiled shader graph to a single bindless callable program as I’m doing it. For that I would need to implement both ways and I didn’t have the time for that, yet.

Simple example code for the “fixed building blocks” method inside the OptiX introduction examples.
Block diagram of the renderer architecture at the end of the readme page.
https://devtalk.nvidia.com/default/topic/998546/optix/optix-advanced-samples-on-github/

Thanks for that. I was able to implement a system using bindless callable programs for various “nodes”, and at least simple networks of a couple programs worked well and didn’t seem to cause a major FPS drop vs a monolithic shader program.

It is pretty much a similar system to the shade tree from the 3.9 SDK, which has been removed from the latest SDK packages.

I’ll do some more performance testing and see what I get.

The next step, and something mentioned in the Pixar talk, is a cache of shading program values to lookup instead of calling the same program many times in a network.

I had looked at using a hash table on device for this, but instead of a hash just use the programId for a Buffer index and store the value. This however would need to be created in the Closest Hit so that it is unique per time the shader tree is calculated and I have not seen an example of a Buffer created on the device, and only existing for one program.

The other idea I had was for a it to be a callable program that takes a references to a struct for an input, along with the requested programId to run, the struct has a fixed amount of storage for programIds and values, and the callable program searches the struct for a given ID and returns the value, otherwise it calls the shader program, gets the value and replaces the oldest of the stored values. This would be passed around the shader tree and run while calling any connection between nodes.

However I worry that for some nodes that caching process would take longer then the simple function the program performs.