Be careful what you grab!

April 28, 2017

Grabbing a rendered image is a fairly common thing to do in VTK applications. Many do that as follows:

vtkRenderWindow *renWin = ...
..
renWin->Render()

vtkNew<vtkWindowToImage> w2i;
..
// Let's grab from back buffer as that overcomes
// issues with overlapping windows or other UI
// components obfuscating the captured image on
// certain windowing systems/platforms.
w2i->ReadFrontBufferOff();
w2i->Update();

This seemingly innocuous code has a serious flaw. You’re actually grabbing undefined contents! Let’s look at what’s going on a little more closely.

vtkRenderWindow, by default, is setup to use double-buffering. When using double-buffering, it is also setup to swap back and front buffers at the end of each render. The kicker is that despite its name (and common perception), this swap is not defined as a true swap. It merely implies back buffer contents being copied to the front buffer. What is left in the back buffer at the end of the swap is not defined. As a result, when vtkWindowToImage filter goes to grab the back-buffer after the render, it invariable is reading undefined contents — although one may be getting lucky in most cases.

The correct way to address this would be as follows:

vtkRenderWindow *renWin = ...
..
renWin->Render()

vtkNew<vtkWindowToImage> w2i;
..

int oldSB = renWin->GetSwapBuffers();
// Tell render window to not swap buffers at end of render.
renWin->SwapBuffersOff();

w2i->ReadFrontBufferOff();
w2i->Update();

// restore swapping state
renWin->SetSwapBuffers(oldSB);

Another thing to note is that if you are telling vtkWindowToImage filter to not re-render i.e. vtkWindowToImage::ShouldRerenderOff(), then make sure that the SwapBuffers is turned off before the latest Render call on the render-window.

Tags:

Leave a Reply