|
|
//========= 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; }
|