Switching offscreen rendering from off to on crashes on Windows
Starting VTK 7.0, a bug occurred when switching a render window to offscreen rendering and then back to on. This is caused by the window context being incorrectly destroyed.
Below is a small piece of code used to reproduce the bug. This creates a window with a sphere, clicking inside the window leads to a crash.
#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
int main()
{
vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
sphere->SetRadius( 10.0 );
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection( sphere->GetOutputPort() );
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper( mapper );
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor( actor );
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer( renderer );
vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow( renderWindow );
interactor->Initialize();
renderWindow->OffScreenRenderingOn();
renderWindow->OffScreenRenderingOff();
interactor->Start();
return 0;
}
This code worked perfectly in VTK 6.x. The bug is due to a change that occurred between 6.3 and 7.0 in vtkWin32OpenGLRenderWindow::DestroyWindow():
VTK 6.3:
void vtkWin32OpenGLRenderWindow::DestroyWindow()
{
if(this->WindowIdReferenceCount > 0)
{
--this->WindowIdReferenceCount;
if(this->WindowIdReferenceCount == 0)
{
this->Clean();
if (this->WindowId)
{
ReleaseDC(this->WindowId, this->DeviceContext);
// can't set WindowId=NULL, needed for DestroyWindow
this->DeviceContext = NULL;
// clear the extra data before calling destroy
vtkSetWindowLong(this->WindowId,sizeof(vtkLONG),(vtkLONG)0);
if(this->OwnWindow)
{
::DestroyWindow(this->WindowId); // windows api
this->WindowId=0;
}
}
}
}
}
VTK 7.x:
void vtkWin32OpenGLRenderWindow::DestroyWindow()
{
this->Clean();
if (this->WindowIdReferenceCount > 0)
{
--this->WindowIdReferenceCount;
if (this->WindowIdReferenceCount == 0)
{
if (this->WindowId)
{
ReleaseDC(this->WindowId, this->DeviceContext);
// can't set WindowId=NULL, needed for DestroyWindow
this->DeviceContext = NULL;
// clear the extra data before calling destroy
vtkSetWindowLong(this->WindowId, sizeof(vtkLONG), (vtkLONG)0);
if (this->OwnWindow)
{
::DestroyWindow(this->WindowId); // windows api
this->WindowId = 0;
}
}
}
}
}
VTK 6.3 code was right there, because in VTK 7.x, call to Clean
is done before checking that the window reference count is equal to 0, which leads to the OpenGL context being destroyed whil a window is still alive.