source-engine/togles/linuxwin/cglmfbo.cpp
2021-11-21 01:38:59 +03:00

355 lines
9.7 KiB
C++

//========= 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 "togles/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->glGenFramebuffers( 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->glDeleteFramebuffers( 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 + (int) index;
}
else
{
switch( index )
{
case kAttDepth:
return GL_DEPTH_ATTACHMENT;
break;
case kAttStencil:
return GL_STENCIL_ATTACHMENT;
break;
case kAttDepthStencil:
return GL_DEPTH_STENCIL_ATTACHMENT;
break;
default:
GLMStop(); // bad news
break;
}
}
GLMStop(); // bad news
// shouldn't get here
return GL_COLOR_ATTACHMENT0;
}
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)
{
// 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)
{
// you have to attach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
// bind the RBO to the GL_RENDERBUFFER target
gGL->glBindRenderbuffer( GL_RENDERBUFFER, tex->m_rboName );
// attach the GL_RENDERBUFFER target to the depth and stencil attach points
gGL->glFramebufferRenderbuffer( fboBindPoint, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, tex->m_rboName);
gGL->glFramebufferRenderbuffer( fboBindPoint, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, tex->m_rboName);
// no need to leave the RBO hanging on
gGL->glBindRenderbuffer( GL_RENDERBUFFER, 0 );
}
else
{
// color attachment (likely 0)
gGL->glBindRenderbuffer( GL_RENDERBUFFER, tex->m_rboName );
gGL->glFramebufferRenderbuffer( fboBindPoint, attachIndexGL, GL_RENDERBUFFER, tex->m_rboName);
gGL->glBindRenderbuffer( GL_RENDERBUFFER, 0 );
}
tex->ForceRBODirty();
}
else
{
// regular path - attaching a texture2d
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT)
{
// you have to attach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
gGL->glFramebufferTexture2D( fboBindPoint, GL_DEPTH_ATTACHMENT, target, tex->m_texName, params->m_mip );
gGL->glFramebufferTexture2D( fboBindPoint, GL_STENCIL_ATTACHMENT, target, tex->m_texName, params->m_mip );
}
else
{
gGL->glFramebufferTexture2D( 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->glFramebufferTexture2D( 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->glBindRenderbuffer( GL_RENDERBUFFER, 0 );
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT)
{
// detach the GL_RENDERBUFFER target at depth and stencil attach points
gGL->glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gGL->glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
}
else
{
// color attachment (likely 0)
gGL->glFramebufferRenderbuffer( GL_FRAMEBUFFER, attachIndexGL, GL_RENDERBUFFER, 0);
}
}
else
{
// plain tex detach
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT)
{
// you have to detach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
gGL->glFramebufferTexture2D( fboBindPoint, GL_DEPTH_ATTACHMENT, target, 0, 0 );
gGL->glFramebufferTexture2D( fboBindPoint, GL_STENCIL_ATTACHMENT, target, 0, 0 );
}
else
{
gGL->glFramebufferTexture2D( 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->glFramebufferTexture2D( 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 );
}
}
}
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->glCheckFramebufferStatus(GL_FRAMEBUFFER);
#if 0
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;
}
#endif
return true;
}