diff options
Diffstat (limited to 'togl/linuxwin/cglmfbo.cpp')
| -rw-r--r-- | togl/linuxwin/cglmfbo.cpp | 355 |
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; +} |