Commit a0cbcf75 authored by Ken Martin's avatar Ken Martin Committed by Kitware Robot

Merge topic 'new_opengl_resource_management'

d0e64da3 work on better resource management for OpenGL
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Reviewed-by: Berk Geveci's avatarBerk Geveci <berk.geveci@kitware.com>
Merge-request: !1953
parents 3d1d1889 d0e64da3
......@@ -41,6 +41,7 @@ PURPOSE. See the above copyright notice for more information.
#define vtkCocoaRenderWindow_h
#include "vtkRenderingOpenGL2Module.h" // For export macro
#include <stack> // for ivar
#include "vtkOpenGLRenderWindow.h"
class VTKRENDERINGOPENGL2_EXPORT vtkCocoaRenderWindow : public vtkOpenGLRenderWindow
......@@ -292,10 +293,21 @@ public:
void SetPixelFormat(void *pixelFormat);
void *GetPixelFormat();
// Description
// Ability to push and pop this window's context
// as the current context. The idea being to
// if needed make this window's context current
// and when done releasing resources restore
// the prior context
virtual void PushContext();
virtual void PopContext();
protected:
vtkCocoaRenderWindow();
~vtkCocoaRenderWindow();
std::stack<void *> ContextStack;
void CreateGLContext();
void CreateAWindow();
......
......@@ -358,6 +358,29 @@ void vtkCocoaRenderWindow::MakeCurrent()
}
}
void vtkCocoaRenderWindow::PushContext()
{
NSOpenGLContext *current = [NSOpenGLContext currentContext];
NSOpenGLContext *mine = static_cast<NSOpenGLContext *>(this->GetContextId());
this->ContextStack.push(current);
if (current != mine)
{
this->MakeCurrent();
}
}
void vtkCocoaRenderWindow::PopContext()
{
NSOpenGLContext *current = [NSOpenGLContext currentContext];
NSOpenGLContext *target =
static_cast<NSOpenGLContext *>(this->ContextStack.top());
this->ContextStack.pop();
if (target != current)
{
[target makeCurrentContext];
}
}
// ----------------------------------------------------------------------------
// Description:
// Tells if this window is the current OpenGL context for the calling thread.
......
......@@ -23,6 +23,7 @@
#include "vtkPixelBufferObject.h"
#include "vtkOpenGLBufferObject.h"
#include "vtkOpenGLError.h"
#include "vtkOpenGLResourceFreeCallback.h"
#include <cassert>
#include <vector>
......@@ -44,11 +45,19 @@ vtkFrameBufferObject::vtkFrameBufferObject()
this->LastSize[0] = this->LastSize[1] = -1;
this->SetActiveBuffer(0);
this->NumberOfRenderTargets = 1;
this->ResourceCallback = new vtkOpenGLResourceFreeCallback<vtkFrameBufferObject>(this,
&vtkFrameBufferObject::ReleaseGraphicsResources);
}
//----------------------------------------------------------------------------
vtkFrameBufferObject::~vtkFrameBufferObject()
{
if (this->ResourceCallback)
{
this->ResourceCallback->Release();
delete this->ResourceCallback;
this->ResourceCallback = NULL;
}
this->DestroyFBO();
this->DestroyDepthBuffer();
this->DestroyColorBuffers();
......@@ -119,20 +128,33 @@ bool vtkFrameBufferObject::LoadRequiredExtensions(vtkOpenGLRenderWindow *)
return fbo && fboBlit;
}
//----------------------------------------------------------------------------
void vtkFrameBufferObject::SetContext(vtkOpenGLRenderWindow *renWin)
void vtkFrameBufferObject::ReleaseGraphicsResources(vtkWindow *)
{
// avoid pointless re-assignment
if (this->Context==renWin)
if (!this->ResourceCallback->IsReleasing())
{
this->ResourceCallback->Release();
return;
}
// free previous resources
this->DestroyDepthBuffer();
this->DestroyColorBuffers();
this->DestroyFBO();
this->Context = NULL;
this->Modified();
}
//----------------------------------------------------------------------------
void vtkFrameBufferObject::SetContext(vtkOpenGLRenderWindow *renWin)
{
// avoid pointless re-assignment
if (this->Context==renWin)
{
return;
}
this->ResourceCallback->RegisterGraphicsResources(renWin);
// all done if assigned null
if (!renWin)
{
......
......@@ -38,6 +38,8 @@ class vtkPixelBufferObject;
class vtkOpenGLRenderWindow;
class vtkShaderProgram;
class vtkOpenGLVertexArrayObject;
class vtkGenericOpenGLResourceFreeCallback;
class vtkWindow;
class VTKRENDERINGOPENGL2_EXPORT vtkFrameBufferObject : public vtkFrameBufferObjectBase
{
......@@ -167,12 +169,18 @@ public:
// prints detected errors to vtkErrorMacro.
int CheckFrameBufferStatus(unsigned int mode);
// Description:
// Deactivate and UnBind
virtual void ReleaseGraphicsResources(vtkWindow *win);
protected:
// Description:
// Load all necessary extensions.
static
bool LoadRequiredExtensions(vtkOpenGLRenderWindow *renWin);
vtkGenericOpenGLResourceFreeCallback *ResourceCallback;
// gen buffer (occurs when context is set)
void CreateFBO();
......
......@@ -37,6 +37,7 @@
#include "vtkOpenGLRenderPass.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLRenderer.h"
#include "vtkOpenGLResourceFreeCallback.h"
#include "vtkOpenGLShaderCache.h"
#include "vtkOpenGLTexture.h"
#include "vtkOpenGLVertexArrayObject.h"
......@@ -112,11 +113,19 @@ vtkOpenGLPolyDataMapper::vtkOpenGLPolyDataMapper()
this->LastLightComplexity[&this->TriStripsEdges] = -1;
this->TimerQuery = 0;
this->ResourceCallback = new vtkOpenGLResourceFreeCallback<vtkOpenGLPolyDataMapper>(this,
&vtkOpenGLPolyDataMapper::ReleaseGraphicsResources);
}
//-----------------------------------------------------------------------------
vtkOpenGLPolyDataMapper::~vtkOpenGLPolyDataMapper()
{
if (this->ResourceCallback)
{
this->ResourceCallback->Release();
delete this->ResourceCallback;
this->ResourceCallback = NULL;
}
if (this->InternalColorTexture)
{ // Resources released previously.
this->InternalColorTexture->Delete();
......@@ -167,13 +176,10 @@ vtkOpenGLPolyDataMapper::~vtkOpenGLPolyDataMapper()
//-----------------------------------------------------------------------------
void vtkOpenGLPolyDataMapper::ReleaseGraphicsResources(vtkWindow* win)
{
vtkOpenGLRenderWindow *rwin =
vtkOpenGLRenderWindow::SafeDownCast(win);
if (rwin)
if (!this->ResourceCallback->IsReleasing())
{
// Ensure that the context is current before releasing any
// graphics resources tied to it.
rwin->MakeCurrent();
this->ResourceCallback->Release();
return;
}
this->VBO->ReleaseGraphicsResources();
......@@ -2528,6 +2534,9 @@ void vtkOpenGLPolyDataMapper::RenderPiece(vtkRenderer* ren, vtkActor *actor)
return;
}
this->ResourceCallback->RegisterGraphicsResources(
static_cast<vtkOpenGLRenderWindow *>(ren->GetRenderWindow()));
this->CurrentInput = this->GetInput();
if (this->CurrentInput == NULL)
......
......@@ -36,6 +36,7 @@ class vtkOpenGLBufferObject;
class vtkOpenGLVertexBufferObject;
class vtkTextureObject;
class vtkTransform;
class vtkGenericOpenGLResourceFreeCallback;
class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLPolyDataMapper : public vtkPolyDataMapper
{
......@@ -185,6 +186,8 @@ protected:
vtkOpenGLPolyDataMapper();
~vtkOpenGLPolyDataMapper();
vtkGenericOpenGLResourceFreeCallback *ResourceCallback;
// the following is all extra stuff to work around the
// fact that gl_PrimitiveID does not work correctly on
// Apple devices with AMD graphics hardware. See apple
......
......@@ -39,6 +39,7 @@
#include "vtkTextureObject.h"
#include "vtkTextureUnitManager.h"
#include "vtkUnsignedCharArray.h"
#include "vtkOpenGLResourceFreeCallback.h"
#include "vtkTextureObjectVS.h" // a pass through shader
......@@ -166,6 +167,16 @@ vtkOpenGLRenderWindow::~vtkOpenGLRenderWindow()
// ----------------------------------------------------------------------------
void vtkOpenGLRenderWindow::ReleaseGraphicsResources(vtkRenderWindow *renWin)
{
// release the registered resources
std::set<vtkGenericOpenGLResourceFreeCallback *>::iterator it
= this->Resources.begin();
while (it != this->Resources.end() )
{
(*it)->Release();
it = this->Resources.begin();
}
vtkCollectionSimpleIterator rsit;
this->Renderers->InitTraversal(rsit);
vtkRenderer *aren;
......
......@@ -26,6 +26,7 @@
#include "vtkRenderWindow.h"
#include <string> // for ivar
#include <map> // for ivar
#include <set> // for ivar
#include "vtkType.h" // for ivar
class vtkIdList;
......@@ -37,6 +38,7 @@ class vtkStdString;
class vtkTexture;
class vtkTextureObject;
class vtkTextureUnitManager;
class vtkGenericOpenGLResourceFreeCallback;
class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLRenderWindow : public vtkRenderWindow
{
......@@ -292,6 +294,37 @@ public:
// in-between. This is what WindowRemap does.
virtual void Initialize(void) {};
std::set<vtkGenericOpenGLResourceFreeCallback *> Resources;
void RegisterGraphicsResources(vtkGenericOpenGLResourceFreeCallback *cb) {
std::set<vtkGenericOpenGLResourceFreeCallback *>::iterator it
= this->Resources.find(cb);
if (it == this->Resources.end())
{
this->Resources.insert(cb);
}
}
void UnregisterGraphicsResources(vtkGenericOpenGLResourceFreeCallback *cb) {
std::set<vtkGenericOpenGLResourceFreeCallback *>::iterator it
= this->Resources.find(cb);
if (it != this->Resources.end())
{
this->Resources.erase(it);
}
}
// Description:
// Ability to push and pop this window's context
// as the current context. The idea being to
// if needed make this window's context current
// and when done releasing resources restore
// the prior context. The default implementation
// here is only meant as a backup for subclasses
// that lack a proper implementation.
virtual void PushContext() { this->MakeCurrent(); }
virtual void PopContext() {}
protected:
vtkOpenGLRenderWindow();
~vtkOpenGLRenderWindow();
......
/*=========================================================================
Program: Visualization Toolkit
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#ifndef vtkOpenGLResourceFreeCallback_h
#define vtkOpenGLResourceFreeCallback_h
// Description:
// Provide a mechanism for making sure graphics resources are
// freed properly.
class vtkOpenGLRenderWindow;
class vtkWindow;
class vtkGenericOpenGLResourceFreeCallback
{
public:
vtkGenericOpenGLResourceFreeCallback() {
this->VTKWindow = NULL; this->Releasing = false; }
virtual ~vtkGenericOpenGLResourceFreeCallback() { }
// Called when the event is invoked
virtual void Release() = 0;
virtual void RegisterGraphicsResources(vtkOpenGLRenderWindow *rw) = 0;
bool IsReleasing() {
return this->Releasing; }
protected:
vtkOpenGLRenderWindow *VTKWindow;
bool Releasing;
};
// Description:
// Templated member callback.
template <class T>
class vtkOpenGLResourceFreeCallback : public vtkGenericOpenGLResourceFreeCallback
{
public:
vtkOpenGLResourceFreeCallback(T* handler, void (T::*method)(vtkWindow *))
{
this->Handler = handler;
this->Method = method;
}
virtual ~vtkOpenGLResourceFreeCallback() { }
virtual void RegisterGraphicsResources(vtkOpenGLRenderWindow *rw) {
if (this->VTKWindow == rw)
{
return;
}
if (this->VTKWindow)
{
this->Release();
}
this->VTKWindow = rw;
this->VTKWindow->RegisterGraphicsResources(this);
}
// Called when the event is invoked
virtual void Release()
{
if (this->VTKWindow && this->Handler && !this->Releasing)
{
this->Releasing = true;
this->VTKWindow->PushContext();
(this->Handler->*this->Method)(this->VTKWindow);
this->VTKWindow->UnregisterGraphicsResources(this);
this->VTKWindow->PopContext();
this->VTKWindow = NULL;
this->Releasing = false;
}
}
protected:
T* Handler;
void (T::*Method)(vtkWindow *);
};
#endif
// VTK-HeaderTest-Exclude: vtkOpenGLResourceFreeCallback.h
\ No newline at end of file
......@@ -28,6 +28,7 @@
#include "vtkOpenGLError.h"
#include "vtkOpenGLRenderUtilities.h"
#include "vtkOpenGLRenderWindow.h"
#include "vtkOpenGLResourceFreeCallback.h"
#include "vtkOpenGLShaderCache.h"
#include "vtkOpenGLTexture.h"
#include "vtkOpenGLVertexArrayObject.h"
......@@ -255,13 +256,21 @@ vtkTextureObject::vtkTextureObject()
this->BorderColor[3] = 0.0f;
this->BufferObject = 0;
this->ResourceCallback = new vtkOpenGLResourceFreeCallback<vtkTextureObject>(this,
&vtkTextureObject::ReleaseGraphicsResources);
this->ResetFormatAndType();
}
//----------------------------------------------------------------------------
vtkTextureObject::~vtkTextureObject()
{
this->DestroyTexture();
if (this->ResourceCallback)
{
this->ResourceCallback->Release();
delete this->ResourceCallback;
this->ResourceCallback = NULL;
}
if (this->ShaderProgram)
{
delete this->ShaderProgram;
......@@ -362,8 +371,9 @@ void vtkTextureObject::SetContext(vtkOpenGLRenderWindow* renWin)
{
return;
}
// free previous resources
this->DestroyTexture();
this->ResourceCallback->RegisterGraphicsResources(renWin);
this->Context = NULL;
this->Modified();
// all done if assigned null
......@@ -501,30 +511,32 @@ void vtkTextureObject::Deactivate()
//---------------------------------------------------------------------------
void vtkTextureObject::ReleaseGraphicsResources(vtkWindow *win)
{
if (!this->ResourceCallback->IsReleasing())
{
this->ResourceCallback->Release();
return;
}
vtkOpenGLRenderWindow *rwin =
vtkOpenGLRenderWindow::SafeDownCast(win);
if (rwin)
// Ensure that the context is current before releasing any graphics
// resources tied to it.
if (this->Handle)
{
// Ensure that the context is current before releasing any graphics
// resources tied to it.
rwin->MakeCurrent();
if (this->Handle)
{
rwin->ActivateTexture(this);
this->UnBind();
rwin->DeactivateTexture(this);
GLuint tex = this->Handle;
glDeleteTextures(1, &tex);
this->Handle = 0;
this->NumberOfDimensions = 0;
this->Target =0;
this->InternalFormat = 0;
this->Format = 0;
this->Type = 0;
this->Components = 0;
this->Width = this->Height = this->Depth = 0;
}
rwin->ActivateTexture(this);
this->UnBind();
rwin->DeactivateTexture(this);
GLuint tex = this->Handle;
glDeleteTextures(1, &tex);
this->Handle = 0;
this->NumberOfDimensions = 0;
this->Target =0;
this->InternalFormat = 0;
this->Format = 0;
this->Type = 0;
this->Components = 0;
this->Width = this->Height = this->Depth = 0;
}
if (this->ShaderProgram)
{
......
......@@ -30,6 +30,7 @@ class vtkOpenGLRenderWindow;
class vtkOpenGLVertexArrayObject;
class vtkShaderProgram;
class vtkWindow;
class vtkGenericOpenGLResourceFreeCallback;
#if GL_ES_VERSION_2_0 != 1 || GL_ES_VERSION_3_0 == 1
class vtkPixelBufferObject;
......@@ -624,6 +625,8 @@ protected:
vtkTextureObject();
~vtkTextureObject();
vtkGenericOpenGLResourceFreeCallback *ResourceCallback;
// Description:
// Load all necessary extensions.
bool LoadRequiredExtensions(vtkOpenGLRenderWindow *renWin);
......
......@@ -238,6 +238,30 @@ void vtkWin32OpenGLRenderWindow::MakeCurrent()
}
}
void vtkWin32OpenGLRenderWindow::PushContext()
{
HGLRC current = wglGetCurrentContext();
this->ContextStack.push(current);
this->DCStack.push(wglGetCurrentDC());
if (current != this->ContextId)
{
this->MakeCurrent();
}
}
void vtkWin32OpenGLRenderWindow::PopContext()
{
HGLRC current = wglGetCurrentContext();
HGLRC target = this->ContextStack.top();
HDC dc = this->DCStack.top();
this->ContextStack.pop();
this->DCStack.pop();
if (target != current)
{
wglMakeCurrent(dc, target);
}
}
// ----------------------------------------------------------------------------
// Description:
// Tells if this window is the current OpenGL context for the calling thread.
......
......@@ -22,6 +22,7 @@ PURPOSE. See the above copyright notice for more information.
#define vtkWin32OpenGLRenderWindow_h
#include "vtkRenderingOpenGL2Module.h" // For export macro
#include <stack> // for ivar
#include "vtkOpenGLRenderWindow.h"
#include "vtkWindows.h" // For windows API
......@@ -210,6 +211,15 @@ public:
// on and off screen rendering.
virtual void SetOffScreenRendering(int offscreen);
// Description
// Ability to push and pop this window's context
// as the current context. The idea being to
// if needed make this window's context current
// and when done releasing resources restore
// the prior context
virtual void PushContext();
virtual void PopContext();
protected:
vtkWin32OpenGLRenderWindow();
~vtkWin32OpenGLRenderWindow();
......@@ -226,6 +236,9 @@ protected:
int OwnWindow;
int ScreenSize[2];
std::stack<HGLRC> ContextStack;
std::stack<HDC> DCStack;
int CreatingOffScreenWindow; // to avoid recursion (and memory leaks...)
// message handler
......
......@@ -1365,8 +1365,8 @@ bool vtkXOpenGLRenderWindow::IsCurrent()
result=this->Internal->OffScreenContextId==OSMesaGetCurrentContext();
}
else
{
#endif
{
if(this->OffScreenRendering && this->Internal->PixmapContextId)
{
result=this->Internal->PixmapContextId==glXGetCurrentContext();
......@@ -1378,12 +1378,45 @@ bool vtkXOpenGLRenderWindow::IsCurrent()
result=this->Internal->ContextId==glXGetCurrentContext();
}
}
}
return result;
}
void vtkXOpenGLRenderWindow::PushContext()
{
#ifdef VTK_USE_OSMESA
this->MakeCurrent();
return;
#else
GLXContext current = glXGetCurrentContext();
this->ContextStack.push(current);
this->DisplayStack.push(glXGetCurrentDisplay());
this->DrawableStack.push(glXGetCurrentDrawable());
if(this->Internal->ContextId != current)
{
this->MakeCurrent();
}
#endif
return result;
}
void vtkXOpenGLRenderWindow::PopContext()
{
#ifndef VTK_USE_OSMESA
GLXContext current = glXGetCurrentContext();
GLXContext target = static_cast<GLXContext>(this->ContextStack.top());
this->ContextStack.pop();
if (target != current)
{
glXMakeCurrent(this->DisplayStack.top(),
this->DrawableStack.top(),
target);
}
this->DisplayStack.pop();
this->DrawableStack.pop();
#endif
}
void vtkXOpenGLRenderWindow::SetForceMakeCurrent()
{
this->ForceMakeCurrent = 1;
......
......@@ -23,6 +23,7 @@
#define vtkXOpenGLRenderWindow_h
#include "vtkRenderingOpenGL2Module.h" // For export macro
#include <stack> // for ivar
#include "vtkOpenGLRenderWindow.h"
#include <X11/Xlib.h> // Needed for X types used in the public interface
#include <X11/Xutil.h> // Needed for X types used in the public interface
......@@ -229,6 +230,15 @@ public:
// Render without displaying the window.
void SetOffScreenRendering(int i);
// Description
// Ability to push and pop this window's context
// as the current context. The idea being to
// if needed make this window's context current
// and when done releasing resources restore
// the prior context
virtual void PushContext();
virtual void PopContext();
protected:
vtkXOpenGLRenderWindow();
~vtkXOpenGLRenderWindow();
......@@ -248,6 +258,10 @@ protected:
int UsingHardware;
char *Capabilities;
std::stack<Display *> DisplayStack;
std::stack<Drawable> DrawableStack;
std::stack<void *> ContextStack;
// we must keep track of the cursors we are using
Cursor XCCrosshair;
Cursor XCArrow;
......
......@@ -48,6 +48,7 @@
#include <vtkOpenGLError.h>
#include <vtkOpenGLCamera.h>
#include <vtkOpenGLRenderWindow.h>
#include "vtkOpenGLResourceFreeCallback.h"
#include <vtkOpenGLShaderCache.h>
#include <vtkPerlinNoise.h>
#include <vtkPixelBufferObject.h>
......@@ -2557,11 +2558,20 @@ vtkOpenGLGPUVolumeRayCastMapper::vtkOpenGLGPUVolumeRayCastMapper() :
this->Impl = new vtkInternal(this);
this->ReductionFactor = 1.0;
this->CurrentPass = RenderPass;
this->ResourceCallback = new vtkOpenGLResourceFreeCallback<vtkOpenGLGPUVolumeRayCastMapper>(this,
&vtkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources);
}
//----------------------------------------------------------------------------
vtkOpenGLGPUVolumeRayCastMapper::~vtkOpenGLGPUVolumeRayCastMapper()
{
if (this->ResourceCallback)
{
this->ResourceCallback->Release();
delete this->ResourceCallback;
this->ResourceCallback = NULL;
}
delete this->Impl;
this->Impl = 0;
}
......@@ -2605,6 +2615,12 @@ void vtkOpenGLGPUVolumeRayCastMapper::GetColorImage(vtkImageData* output)
void vtkOpenGLGPUVolumeRayCastMapper::ReleaseGraphicsResources(
vtkWindow *window)
{
if (!this->ResourceCallback->IsReleasing())
{
this->ResourceCallback->Release();
return;
}
this->Impl->DeleteBufferObjects();
if (this->Impl->VolumeTextureObject)
......@@ -3137,6 +3153,9 @@ void vtkOpenGLGPUVolumeRayCastMapper::GPURender(vtkRenderer* ren,
{
vtkOpenGLClearErrorMacro();
this->ResourceCallback->RegisterGraphicsResources(
static_cast<vtkOpenGLRenderWindow *>(ren->GetRenderWindow(