summaryrefslogtreecommitdiff
path: root/togl/linuxwin/cglmfbo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'togl/linuxwin/cglmfbo.cpp')
-rw-r--r--togl/linuxwin/cglmfbo.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/togl/linuxwin/cglmfbo.cpp b/togl/linuxwin/cglmfbo.cpp
new file mode 100644
index 0000000..ec2418d
--- /dev/null
+++ b/togl/linuxwin/cglmfbo.cpp
@@ -0,0 +1,355 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// TOGL CODE LICENSE
+//
+// Copyright 2011-2014 Valve Corporation
+// All Rights Reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// cglmfbo.cpp
+//
+//===============================================================================
+
+#include "togl/rendermechanism.h"
+
+// memdbgon -must- be the last include file in a .cpp file.
+#include "tier0/memdbgon.h"
+
+CGLMFBO::CGLMFBO( GLMContext *ctx )
+{
+ m_ctx = ctx;
+ m_ctx->CheckCurrent();
+
+ gGL->glGenFramebuffersEXT( 1, &m_name );
+
+ memset( m_attach, 0, sizeof( m_attach ) );
+}
+
+
+CGLMFBO::~CGLMFBO( )
+{
+ m_ctx->CheckCurrent();
+
+ // detach all known attached textures first... necessary ?
+ for( int index = 0; index < kAttCount; index++)
+ {
+ if (m_attach[ index ].m_tex)
+ {
+ TexDetach( (EGLMFBOAttachment)index );
+ }
+ }
+
+ gGL->glDeleteFramebuffersEXT( 1, &m_name );
+
+ m_name = 0;
+ m_ctx = NULL;
+}
+
+// the tex attach path should also select a specific slice of the texture...
+// and we need a way to make renderbuffers..
+
+static GLenum EncodeAttachmentFBO( EGLMFBOAttachment index )
+{
+ if (index < kAttDepth)
+ {
+ return GL_COLOR_ATTACHMENT0_EXT + (int) index;
+ }
+ else
+ {
+ switch( index )
+ {
+ case kAttDepth:
+ return GL_DEPTH_ATTACHMENT_EXT;
+ break;
+
+ case kAttStencil:
+ return GL_STENCIL_ATTACHMENT_EXT;
+ break;
+
+ case kAttDepthStencil:
+ return GL_DEPTH_STENCIL_ATTACHMENT_EXT;
+ break;
+
+ default:
+ GLMStop(); // bad news
+ break;
+ }
+ }
+
+ GLMStop(); // bad news
+ // shouldn't get here
+ return GL_COLOR_ATTACHMENT0_EXT;
+}
+
+void CGLMFBO::TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
+{
+ // force our parent context to be current
+ m_ctx->MakeCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this, fboBindPoint );
+
+ // it's either a plain 2D, a 2D face of a cube map, or a slice of a 3D.
+ CGLMTex *tex = params->m_tex;
+
+ // always detach what is currently there, if anything
+ this->TexDetach( attachIndex, fboBindPoint );
+
+ if (!tex)
+ {
+ // andif they pass NULL to us, then we are done.
+ return;
+ }
+
+ GLMTexLayout *layout = tex->m_layout;
+
+ GLenum target = tex->m_layout->m_key.m_texGLTarget;
+
+ GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
+
+ switch( target )
+ {
+ case GL_TEXTURE_2D:
+ {
+ // we will attach the underlying RBO on a multisampled tex, iff the tex has one, **and** we're not being asked to attach it to the read buffer.
+ // if we get a req to attach an MSAA tex to the read buffer, chances are it's BlitTex calling, andit has already resolved the tex, so in those
+ // cases you really do want to attach the texture and not the RBO to the FBO in question.
+
+ bool useRBO = false; // initial state
+
+ if (layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ // it is an MSAA tex
+ if (fboBindPoint == GL_READ_FRAMEBUFFER_EXT)
+ {
+ // I think you just want to read a resolved tex.
+ // But I will check that it is resolved first..
+ Assert( tex->IsRBODirty() == false );
+ }
+ else
+ {
+ // you want to draw into it. You get the RBO bound instead of the tex.
+ useRBO = true;
+ }
+ }
+
+ if (useRBO)
+ {
+ // MSAA path - attach the RBO, not the texture, and mark the RBO dirty
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to attach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ // bind the RBO to the GL_RENDERBUFFER_EXT target
+ gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+
+ // attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
+ gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+
+ gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
+
+ // no need to leave the RBO hanging on
+ gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ }
+ else
+ {
+ // color attachment (likely 0)
+ gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
+
+ gGL->glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
+
+ gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+ }
+ tex->ForceRBODirty();
+ }
+ else
+ {
+ // regular path - attaching a texture2d
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to attach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
+
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
+ }
+ else
+ {
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
+ }
+ }
+ }
+ break;
+
+ case GL_TEXTURE_3D:
+ {
+ gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ {
+ // adjust target to steer to the proper face of the cube map
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params->m_face;
+
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
+ }
+ break;
+ }
+
+ // log the attached tex
+ m_attach[ attachIndex ] = *params;
+
+ // indicate that the tex has been bound to an RT
+ tex->m_rtAttachCount++;
+}
+
+void CGLMFBO::TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
+{
+ // force our parent context to be current
+ m_ctx->MakeCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this, fboBindPoint );
+
+ if (m_attach[ attachIndex ].m_tex)
+ {
+ CGLMTex *tex = m_attach[ attachIndex ].m_tex;
+ GLMTexLayout *layout = tex->m_layout;
+ GLenum target = tex->m_layout->m_key.m_texGLTarget;
+
+ GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
+
+ switch( target )
+ {
+ case GL_TEXTURE_2D:
+ {
+ if (layout->m_key.m_texFlags & kGLMTexMultisampled)
+ {
+ // MSAA path - detach the RBO, not the texture
+ // (is this the right time to resolve? probably better to wait until someone tries to sample the texture)
+
+ gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
+
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
+ gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+
+ gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
+ }
+ else
+ {
+ // color attachment (likely 0)
+ gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
+ }
+ }
+ else
+ {
+ // plain tex detach
+ if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
+ {
+ // you have to detach it both places...
+ // http://www.opengl.org/wiki/GL_EXT_framebuffer_object
+
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, 0, 0 );
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, 0, 0 );
+ }
+ else
+ {
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
+ }
+ }
+ }
+ break;
+
+ case GL_TEXTURE_3D:
+ {
+ gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, 0, 0, 0 );
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ {
+ gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
+ }
+ break;
+ }
+
+ // un-log the attached tex
+ memset( &m_attach[ attachIndex ], 0, sizeof( m_attach[0] ) );
+
+ // drop the RT attach count
+ tex->m_rtAttachCount--;
+ }
+ else
+ {
+ //Debugger(); // odd, but not harmful - typ comes from D3D code passing NULL into SetRenderTarget
+ }
+}
+
+void CGLMFBO::TexScrub( CGLMTex *tex )
+{
+ // see if it's attached anywhere
+ for( int attachIndex = 0; attachIndex < kAttCount; attachIndex++ )
+ {
+ if (m_attach[ attachIndex ].m_tex == tex)
+ {
+ // blammo
+ TexDetach( (EGLMFBOAttachment)attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
+ }
+ }
+}
+
+
+bool CGLMFBO::IsReady( void )
+{
+ bool result = false;
+
+ // ensure our parent context is current
+ m_ctx->CheckCurrent();
+
+ // bind to context (will cause FBO object creation on first use)
+ m_ctx->BindFBOToCtx( this );
+
+ GLenum status;
+ status = gGL->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ result = true;
+ break;
+
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ result = false;
+ DebuggerBreak();
+ /* choose different formats */
+ break;
+
+ default:
+ result = false;
+ DebuggerBreak();
+ /* programming error; will fail on all hardware */
+ break;
+ }
+ return result;
+}