Tutorial: How to compute data on the GPU and stream it back to the CPU

May 21, 2013 at 5:08 PM
Edited May 21, 2013 at 5:10 PM
Hi All,

My name is Vladeta Stojanovic and I work as a research assistant in visualisation and modelling at the University of Abertay Dundee. I'm using Optix.Net to create a real-time tool for approximating passive solar gain for arbitrary house shapes (generated using a genetic algorithm). The approximation of the passive solar gain is computed using ray tracing methods facilitated by Optix.Net. I decided to use Optix.Net because it supports C#. Overall, I think Kyle did a great job by porting Optix to the .Net platform.

Anyways, over the past week I had a real headache trying to figure out how to compute data on the GPU and stream it back to the CPU. There seems to be very little practical documentation for Optix, let alone Optix.Net. Thus I would like outline the steps I followed for calcuting numerical data on the GPU (using Optix and CUDA C), and streaming it back to the CPU via a simple buffer streaming operation. Overall, the entire process is very straightforward, but I had to hack, debug and guess my way to the solution. Thus I'm writing this short tutorial post so other don't have to go through all the bumps along the way to learning and using Optix.Net. Sharing knowledge is power, after all.

So, in this example, in order to compute a floating point value on the GPU and stream it back to the CPU, the following steps should be taken:

1) Create a Optix buffer:
BufferDesc desc = new BufferDesc()
  Width = (uint)Width,
  Height = (uint)Height,
  Format = Format.Float,
  Type = BufferType.InputOutput //could just be Output

ResultsBuffer = new OptixDotNet.Buffer(Context, desc);
2) Create a mirror buffer for the Optix CUDA kernel in the desired .cu shader:
  rtBuffer<float, 2> gainResults;
3) Compute the results you want and store them in the buffer via the CUDA kernel in the .cu shader:
RT_PROGRAM void envmap_miss()
  prd_radiance.result = CalculateSkyColor();

  gainResults[launch_index] = 66776.2133f; //test result
Notice that I'm using the RT_PROGRAM specific to the event of the rays not intersecting any geometry. Since the scene I'm using has a skybox, the result can be computed and updated every frame. Also, I'm storing the computed results in the buffer using the launch_index, which is a 2D array operation (as it is relative to the screen width & height, as each ray is projected from each screen pixel, where the result is projected back in screen-space from world-space).

3) Then finally, back to the C# code, to stream the data back from the GPU device to the CPU host device, I use the following code:
protected override void RayTrace()
  Context.Launch( 0, (uint)Width, (uint)Height );

  //Get results
  BufferStream stream = ResultsBuffer.Map();


Hope that clarifies some things for anyone who is using Optix.Net for more scientific visualisation/computation purposes.



May 22, 2013 at 2:15 AM
Edited May 22, 2013 at 4:46 AM
Hi Vlad

Many thanks for sharing that tut your right there seems very little info for Optix in general im still looking for tuts on

Layered Shaders
Image Based Lighting
Bump/Normal Mapping
Sky/Sun Modeling/Atmospheric-Scattering LINK Example with code or LINK example with better code
FOG/Mist LINK Example
Bloom Realtime Post Effect

The layered shaders i am working on right now using Buffers like the lights do and seems to be working nicely so far need to still sort out masking between the shaders all fun....:)

the atmospheric scattering example has some code but my c++ is really not that great to even convert it i would imagine that the image would be created once and just mapped to a sphere and then recreated if any parameters where changed like an environment map...
May 22, 2013 at 9:19 AM
Hi Mentalarray,

Those are some great links! I think it's a good idea for us as a community of Optix users (and Optix.net users), to share knowledge and resources.
Even the Nvidia developer site seems to be scarce when it comes to finding practical information and examples (lots of theory - but only a few practical demos/examples, and they are all very basic).

I made a personal demo using Optix.Net that you can download from my portfolio:


(called Optix.Net Real-Time Ray Tracing Teapot Demo). The demo shows off the following features:
Essentially the approximated ambient occlusion and indirect ambient lighting are used to create a cheaper version of the dynamic ambient lighting method described by Michel Bunnell is GPU Gems 2:
http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter14.html .
The main thing to remember with Optix is that the CUDA C kernels are essentially shaders (and are in my opinion much more flexible then the standard programmable graphics pipeline shaders - as you don't need to explicitly set up and pass data between the vertex, geometry and pixel shader stages).

On a final note, for fog simulation, someone wrote an academic paper on specifically simulating volumetric fog using Optix:


Hope you find this info useful.
  • Vlad
May 23, 2013 at 1:05 AM
Great Vlad lot of info to wade through exellent Oren-Nayar shader..im currently waiting on getting a GTX 660 with its 960 cores makes my 16 core directx10 laptop card look so slow :)