Rendering Multiple Displays as a Single Display

Hi! I previously posted about splitting the scene into multiple viewports. However, that did not work what I wanted to achieve.

I have a 3x3 display setup, each with resolution 2560x1440 and total around 298.6 MPixels. I am using mpich library to manage the 4 GPUs. Setup like this:

I need to render the scene as a whole for all the 9 displays. Now, what I am getting each screen is returning the same scene 9 times. I know it could be even easier with multi-GPU feature/ tile-rendering, but for my case, the mpi library passes data in-between machines and displays.

Now, each of the displays is a viewport. My approach simply increases the optixGetLaunchDimensions() with user defined number same as the screen resolution, and start from optixGetLaunchIndex(). Also, increase the buffer size that matches the user-defined width and height. A sample code snipped below:

extern "C" __device__ void __Raygen__pinhole()
{
const Vec3ui idx = optixGetLaunchIndex();
//  const uint2 dim = make_uint2(optixGetLaunchDimensions());
const uint2 dim = make_uint2(10240, 5760); // 4x display for test purpose
const uint2 screen = make_uint2(10240, 5760); //4x
 
uint32_t seed = tea<4>(idx.y() * screen.x + idx.x(), frame);

Vec3f result(0.0f);
...
const Vec2f res(params.width, params.height);
const Vec2f coord(idx.x(), idx.y());
const Vec2f d = 2.0f * ((coord + jitter) / res) - 1.0f;
Vec3f ro, rd;
getCameraRay(raygen->camera, d.x(), d.y(), ro, rd);
...

int depth = 0;
for (;; ) {

if (depth >= params.max_depth)
    break;

...
}
} while (--i);
// bm
const uint32_t image_index = idx.y() * dim.x + idx.x();
...

params.result_buffer[image_index] = Vec4u(color, 255);

} 

My Quesion is, can I increase the optixGetLaunchDimensions()? Any suggestion on this?

Hi @_Bi2022,

My Quesion is, can I increase the optixGetLaunchDimensions()? Any suggestion on this?

I’m not sure what you’re imagining exactly, but you do need your launch dimensions to know how to map from the launch index to a pixel in your viewport, and where to write to the frame buffer. What you’re missing is the extra step to map your viewport to the virtual screen. Your code sample lacks any way to identify which viewport you’re rendering. You need to write the tile rendering feature.

The d parameter in this code is the screen space parameter of the pixel you want to render relative to the virtual screen (the final large display after stitching together your 9 or 16 viewport renders).

d will range from -1 to 1 in both x and y over the whole virtual screen, but it should of course span a smaller range for each of your viewports. For example viewport (0,0) in a 4x virtual screen will have d ranging from -1 to -0.5 in each of x and y. The way you have it setup here, your d parameter is spanning -1 to 1 regardless of viewport. Your mapping might look something like this: (pseudocode, hastily typed, check for errors, the vars up to virtual_screen_coord & the corresponding assignment expressions are 2d).

pixel_coord           = optixGetLaunchIndex() // current pixel-space coord in current viewport
viewport_dim          = (params.width, params.height) // size of viewport in pixels
num_tiles             = (params.num_viewport_tiles.x, params.num_viewport_tiles.y)
virtual_dim           = viewport_dim * num_tiles // size of virtual screen in pixels
viewport_tile         = (params.viewport_tile.x, params.viewport_tile.y) // which tile we're currently rendering
viewport_screen_coord = (pixel_coord + jitter) / viewport_dim // [-1..1] over viewport
virtual_screen_coord  = viewport_screen_coord / num_tiles + (viewport_tile * viewport_dim) / virtual_dim // [-1..1] over virtual screen
...
getCameraRay(raygen->camera, virtual_screen_coord.x, virtual_screen_coord.y, ro, rd); // use virtual screen coords for camera
...
const uint32_t image_index = pixel_coord.y * dim.x + pixel_coord.x; // use viewport pixel coords for local framebuffer indexing
params.result_buffer[image_index] = Vec4u(color, 255);

This assumes a viewport frame buffer, so after this, up to you to copy / transmit / stitch / display the local viewport framebuffer into something bigger. You may need to repeat some of the above mapping. If you instead wanted to write into a single frame buffer that is somehow shared and accessible to all GPUs, then you’ll need to use virtual pixel coords instead of viewport pixel coords to index that frame buffer. Each GPU would write into it’s own portion of a shared frame buffer. No reason to keep your viewport/pixel/virtual screen/camera mapping short or cryptic like the OptiX samples. It’s worth being explicit about which space each variable belongs to when naming them, and writing the code so that it’s easy and clear how to transform between these different coordinate frames.


David.

1 Like

Hi @dhart!

Thanks a lot for all the details. Your suggestions always give me deeper insights. Now the problem has been solved, and see OptiX 7.5 is running on 3x3 displays with 4 GPUs.

1 Like