You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
514 lines
17 KiB
C
514 lines
17 KiB
C
3 weeks ago
|
/*=========================================================================
|
||
|
|
||
|
Program: Visualization Toolkit
|
||
|
Module: vtkOpenGLFramebufferObject.h
|
||
|
|
||
|
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.
|
||
|
|
||
|
=========================================================================*/
|
||
|
/**
|
||
|
* @class vtkOpenGLFramebufferObject
|
||
|
* @brief Internal class which encapsulates OpenGL FramebufferObject
|
||
|
*
|
||
|
* Before delving into this class it is best to have some background
|
||
|
* in some OpenGL terms. OpenGL has a notion of a currently
|
||
|
* bound Framebuffers for drawing and reading. It can be the default
|
||
|
* framebuffer such as created with a standard window/context or
|
||
|
* it can be a user created Framebuffer objects. When draw and read
|
||
|
* commands are invoked, they apply to the current draw and/or read
|
||
|
* frambuffers.
|
||
|
*
|
||
|
* A framebuffer consists of color buffers and an optional depth buffer.
|
||
|
* The FramebufferObject does not hold the memory for these buffers, it
|
||
|
* just keeps track of what buffers are attached to it. The buffers themselves
|
||
|
* hold the storage for the pixels/depths.
|
||
|
*
|
||
|
* In the context of this discussion a buffer can be either a
|
||
|
* vtkTextureObject (both 2D or a slice of a 3D texture) or
|
||
|
* a vtkRenderbuffer. In some cases a renderbuffer may be faster
|
||
|
* or more lightweight but you cannot pass a renderbuffer into
|
||
|
* a shader for sampling in a later pass like you can a texture.
|
||
|
*
|
||
|
* You attach these buffers to the Framebuffer using methods
|
||
|
* such as AddColorAttachment or AddDepthAttachment
|
||
|
* In normal usage a buffer is Attached to a FramebufferObject
|
||
|
* and then some or all of the attached buffers are activated for drawing
|
||
|
* or reading.
|
||
|
*
|
||
|
* When you have a framebuffer bound along with some buffers attached to it
|
||
|
* you can then activate specific buffers for drawing or reading. So you
|
||
|
* have draw and read framebuffer objects (bindings) and then for the currently
|
||
|
* bound FramebufferObjects you have active draw and read buffers.
|
||
|
*
|
||
|
* A single FramebufferObject can be bound to both Draw and Read. You
|
||
|
* cannot assign and activate a TextureObject for drawing on the FO and
|
||
|
* at the same time pass it in as a Texture to the shader program. That
|
||
|
* type of operation is very common and must be done in two steps.
|
||
|
* - Render to the FO with the Texture attached as an active buffer
|
||
|
* - deactivate the texture obj and then render with the texture obj
|
||
|
* as a texture passed into the shader
|
||
|
*
|
||
|
* Typical use cases:
|
||
|
* The simplest example
|
||
|
*\code{.cpp}
|
||
|
* fbo->SetContext(renWin);
|
||
|
* fbo->SaveCurrentBindingsAndBuffers();
|
||
|
* fbo->PopulateFramebuffer(width, height);
|
||
|
*
|
||
|
* ...
|
||
|
*
|
||
|
* fbo->RestorePreviousBindingsAndBuffers();
|
||
|
*\endcode
|
||
|
*
|
||
|
* If you wish to use a texture you created
|
||
|
*
|
||
|
*\code{.cpp}
|
||
|
* fbo->SetContext(renWin);
|
||
|
* fbo->SaveCurrentBindingsAndBuffers();
|
||
|
* fbo->Bind();
|
||
|
* fbo->AddColorAttachment(0, vtkTextureObj);
|
||
|
* fbo->AddDepthAttachment(); // auto create depth buffer
|
||
|
* fbo->ActivateBuffer(0);
|
||
|
*
|
||
|
* ...
|
||
|
*
|
||
|
* fbo->RestorePreviousBindingsAndBuffers();
|
||
|
*\endcode
|
||
|
*
|
||
|
* If you will be using a FO repeatedly then it is best to create it
|
||
|
* attach the buffers and then use as needed for example
|
||
|
*
|
||
|
* Typical use case:
|
||
|
*\code{.cpp}
|
||
|
* // setup the FBO once
|
||
|
* fbo->SetContext(renWin);
|
||
|
* fbo->SaveCurrentBindingsAndBuffers();
|
||
|
* fbo->AddColorAttachment(0, vtkTextureObj);
|
||
|
* fbo->AddDepthAttachment(); // auto create depth buffer
|
||
|
* fbo->RestorePreviousBindingsAndBuffers();
|
||
|
*
|
||
|
* // use it many times
|
||
|
* fbo->SaveCurrentBindingsAndBuffers();
|
||
|
* fbo->Bind();
|
||
|
* fbo->ActivateBuffer(0);
|
||
|
* ... // render here etc
|
||
|
* fbo->RestorePreviousBindingsAndBuffers();
|
||
|
*\endcode
|
||
|
*
|
||
|
* If you with to only bind the framebuffer for drawing or reading there
|
||
|
* are mode specific versions of some methods that only apply to the
|
||
|
* mode specified Draw/Read/Both. The mode argument uses OpenGL constants
|
||
|
* so this class provides convenience methods to return them named
|
||
|
* GetDrawMode() GetReadMode() and GetBothMode() so that your code
|
||
|
* does not need to be polluted with OpenGL headers/constants.
|
||
|
*
|
||
|
* This class replaces both vtkFrameBufferObject and vtkFrameBufferObject2
|
||
|
* and contins methods from both of them. Most methods from FO2 should
|
||
|
* work with this class. Just rename FBO2 to FBO and make sure to Save and
|
||
|
* Restore the bindings and buffers.
|
||
|
* If you have been using the old FO class, which had comments
|
||
|
* in the header saying not to use it. Then you are in for a bit more of
|
||
|
* a conversion but generally it should still be easy. Use the code
|
||
|
* samples above (or any of the classes in OpenGL2 that currently use FBOs)
|
||
|
* to guide you. They have all been converted to this class. Where previously
|
||
|
* a DepthBuffer was automatically created for you, you now need to do it
|
||
|
* explicitly using AddDepthAttachment().
|
||
|
*
|
||
|
* Note the capitalization of FramebufferObject
|
||
|
*
|
||
|
* @sa
|
||
|
* vtkTextureObject, vtkRenderbufferObject
|
||
|
*/
|
||
|
|
||
|
#ifndef vtkOpenGLFramebufferObject_h
|
||
|
#define vtkOpenGLFramebufferObject_h
|
||
|
|
||
|
/* Dec 2018 this class has been cleaned up such that
|
||
|
* AddColorAttachment and AddDepthAttachment no longer
|
||
|
* take a mode argument. The mode is determined by how
|
||
|
* the framebuffer is bound. If you are using these methods
|
||
|
* and need to support both the old and new signatures you
|
||
|
* can check for the following define in your code.
|
||
|
*/
|
||
|
#define VTK_UPDATED_FRAMEBUFFER
|
||
|
|
||
|
/**
|
||
|
* A variant of vtkErrorMacro that is used to verify framebuffer
|
||
|
* object completeness. It's provided so that reporting may include
|
||
|
* the file and line number of the offending code. In release mode
|
||
|
* the macro does nothing.
|
||
|
*/
|
||
|
#ifdef NDEBUG
|
||
|
#define vtkCheckFrameBufferStatusMacro(mode)
|
||
|
#define vtkStaticCheckFrameBufferStatusMacro(mode)
|
||
|
#else
|
||
|
#define vtkCheckFrameBufferStatusMacroImpl(macro, mode) \
|
||
|
{ \
|
||
|
const char* eStr; \
|
||
|
bool ok = vtkOpenGLFramebufferObject::GetFrameBufferStatus(mode, eStr); \
|
||
|
if (!ok) \
|
||
|
{ \
|
||
|
macro(<< "OpenGL ERROR. The FBO is incomplete : " << eStr); \
|
||
|
} \
|
||
|
}
|
||
|
#define vtkCheckFrameBufferStatusMacro(mode) vtkCheckFrameBufferStatusMacroImpl(vtkErrorMacro, mode)
|
||
|
#define vtkStaticCheckFrameBufferStatusMacro(mode) \
|
||
|
vtkCheckFrameBufferStatusMacroImpl(vtkGenericWarningMacro, mode)
|
||
|
#endif
|
||
|
|
||
|
#include "vtkFrameBufferObjectBase.h"
|
||
|
#include "vtkRenderingOpenGL2Module.h" // For export macro
|
||
|
#include <map> // for the maps
|
||
|
#include <vector> // for the lists of logical buffers.
|
||
|
|
||
|
class vtkFOInfo;
|
||
|
class vtkGenericOpenGLResourceFreeCallback;
|
||
|
class vtkOpenGLRenderWindow;
|
||
|
class vtkOpenGLVertexArrayObject;
|
||
|
class vtkPixelBufferObject;
|
||
|
class vtkRenderWindow;
|
||
|
class vtkRenderbuffer;
|
||
|
class vtkShaderProgram;
|
||
|
class vtkTextureObject;
|
||
|
class vtkWindow;
|
||
|
|
||
|
class VTKRENDERINGOPENGL2_EXPORT vtkOpenGLFramebufferObject : public vtkFrameBufferObjectBase
|
||
|
{
|
||
|
public:
|
||
|
static vtkOpenGLFramebufferObject* New();
|
||
|
vtkTypeMacro(vtkOpenGLFramebufferObject, vtkFrameBufferObjectBase);
|
||
|
void PrintSelf(ostream& os, vtkIndent indent) override;
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Get/Set the context. Context must be a vtkOpenGLRenderWindow.
|
||
|
* This does not increase the reference count of the
|
||
|
* context to avoid reference loops.
|
||
|
* SetContext() may raise an error is the OpenGL context does not support the
|
||
|
* required OpenGL extensions.
|
||
|
*/
|
||
|
void SetContext(vtkRenderWindow* context);
|
||
|
vtkOpenGLRenderWindow* GetContext();
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Make the draw frame buffer active.
|
||
|
*/
|
||
|
void Bind();
|
||
|
void Bind(unsigned int mode);
|
||
|
|
||
|
/**
|
||
|
* Unbind this buffer
|
||
|
*/
|
||
|
void UnBind();
|
||
|
void UnBind(unsigned int mode);
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Store/Restore the current framebuffer bindings and buffers.
|
||
|
*/
|
||
|
void SaveCurrentBindingsAndBuffers();
|
||
|
void SaveCurrentBindingsAndBuffers(unsigned int mode);
|
||
|
void RestorePreviousBindingsAndBuffers();
|
||
|
void RestorePreviousBindingsAndBuffers(unsigned int mode);
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* User must take care that width/height match the dimensions of
|
||
|
* the user defined texture attachments.
|
||
|
* This method makes the "active buffers" the buffers that will get drawn
|
||
|
* into by subsequent drawing calls.
|
||
|
* Note that this does not clear the render buffers i.e. no glClear() calls
|
||
|
* are made by either of these methods. It's up to the caller to clear the
|
||
|
* buffers if needed.
|
||
|
*/
|
||
|
bool Start(int width, int height);
|
||
|
bool StartNonOrtho(int width, int height);
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Set up ortho viewport with scissor, lighting, blend, and depth
|
||
|
* disabled. The method affects the current bound FBO.
|
||
|
*/
|
||
|
void InitializeViewport(int width, int height);
|
||
|
|
||
|
//@{
|
||
|
// activate deactivate draw/read buffers (color buffers)
|
||
|
void ActivateDrawBuffers(unsigned int n);
|
||
|
void ActivateDrawBuffers(unsigned int* ids, int n);
|
||
|
void ActivateDrawBuffer(unsigned int id);
|
||
|
void ActivateReadBuffer(unsigned int id);
|
||
|
void ActivateBuffer(unsigned int id)
|
||
|
{
|
||
|
this->ActivateDrawBuffer(id);
|
||
|
this->ActivateReadBuffer(id);
|
||
|
}
|
||
|
void DeactivateDrawBuffers();
|
||
|
void DeactivateReadBuffer();
|
||
|
//@}
|
||
|
|
||
|
vtkGetMacro(ActiveReadBuffer, unsigned int);
|
||
|
unsigned int GetActiveDrawBuffer(unsigned int id);
|
||
|
|
||
|
/**
|
||
|
* Renders a quad at the given location with pixel coordinates. This method
|
||
|
* is provided as a convenience, since we often render quads in a FBO.
|
||
|
* \pre positive_minX: minX>=0
|
||
|
* \pre increasing_x: minX<=maxX
|
||
|
* \pre valid_maxX: maxX<LastSize[0]
|
||
|
* \pre positive_minY: minY>=0
|
||
|
* \pre increasing_y: minY<=maxY
|
||
|
* \pre valid_maxY: maxY<LastSize[1]
|
||
|
*/
|
||
|
void RenderQuad(int minX, int maxX, int minY, int maxY, vtkShaderProgram* program,
|
||
|
vtkOpenGLVertexArrayObject* vao);
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Directly assign/remove a texture to color attachments.
|
||
|
*/
|
||
|
void AddColorAttachment(unsigned int attId, vtkTextureObject* tex, unsigned int zslice = 0,
|
||
|
unsigned int format = 0, unsigned int mipmapLevel = 0);
|
||
|
void AddColorAttachment(unsigned int attId, vtkRenderbuffer* tex);
|
||
|
void RemoveColorAttachment(unsigned int index);
|
||
|
void RemoveColorAttachments(unsigned int num);
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Return the number of color attachments for the given mode
|
||
|
*/
|
||
|
int GetNumberOfColorAttachments();
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Directly assign/remove a texture/renderbuffer to depth attachments.
|
||
|
*/
|
||
|
void AddDepthAttachment();
|
||
|
void AddDepthAttachment(vtkTextureObject* tex);
|
||
|
void AddDepthAttachment(vtkRenderbuffer* tex);
|
||
|
void RemoveDepthAttachment();
|
||
|
//@}
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Convenience method to populate a framebuffer with
|
||
|
* attachments created as well. Returns true if a
|
||
|
* complete valid Framebuffer was created
|
||
|
*/
|
||
|
bool PopulateFramebuffer(int width, int height);
|
||
|
bool PopulateFramebuffer(int width, int height, bool useTextures, int numberOfColorAttachments,
|
||
|
int colorDataType, bool wantDepthAttachment, int depthBitplanes, int multisamples,
|
||
|
bool wantStencilAttachment = false);
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Returns the maximum number of targets that can be rendered to at one time.
|
||
|
* This limits the active targets set by SetActiveTargets().
|
||
|
* The return value is valid only if GetContext is non-null.
|
||
|
*/
|
||
|
unsigned int GetMaximumNumberOfActiveTargets();
|
||
|
|
||
|
/**
|
||
|
* Returns the maximum number of render targets available. This limits the
|
||
|
* available attachment points for SetColorAttachment().
|
||
|
* The return value is valid only if GetContext is non-null.
|
||
|
*/
|
||
|
unsigned int GetMaximumNumberOfRenderTargets();
|
||
|
|
||
|
//@{
|
||
|
/**
|
||
|
* Dimensions in pixels of the framebuffer.
|
||
|
*/
|
||
|
int* GetLastSize() override
|
||
|
{
|
||
|
vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning LastSize pointer "
|
||
|
<< this->LastSize);
|
||
|
return this->LastSize;
|
||
|
}
|
||
|
void GetLastSize(int& _arg1, int& _arg2) override
|
||
|
{
|
||
|
_arg1 = this->LastSize[0];
|
||
|
_arg2 = this->LastSize[1];
|
||
|
vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning LastSize (" << _arg1
|
||
|
<< "," << _arg2 << ")");
|
||
|
}
|
||
|
void GetLastSize(int _arg[2]) override { this->GetLastSize(_arg[0], _arg[1]); }
|
||
|
//@}
|
||
|
|
||
|
/**
|
||
|
* Returns if the context supports the required extensions.
|
||
|
* Extension will be loaded when the context is set.
|
||
|
*/
|
||
|
static bool IsSupported(vtkOpenGLRenderWindow*) { return true; }
|
||
|
|
||
|
/**
|
||
|
* Validate the current FBO configuration (attachments, formats, etc)
|
||
|
* prints detected errors to vtkErrorMacro.
|
||
|
*/
|
||
|
int CheckFrameBufferStatus(unsigned int mode);
|
||
|
|
||
|
/**
|
||
|
* Deactivate and UnBind
|
||
|
*/
|
||
|
virtual void ReleaseGraphicsResources(vtkWindow* win);
|
||
|
|
||
|
/**
|
||
|
* Validate the current FBO configuration (attachments, formats, etc)
|
||
|
* return false if the FBO is incomplete. Assigns description a literal
|
||
|
* containing a description of the status.
|
||
|
* Low level api.
|
||
|
*/
|
||
|
static bool GetFrameBufferStatus(unsigned int mode, const char*& desc);
|
||
|
|
||
|
vtkGetMacro(FBOIndex, unsigned int);
|
||
|
|
||
|
/**
|
||
|
* Copy from the currently bound READ FBO to the currently
|
||
|
* bound DRAW FBO. The method is static so that one doesn't
|
||
|
* need to ccreate an instance when transferring between attachments
|
||
|
* in the default FBO.
|
||
|
*/
|
||
|
static int Blit(
|
||
|
const int srcExt[4], const int destExt[4], unsigned int bits, unsigned int mapping);
|
||
|
|
||
|
/**
|
||
|
* Download data from the read color attachment of the currently
|
||
|
* bound FBO into the returned PBO. The PBO must be free'd when
|
||
|
* you are finished with it. The number of components in the
|
||
|
* PBO is the same as in the name of the specific download function.
|
||
|
* When downloading a single color channel, the channel must be
|
||
|
* identified by index, 1->red, 2->green, 3-> blue.
|
||
|
*/
|
||
|
vtkPixelBufferObject* DownloadColor1(int extent[4], int vtkType, int channel);
|
||
|
|
||
|
vtkPixelBufferObject* DownloadColor3(int extent[4], int vtkType);
|
||
|
|
||
|
vtkPixelBufferObject* DownloadColor4(int extent[4], int vtkType);
|
||
|
|
||
|
/**
|
||
|
* Download data from the depth attachment of the currently
|
||
|
* bound FBO. The returned PBO must be Delete'd by the caller.
|
||
|
* The returned PBO has one component.
|
||
|
*/
|
||
|
vtkPixelBufferObject* DownloadDepth(int extent[4], int vtkType);
|
||
|
|
||
|
/**
|
||
|
* Download data from the read buffer of the current FBO. These
|
||
|
* are low level meothds. In the static variant a PBO must be
|
||
|
* passed in since we don't have access to a context. The static
|
||
|
* method is provided so that one may download from the default
|
||
|
* FBO.
|
||
|
*/
|
||
|
vtkPixelBufferObject* Download(
|
||
|
int extent[4], int vtkType, int nComps, int oglType, int oglFormat);
|
||
|
|
||
|
static void Download(
|
||
|
int extent[4], int vtkType, int nComps, int oglType, int oglFormat, vtkPixelBufferObject* pbo);
|
||
|
|
||
|
// returns the mode values for draw/read/both
|
||
|
// Can be used in cases where you do not
|
||
|
// want to have OpenGL code mixed in.
|
||
|
static unsigned int GetDrawMode();
|
||
|
static unsigned int GetReadMode();
|
||
|
static unsigned int GetBothMode();
|
||
|
|
||
|
/**
|
||
|
* Resize all FO attachments
|
||
|
*/
|
||
|
void Resize(int width, int height);
|
||
|
|
||
|
int GetMultiSamples();
|
||
|
|
||
|
protected:
|
||
|
/**
|
||
|
* Attach a specific buffer
|
||
|
*/
|
||
|
void AttachColorBuffer(unsigned int index);
|
||
|
void AttachDepthBuffer();
|
||
|
|
||
|
/**
|
||
|
* Load all necessary extensions.
|
||
|
*/
|
||
|
static bool LoadRequiredExtensions(vtkOpenGLRenderWindow*) { return true; }
|
||
|
|
||
|
vtkGenericOpenGLResourceFreeCallback* ResourceCallback;
|
||
|
|
||
|
// gen buffer (occurs when context is set)
|
||
|
void CreateFBO();
|
||
|
|
||
|
// delete buffer (occurs during destruction or context switch)
|
||
|
void DestroyFBO();
|
||
|
|
||
|
// detach and delete our reference(s)
|
||
|
void DestroyDepthBuffer(vtkWindow* win);
|
||
|
void DestroyColorBuffers(vtkWindow* win);
|
||
|
|
||
|
// glDrawBuffers
|
||
|
void ActivateBuffers();
|
||
|
|
||
|
// examine attachments to see if they have the same size
|
||
|
void UpdateSize();
|
||
|
|
||
|
/**
|
||
|
* Display all the attachments of the current framebuffer object.
|
||
|
*/
|
||
|
void DisplayFrameBufferAttachments();
|
||
|
|
||
|
/**
|
||
|
* Display a given attachment for the current framebuffer object.
|
||
|
*/
|
||
|
void DisplayFrameBufferAttachment(unsigned int uattachment);
|
||
|
|
||
|
/**
|
||
|
* Display the draw buffers.
|
||
|
*/
|
||
|
void DisplayDrawBuffers();
|
||
|
|
||
|
/**
|
||
|
* Display the read buffer.
|
||
|
*/
|
||
|
void DisplayReadBuffer();
|
||
|
|
||
|
/**
|
||
|
* Display any buffer (convert value into string).
|
||
|
*/
|
||
|
void DisplayBuffer(int value);
|
||
|
|
||
|
/**
|
||
|
* Given a vtk type get a compatible open gl type.
|
||
|
*/
|
||
|
int GetOpenGLType(int vtkType);
|
||
|
|
||
|
vtkOpenGLFramebufferObject();
|
||
|
~vtkOpenGLFramebufferObject() override;
|
||
|
|
||
|
vtkOpenGLRenderWindow* Context;
|
||
|
|
||
|
unsigned int FBOIndex;
|
||
|
|
||
|
bool DrawBindingSaved;
|
||
|
bool ReadBindingSaved;
|
||
|
bool DrawBufferSaved;
|
||
|
bool ReadBufferSaved;
|
||
|
|
||
|
int LastSize[2];
|
||
|
std::vector<unsigned int> ActiveBuffers;
|
||
|
unsigned int ActiveReadBuffer;
|
||
|
|
||
|
vtkFOInfo* DepthBuffer;
|
||
|
std::map<unsigned int, vtkFOInfo*> ColorBuffers;
|
||
|
|
||
|
private:
|
||
|
vtkOpenGLFramebufferObject(const vtkOpenGLFramebufferObject&) = delete;
|
||
|
void operator=(const vtkOpenGLFramebufferObject&) = delete;
|
||
|
};
|
||
|
|
||
|
#endif
|