initial
This commit is contained in:
358
materialsystem/glmgr/cglmbuffer.cpp
Normal file
358
materialsystem/glmgr/cglmbuffer.cpp
Normal file
@@ -0,0 +1,358 @@
|
||||
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// cglmbuffer.cpp
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
#include "glmgr/glmgr.h"
|
||||
#include "glmgr/cglmbuffer.h"
|
||||
|
||||
// memdbgon -must- be the last include file in a .cpp file.
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// void BindBufferARB(enum target, uint buffer);
|
||||
// void DeleteBuffersARB(sizei n, const uint *buffers);
|
||||
// void GenBuffersARB(sizei n, uint *buffers);
|
||||
// boolean IsBufferARB(uint buffer);
|
||||
//
|
||||
// void BufferDataARB(enum target, sizeiptrARB size, const void *data,
|
||||
// enum usage);
|
||||
// void BufferSubDataARB(enum target, intptrARB offset, sizeiptrARB size,
|
||||
// const void *data);
|
||||
// void GetBufferSubDataARB(enum target, intptrARB offset,
|
||||
// sizeiptrARB size, void *data);
|
||||
//
|
||||
// void *MapBufferARB(enum target, enum access);
|
||||
// boolean UnmapBufferARB(enum target);
|
||||
//
|
||||
// void GetBufferParameterivARB(enum target, enum pname, int *params);
|
||||
// void GetBufferPointervARB(enum target, enum pname, void **params);
|
||||
//
|
||||
//New Tokens
|
||||
//
|
||||
// Accepted by the <target> parameters of BindBufferARB, BufferDataARB,
|
||||
// BufferSubDataARB, MapBufferARB, UnmapBufferARB,
|
||||
// GetBufferSubDataARB, GetBufferParameterivARB, and
|
||||
// GetBufferPointervARB:
|
||||
//
|
||||
// ARRAY_BUFFER_ARB 0x8892
|
||||
// ELEMENT_ARRAY_BUFFER_ARB 0x8893
|
||||
//
|
||||
// Accepted by the <pname> parameter of GetBooleanv, GetIntegerv,
|
||||
// GetFloatv, and GetDoublev:
|
||||
//
|
||||
// ARRAY_BUFFER_BINDING_ARB 0x8894
|
||||
// ELEMENT_ARRAY_BUFFER_BINDING_ARB 0x8895
|
||||
// VERTEX_ARRAY_BUFFER_BINDING_ARB 0x8896
|
||||
// NORMAL_ARRAY_BUFFER_BINDING_ARB 0x8897
|
||||
// COLOR_ARRAY_BUFFER_BINDING_ARB 0x8898
|
||||
// INDEX_ARRAY_BUFFER_BINDING_ARB 0x8899
|
||||
// TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB 0x889A
|
||||
// EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB 0x889B
|
||||
// SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB 0x889C
|
||||
// FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB 0x889D
|
||||
// WEIGHT_ARRAY_BUFFER_BINDING_ARB 0x889E
|
||||
//
|
||||
// Accepted by the <pname> parameter of GetVertexAttribivARB:
|
||||
//
|
||||
// VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB 0x889F
|
||||
//
|
||||
// Accepted by the <usage> parameter of BufferDataARB:
|
||||
//
|
||||
// STREAM_DRAW_ARB 0x88E0
|
||||
// STREAM_READ_ARB 0x88E1
|
||||
// STREAM_COPY_ARB 0x88E2
|
||||
// STATIC_DRAW_ARB 0x88E4
|
||||
// STATIC_READ_ARB 0x88E5
|
||||
// STATIC_COPY_ARB 0x88E6
|
||||
// DYNAMIC_DRAW_ARB 0x88E8
|
||||
// DYNAMIC_READ_ARB 0x88E9
|
||||
// DYNAMIC_COPY_ARB 0x88EA
|
||||
//
|
||||
// Accepted by the <access> parameter of MapBufferARB:
|
||||
//
|
||||
// READ_ONLY_ARB 0x88B8
|
||||
// WRITE_ONLY_ARB 0x88B9
|
||||
// READ_WRITE_ARB 0x88BA
|
||||
//
|
||||
// Accepted by the <pname> parameter of GetBufferParameterivARB:
|
||||
//
|
||||
// BUFFER_SIZE_ARB 0x8764
|
||||
// BUFFER_USAGE_ARB 0x8765
|
||||
// BUFFER_ACCESS_ARB 0x88BB
|
||||
// BUFFER_MAPPED_ARB 0x88BC
|
||||
//
|
||||
// Accepted by the <pname> parameter of GetBufferPointervARB:
|
||||
//
|
||||
// BUFFER_MAP_POINTER_ARB 0x88BD
|
||||
|
||||
// http://www.opengl.org/registry/specs/ARB/pixel_buffer_object.txt
|
||||
// Accepted by the <target> parameters of BindBuffer, BufferData,
|
||||
// BufferSubData, MapBuffer, UnmapBuffer, GetBufferSubData,
|
||||
// GetBufferParameteriv, and GetBufferPointerv:
|
||||
// PIXEL_PACK_BUFFER_ARB 0x88EB
|
||||
// PIXEL_UNPACK_BUFFER_ARB 0x88EC
|
||||
|
||||
|
||||
// gl_bufmode: zero means we mark all vertex/index buffers static
|
||||
|
||||
// non zero means buffers are initially marked static..
|
||||
// ->but can shift to dynamic upon first 'discard' (orphaning)
|
||||
|
||||
ConVar gl_bufmode( "gl_bufmode", "1" );
|
||||
|
||||
CGLMBuffer::CGLMBuffer( GLMContext *ctx, EGLMBufferType type, uint size, uint options )
|
||||
{
|
||||
m_ctx = ctx;
|
||||
m_type = type;
|
||||
switch(m_type)
|
||||
{
|
||||
case kGLMVertexBuffer: m_buffGLTarget = GL_ARRAY_BUFFER_ARB; break;
|
||||
case kGLMIndexBuffer: m_buffGLTarget = GL_ELEMENT_ARRAY_BUFFER_ARB; break;
|
||||
case kGLMUniformBuffer: m_buffGLTarget = GL_UNIFORM_BUFFER_EXT; break;
|
||||
case kGLMPixelBuffer: m_buffGLTarget = GL_PIXEL_UNPACK_BUFFER_ARB; break;
|
||||
|
||||
default: Assert(!"Unknown buffer type" );
|
||||
}
|
||||
m_size = size;
|
||||
m_bound = false;
|
||||
m_mapped = false;
|
||||
m_lastMappedAddress = NULL;
|
||||
|
||||
m_enableAsyncMap = false;
|
||||
m_enableExplicitFlush = false;
|
||||
m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
|
||||
|
||||
m_ctx->CheckCurrent();
|
||||
m_revision = rand();
|
||||
|
||||
// make a decision about pseudo mode
|
||||
// this looked like it didn't help much or was actually slower, so leave it available but only as opt-in.
|
||||
// a more clever implementation would be able to select pseudo buf storage for small batches only..
|
||||
m_pseudo = (m_type==kGLMIndexBuffer) && (CommandLine()->FindParm("-gl_enable_pseudobufs"));
|
||||
if (m_pseudo)
|
||||
{
|
||||
m_name = 0;
|
||||
m_pseudoBuf = (char*)malloc( size );
|
||||
|
||||
m_ctx->BindBufferToCtx( m_type, NULL ); // exit with no buffer bound
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenBuffersARB( 1, &m_name );
|
||||
GLMCheckError();
|
||||
|
||||
m_ctx->BindBufferToCtx( m_type, this ); // causes glBindBufferARB
|
||||
|
||||
// buffers start out static, but if they get orphaned and gl_bufmode is non zero,
|
||||
// then they will get flipped to dynamic.
|
||||
|
||||
GLenum hint = GL_STATIC_DRAW_ARB;
|
||||
switch(m_type)
|
||||
{
|
||||
case kGLMVertexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
|
||||
case kGLMIndexBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
|
||||
case kGLMUniformBuffer: hint = GL_DYNAMIC_DRAW_ARB; break; // "fwiw" - shrug
|
||||
case kGLMPixelBuffer: hint = (options & GLMBufferOptionDynamic) ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB; break;
|
||||
|
||||
default: Assert(!"Unknown buffer type" );
|
||||
}
|
||||
|
||||
glBufferDataARB( m_buffGLTarget, m_size, NULL, hint ); // may ultimately need more hints to set the usage correctly (esp for streaming)
|
||||
|
||||
this->SetModes( true, true, true );
|
||||
|
||||
m_ctx->BindBufferToCtx( m_type, NULL ); // unbind me
|
||||
}
|
||||
}
|
||||
|
||||
CGLMBuffer::~CGLMBuffer( )
|
||||
{
|
||||
m_ctx->CheckCurrent();
|
||||
|
||||
if (m_pseudo)
|
||||
{
|
||||
free (m_pseudoBuf);
|
||||
m_pseudoBuf = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteBuffersARB( 1, &m_name );
|
||||
GLMCheckError();
|
||||
}
|
||||
|
||||
m_ctx = NULL;
|
||||
m_name = 0;
|
||||
m_bound = 0;
|
||||
|
||||
m_lastMappedAddress = NULL;
|
||||
}
|
||||
|
||||
void CGLMBuffer::SetModes ( bool asyncMap, bool explicitFlush, bool force )
|
||||
{
|
||||
// assumes buffer is bound. called by constructor and by Lock.
|
||||
|
||||
if (m_pseudo)
|
||||
{
|
||||
// ignore it...
|
||||
}
|
||||
else
|
||||
{
|
||||
if (force || (m_enableAsyncMap != asyncMap) )
|
||||
{
|
||||
// note the sense of the parameter, it's TRUE if you *want* serialization, so for async you turn it to false.
|
||||
glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_SERIALIZED_MODIFY_APPLE, asyncMap==false );
|
||||
m_enableAsyncMap = asyncMap;
|
||||
}
|
||||
|
||||
if (force || (m_enableExplicitFlush != explicitFlush) )
|
||||
{
|
||||
// note the sense of the parameter, it's TRUE if you *want* auto-flush-on-unmap, so for explicit-flush, you turn it to false.
|
||||
glBufferParameteriAPPLE( this->m_buffGLTarget, GL_BUFFER_FLUSHING_UNMAP_APPLE, explicitFlush==false );
|
||||
m_enableExplicitFlush = explicitFlush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGLMBuffer::FlushRange ( uint offset, uint size )
|
||||
{
|
||||
if (m_pseudo)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
else
|
||||
{
|
||||
// assumes buffer is bound.
|
||||
glFlushMappedBufferRangeAPPLE(this->m_buffGLTarget, (GLintptr)offset, (GLsizeiptr)size);
|
||||
}
|
||||
}
|
||||
|
||||
ConVar gl_buffer_alignment_quantum ( "gl_buffer_alignment_quantum", "32" ); // the alignment we use pre-SLGU
|
||||
ConVar gl_buffer_alignment_quantum_slgu( "gl_buffer_alignment_quantum_slgu", "2" ); // alignment used post-SLGU
|
||||
|
||||
void CGLMBuffer::Lock( GLMBuffLockParams *params, char **addressOut )
|
||||
{
|
||||
char *resultPtr = NULL;
|
||||
|
||||
Assert( !m_mapped);
|
||||
|
||||
m_ctx->CheckCurrent();
|
||||
GLMCheckError();
|
||||
|
||||
if (params->m_offset >= m_size)
|
||||
Debugger();
|
||||
|
||||
if (params->m_offset + params->m_size > m_size)
|
||||
Debugger();
|
||||
|
||||
// bind (yes, even for pseudo - this binds name 0)
|
||||
m_ctx->BindBufferToCtx( this->m_type, this );
|
||||
|
||||
if (m_pseudo)
|
||||
{
|
||||
// discard is a no-op
|
||||
|
||||
// async map modes are a no-op
|
||||
|
||||
// latch last mapped address (silly..)
|
||||
m_lastMappedAddress = (float*)m_pseudoBuf;
|
||||
|
||||
// calc lock address
|
||||
resultPtr = m_pseudoBuf + params->m_offset;
|
||||
|
||||
// dirty range is a no-op
|
||||
}
|
||||
else
|
||||
{
|
||||
// perform discard if requested
|
||||
if (params->m_discard)
|
||||
{
|
||||
// observe gl_bufmode on any orphan event.
|
||||
// if orphaned and bufmode is nonzero, flip it to dynamic.
|
||||
GLenum hint = gl_bufmode.GetInt() ? GL_DYNAMIC_DRAW_ARB : GL_STATIC_DRAW_ARB;
|
||||
glBufferDataARB( m_buffGLTarget, m_size, NULL, hint );
|
||||
|
||||
m_lastMappedAddress = NULL;
|
||||
|
||||
m_revision++; // revision grows on orphan event
|
||||
}
|
||||
|
||||
// adjust async map option appropriately, leave explicit flush unchanged
|
||||
this->SetModes( params->m_nonblocking, m_enableExplicitFlush );
|
||||
|
||||
// map
|
||||
char *mapPtr = (char*)glMapBufferARB( this->m_buffGLTarget, GL_READ_WRITE_ARB );
|
||||
|
||||
if (!mapPtr)
|
||||
{
|
||||
Debugger();
|
||||
}
|
||||
|
||||
if (m_lastMappedAddress)
|
||||
{
|
||||
// just check if it moved
|
||||
Assert (m_lastMappedAddress == (float*)mapPtr);
|
||||
}
|
||||
|
||||
m_lastMappedAddress = (float*)mapPtr;
|
||||
|
||||
// calculate offset location
|
||||
resultPtr = mapPtr + params->m_offset;
|
||||
|
||||
// adjust dirty range
|
||||
if (m_dirtyMinOffset != m_dirtyMaxOffset)
|
||||
{
|
||||
// grow range
|
||||
m_dirtyMinOffset = MIN( m_dirtyMinOffset, params->m_offset );
|
||||
m_dirtyMaxOffset = MIN( m_dirtyMaxOffset, params->m_offset+params->m_size );
|
||||
}
|
||||
else
|
||||
{
|
||||
// set range
|
||||
m_dirtyMinOffset = params->m_offset;
|
||||
m_dirtyMaxOffset = params->m_offset+params->m_size;
|
||||
}
|
||||
|
||||
// pad and clamp dirty range to choice of boundary
|
||||
uint quantum = (m_ctx->Caps().m_hasPerfPackage1) ? gl_buffer_alignment_quantum_slgu.GetInt() : gl_buffer_alignment_quantum.GetInt();
|
||||
uint quantum_mask = quantum - 1;
|
||||
|
||||
m_dirtyMinOffset = m_dirtyMinOffset & (~quantum_mask);
|
||||
m_dirtyMaxOffset = (m_dirtyMaxOffset + quantum_mask) & (~quantum_mask);
|
||||
m_dirtyMaxOffset = MIN( m_dirtyMaxOffset, m_size );
|
||||
}
|
||||
|
||||
m_mapped = true;
|
||||
|
||||
*addressOut = resultPtr;
|
||||
}
|
||||
|
||||
void CGLMBuffer::Unlock( void )
|
||||
{
|
||||
m_ctx->CheckCurrent();
|
||||
|
||||
Assert (m_mapped);
|
||||
|
||||
if (m_pseudo)
|
||||
{
|
||||
// nothing to do actually
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ctx->BindBufferToCtx( this->m_type, this );
|
||||
|
||||
// time to do explicit flush
|
||||
if (m_enableExplicitFlush)
|
||||
{
|
||||
this->FlushRange( m_dirtyMinOffset, m_dirtyMaxOffset - m_dirtyMinOffset );
|
||||
}
|
||||
|
||||
// clear dirty range no matter what
|
||||
m_dirtyMinOffset = m_dirtyMaxOffset = 0; // adjust/grow on lock, clear on unlock
|
||||
|
||||
glUnmapBuffer( this->m_buffGLTarget );
|
||||
|
||||
}
|
||||
|
||||
m_mapped = false;
|
||||
}
|
||||
355
materialsystem/glmgr/cglmfbo.cpp
Normal file
355
materialsystem/glmgr/cglmfbo.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// cglmfbo.cpp
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
#include "glmgr/glmgr.h"
|
||||
#include "glmgr/cglmfbo.h"
|
||||
// #include "../shaderapidx9/dxabstract.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();
|
||||
|
||||
glGenFramebuffersEXT( 1, &m_name );
|
||||
GLMCheckError();
|
||||
|
||||
memset( m_attach, 0, sizeof( m_attach ) );
|
||||
|
||||
m_sizeX = m_sizeY = 0;
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
GLMCheckError();
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteFramebuffersEXT( 1, &m_name );
|
||||
GLMCheckError();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 hasone, **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->m_rboDirty == 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
|
||||
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
|
||||
GLMCheckError();
|
||||
|
||||
// attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
|
||||
glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
|
||||
GLMCheckError();
|
||||
|
||||
glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
|
||||
GLMCheckError();
|
||||
|
||||
// no need to leave the RBO hanging on
|
||||
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
|
||||
GLMCheckError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// color attachment (likely 0)
|
||||
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
|
||||
GLMCheckError();
|
||||
|
||||
glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
|
||||
GLMCheckError();
|
||||
|
||||
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
|
||||
GLMCheckError();
|
||||
}
|
||||
tex->m_rboDirty = true;
|
||||
}
|
||||
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
|
||||
|
||||
glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
|
||||
GLMCheckError();
|
||||
|
||||
glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
|
||||
GLMCheckError();
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
|
||||
GLMCheckError();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
{
|
||||
glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
|
||||
GLMCheckError();
|
||||
}
|
||||
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;
|
||||
|
||||
glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
|
||||
GLMCheckError();
|
||||
}
|
||||
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)
|
||||
|
||||
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
|
||||
GLMCheckError();
|
||||
|
||||
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
|
||||
{
|
||||
// detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
|
||||
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
|
||||
GLMCheckError();
|
||||
|
||||
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
|
||||
GLMCheckError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// color attachment (likely 0)
|
||||
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
|
||||
GLMCheckError();
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, 0,0,0 );
|
||||
glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, 0,0,0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_3D:
|
||||
{
|
||||
glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, 0, 0, 0, 0 );
|
||||
GLMCheckError();
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
{
|
||||
glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, 0, 0, 0 );
|
||||
GLMCheckError();
|
||||
}
|
||||
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 = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
switch(status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
result = false;
|
||||
Debugger();
|
||||
/* choose different formats */
|
||||
break;
|
||||
|
||||
default:
|
||||
result = false;
|
||||
Debugger();
|
||||
/* programming error; will fail on all hardware */
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
1420
materialsystem/glmgr/cglmprogram.cpp
Normal file
1420
materialsystem/glmgr/cglmprogram.cpp
Normal file
File diff suppressed because it is too large
Load Diff
413
materialsystem/glmgr/cglmquery.cpp
Normal file
413
materialsystem/glmgr/cglmquery.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// cglmquery.cpp
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
#include "glmgr/glmgr.h"
|
||||
#include "glmgr/cglmquery.h"
|
||||
#include "../shaderapidx9/dxabstract.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// memdbgon -must- be the last include file in a .cpp file.
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//===============================================================================
|
||||
|
||||
extern ConVar gl_errorcheckall;
|
||||
extern ConVar gl_errorcheckqueries;
|
||||
extern ConVar gl_errorchecknone;
|
||||
|
||||
// how many microseconds to wait after a failed query-available test
|
||||
// presently on MTGL this doesn't happen, but it could change, keep this handy
|
||||
ConVar gl_nullqueries( "gl_nullqueries", "0" );
|
||||
|
||||
GLenum GetQueryError( void )
|
||||
{
|
||||
if ( ( GLMDEBUG || (gl_errorcheckall.GetInt() != 0) || (gl_errorcheckqueries.GetInt() != 0) ) && (gl_errorchecknone.GetInt() == 0) )
|
||||
{
|
||||
return glGetError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (GLenum) 0; // whistle past graveyard
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================================================
|
||||
|
||||
CGLMQuery::CGLMQuery( GLMContext *ctx, GLMQueryParams *params )
|
||||
{
|
||||
// make sure context is current
|
||||
// get the type of query requested
|
||||
// generate name(s) needed
|
||||
// set initial state appropriately
|
||||
ctx->MakeCurrent();
|
||||
|
||||
m_ctx = ctx;
|
||||
m_params = *params;
|
||||
|
||||
m_name = 0;
|
||||
|
||||
m_started = m_stopped = m_done = false;
|
||||
|
||||
m_nullQuery = false;
|
||||
// assume value of convar at start time
|
||||
// does not change during individual query lifetime
|
||||
// started null = stays null
|
||||
// started live = stays live
|
||||
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion:
|
||||
{
|
||||
//make an occlusion query (and a fence to go with it)
|
||||
glGenQueriesARB( 1, &m_name );
|
||||
GLMPRINTF(("-A- CGLMQuery(OQ) created name %d", m_name));
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::CGLMQuery (OQ) saw %s error (%d) from glGenQueriesARB", decodedStr, errorcode );
|
||||
m_name = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
//make a fence - no aux fence needed
|
||||
glGenFencesAPPLE(1, &m_name );
|
||||
GLMPRINTF(("-A- CGLMQuery(fence) created name %d", m_name));
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::CGLMQuery (fence) saw %s error (%d) from glGenFencesAPPLE", decodedStr, errorcode );
|
||||
m_name = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CGLMQuery::~CGLMQuery()
|
||||
{
|
||||
GLMPRINTF(("-A-> ~CGLMQuery"));
|
||||
|
||||
// make sure query has completed (might not be necessary)
|
||||
// delete the name(s)
|
||||
|
||||
m_ctx->MakeCurrent();
|
||||
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion:
|
||||
{
|
||||
// do a finish occlusion query ?
|
||||
GLMPRINTF(("-A- ~CGLMQuery(OQ) deleting name %d", m_name));
|
||||
glDeleteQueries(1, &m_name );
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::~CGLMQuery (OQ) saw %s error (%d) from glDeleteQueries", decodedStr, errorcode );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
{
|
||||
// do a finish fence ?
|
||||
GLMPRINTF(("-A- ~CGLMQuery(fence) deleting name %d", m_name));
|
||||
glDeleteFencesAPPLE(1, &m_name );
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::~CGLMQuery (fence) saw %s error (%d) from glDeleteFencesAPPLE", decodedStr, errorcode );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
m_name = 0;
|
||||
|
||||
GLMPRINTF(("-A-< ~CGLMQuery"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void CGLMQuery::Start( void ) // "start counting"
|
||||
{
|
||||
m_ctx->MakeCurrent();
|
||||
|
||||
// on occlusion query:
|
||||
// glBeginQueryARB on the OQ name. counting starts.
|
||||
|
||||
// on fence: glSetFence on m_name.
|
||||
|
||||
// note, fences finish themselves via command progress - OQ's do not.
|
||||
|
||||
Assert(!m_started);
|
||||
Assert(!m_stopped);
|
||||
Assert(!m_done);
|
||||
|
||||
m_nullQuery = (gl_nullqueries.GetInt() != 0); // latch value for remainder of query life
|
||||
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion:
|
||||
{
|
||||
if (m_nullQuery)
|
||||
{
|
||||
// do nothing..
|
||||
}
|
||||
else
|
||||
{
|
||||
glBeginQueryARB( GL_SAMPLES_PASSED_ARB, m_name );
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Start(OQ) saw %s error (%d) from glBeginQueryARB (GL_SAMPLES_PASSED_ARB) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
glSetFenceAPPLE( m_name );
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Start(fence) saw %s error (%d) from glSetFenceAPPLE name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
|
||||
m_stopped = true; // caller should not call Stop on a fence, it self-stops
|
||||
break;
|
||||
}
|
||||
|
||||
m_started = true;
|
||||
}
|
||||
|
||||
void CGLMQuery::Stop( void ) // "stop counting"
|
||||
{
|
||||
m_ctx->MakeCurrent();
|
||||
|
||||
Assert(m_started);
|
||||
Assert(!m_stopped); // this will assert if you try to call Stop on a fence that is started
|
||||
Assert(!m_done);
|
||||
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion:
|
||||
{
|
||||
if (m_nullQuery)
|
||||
{
|
||||
// do nothing..
|
||||
}
|
||||
else
|
||||
{
|
||||
glEndQueryARB( GL_SAMPLES_PASSED_ARB ); // we are only putting the request-to-stop-counting into the cmd stream.
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Stop(OQ) saw %s error (%d) from glEndQueryARB( GL_SAMPLES_PASSED_ARB ) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
// nop - you don't "end" a fence, you just test it and/or finish it out in Complete
|
||||
break;
|
||||
}
|
||||
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
bool CGLMQuery::IsDone( void )
|
||||
{
|
||||
m_ctx->MakeCurrent();
|
||||
|
||||
Assert(m_started);
|
||||
Assert(m_stopped);
|
||||
|
||||
if(!m_done) // you can ask more than once, but we only check until it comes back as done.
|
||||
{
|
||||
// on occlusion: glGetQueryObjectivARB - large cost on pre SLGU, cheap after
|
||||
// on fence: glTestFenceAPPLE on the fence
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion: // just test the fence that was set after the query begin
|
||||
{
|
||||
if (m_nullQuery)
|
||||
{
|
||||
// do almost nothing.. but claim work is complete
|
||||
m_done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// prepare to pay a big price on drivers prior to 10.6.4+SLGU
|
||||
|
||||
GLint available = 0;
|
||||
glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glGetQueryObjectivARB(a2) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
|
||||
m_done = (available != 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
{
|
||||
m_done = glTestFenceAPPLE( m_name );
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glTestFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
|
||||
if (m_done)
|
||||
{
|
||||
glFinishFenceAPPLE( m_name ); // no set fence goes un-finished
|
||||
|
||||
errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glFinishFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return m_done;
|
||||
}
|
||||
|
||||
void CGLMQuery::Complete( uint *result )
|
||||
{
|
||||
m_ctx->MakeCurrent();
|
||||
|
||||
uint resultval = 0;
|
||||
GLint available = 0;
|
||||
bool bogus_available = false;
|
||||
|
||||
// blocking call if not done
|
||||
Assert(m_started);
|
||||
Assert(m_stopped);
|
||||
|
||||
switch(m_params.m_type)
|
||||
{
|
||||
case EOcclusion:
|
||||
{
|
||||
if (m_nullQuery)
|
||||
{
|
||||
m_done = true;
|
||||
resultval = 0; // we did say "null queries..."
|
||||
}
|
||||
else
|
||||
{
|
||||
// accept that the query is going to drain pipe in 10.6.4 and prior.
|
||||
// check the error on the spot.
|
||||
glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
|
||||
GLenum errorcode = GetQueryError();
|
||||
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_AVAILABLE_ARB name=%d", decodedStr, errorcode, m_name );
|
||||
|
||||
resultval=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!available)
|
||||
{
|
||||
// this does happen with some very modest frequency.
|
||||
if (!m_ctx->Caps().m_hasPerfPackage1)
|
||||
{
|
||||
glFlush(); // ISTR some deadlock cases on pre-SLGU drivers if you didn't do this to kick the queue along..
|
||||
}
|
||||
}
|
||||
|
||||
glGetQueryObjectuivARB( m_name, GL_QUERY_RESULT_ARB, &resultval);
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_ARB name=%d", decodedStr, errorcode, m_name );
|
||||
|
||||
resultval=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// resultval is legit
|
||||
}
|
||||
}
|
||||
m_done = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EFence:
|
||||
{
|
||||
if(!m_done)
|
||||
{
|
||||
glFinishFenceAPPLE( m_name );
|
||||
|
||||
GLenum errorcode = GetQueryError();
|
||||
if (errorcode)
|
||||
{
|
||||
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
|
||||
printf( "\nCGLMQuery::Complete saw %s error (%d) from glFinishFenceAPPLE (EFence) name=%d", decodedStr, errorcode, m_name );
|
||||
}
|
||||
|
||||
m_done = true; // for clarity or if they try to Complete twice
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Assert( m_done );
|
||||
|
||||
// reset state for re-use - i.e. you have to call Complete if you want to re-use the object
|
||||
m_started = m_stopped = m_done = false;
|
||||
|
||||
if (result) // caller may pass NULL if not interested in result, for example to clear a fence
|
||||
{
|
||||
*result = resultval;
|
||||
}
|
||||
}
|
||||
|
||||
// accessors for the started/stopped state
|
||||
bool CGLMQuery::IsStarted ( void )
|
||||
{
|
||||
return m_started;
|
||||
}
|
||||
|
||||
bool CGLMQuery::IsStopped ( void )
|
||||
{
|
||||
return m_stopped;
|
||||
}
|
||||
|
||||
1831
materialsystem/glmgr/cglmtex.cpp
Normal file
1831
materialsystem/glmgr/cglmtex.cpp
Normal file
File diff suppressed because it is too large
Load Diff
7035
materialsystem/glmgr/glmgr.cpp
Normal file
7035
materialsystem/glmgr/glmgr.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4054
materialsystem/glmgr/glmgrbasics.cpp
Normal file
4054
materialsystem/glmgr/glmgrbasics.cpp
Normal file
File diff suppressed because it is too large
Load Diff
80
materialsystem/glmgr/glmgrcocoa.mm
Normal file
80
materialsystem/glmgr/glmgrcocoa.mm
Normal file
@@ -0,0 +1,80 @@
|
||||
//========= Copyright 1996-2009, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: provide some call-out glue to ObjC from the C++ GLMgr code
|
||||
//
|
||||
// $Revision: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define DONT_DEFINE_BOOL // Don't define BOOL!
|
||||
#include "tier0/threadtools.h"
|
||||
#include "tier1/interface.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier1/utllinkedlist.h"
|
||||
#include "glmgr/glmgr.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
// some glue to let GLMgr call into NS/ObjC classes.
|
||||
// ------------------------------------------------------------------------------------ //
|
||||
|
||||
bool NewNSGLContext( unsigned long *attribs, PseudoNSGLContextPtr nsglShareCtx, PseudoNSGLContextPtr *nsglCtxOut, CGLContextObj *cglCtxOut )
|
||||
{
|
||||
NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init ];
|
||||
NSOpenGLPixelFormat *pixFmt = NULL;
|
||||
NSOpenGLContext *nsglCtx = NULL;
|
||||
|
||||
bool result = true; // optimism
|
||||
|
||||
if (result)
|
||||
{
|
||||
pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:(NSOpenGLPixelFormatAttribute*)attribs];
|
||||
if (!pixFmt)
|
||||
{
|
||||
Debugger(); // bad news
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
nsglCtx = [[NSOpenGLContext alloc] initWithFormat: pixFmt shareContext: (NSOpenGLContext*) nsglShareCtx ];
|
||||
if (!nsglCtx)
|
||||
{
|
||||
Debugger();
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
[nsglCtx makeCurrentContext];
|
||||
|
||||
*nsglCtxOut = nsglCtx;
|
||||
*cglCtxOut = (CGLContextObj)[ (NSOpenGLContext*)nsglCtx CGLContextObj ];
|
||||
}
|
||||
else
|
||||
{
|
||||
*nsglCtxOut = NULL;
|
||||
*cglCtxOut = NULL;
|
||||
}
|
||||
|
||||
[tempPool release];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
CGLContextObj GetCGLContextFromNSGL( PseudoNSGLContextPtr nsglCtx )
|
||||
{
|
||||
return (CGLContextObj)[ (NSOpenGLContext*)nsglCtx CGLContextObj];
|
||||
}
|
||||
|
||||
void DelNSGLContext( PseudoNSGLContextPtr nsglCtx )
|
||||
{
|
||||
[ (NSOpenGLContext*)nsglCtx release ];
|
||||
}
|
||||
|
||||
104
materialsystem/glmgr/glmgrext.cpp
Normal file
104
materialsystem/glmgr/glmgrext.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
//============ Copyright (c) Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// glmgrext.h
|
||||
// helper file for extension testing and runtime importing of entry points
|
||||
//
|
||||
//===============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glext.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "glmgr/glmgr.h"
|
||||
|
||||
PFNglColorMaskIndexedEXT pfnglColorMaskIndexedEXT;
|
||||
PFNglEnableIndexedEXT pfnglEnableIndexedEXT;
|
||||
PFNglDisableIndexedEXT pfnglDisableIndexedEXT;
|
||||
PFNglGetFramebufferAttachmentParameteriv pfnglGetFramebufferAttachmentParameteriv;
|
||||
PFNglUniformBufferEXT pfnglUniformBufferEXT;
|
||||
|
||||
void * NSGLGetProcAddress (const char *name)
|
||||
{
|
||||
NSSymbol symbol;
|
||||
char *symbolName = (char *)malloc (strlen (name) + 2);
|
||||
strcpy(symbolName + 1, name);
|
||||
symbolName[0] = '_';
|
||||
symbol = NULL;
|
||||
if (NSIsSymbolNameDefined (symbolName))
|
||||
symbol = NSLookupAndBindSymbol (symbolName);
|
||||
free (symbolName);
|
||||
return symbol ? NSAddressOfSymbol (symbol) : NULL;
|
||||
}
|
||||
|
||||
|
||||
void GLMSetupExtensions( void )
|
||||
{
|
||||
pfnglColorMaskIndexedEXT = (PFNglColorMaskIndexedEXT) NSGLGetProcAddress( "glColorMaskIndexedEXT" );
|
||||
pfnglEnableIndexedEXT = (PFNglEnableIndexedEXT) NSGLGetProcAddress( "glEnableIndexedEXT" );
|
||||
pfnglDisableIndexedEXT = (PFNglDisableIndexedEXT) NSGLGetProcAddress( "glDisableIndexedEXT" );
|
||||
|
||||
pfnglGetFramebufferAttachmentParameteriv = (PFNglGetFramebufferAttachmentParameteriv) NSGLGetProcAddress( "glGetFramebufferAttachmentParameteriv" );
|
||||
|
||||
pfnglUniformBufferEXT = (PFNglUniformBufferEXT) NSGLGetProcAddress( "glUniformBufferEXT" );
|
||||
}
|
||||
|
||||
/*
|
||||
#define INSTANTIATE_GL_IMPORTS
|
||||
#include "glmgr/glmgr.h" // will include glmgrext.h
|
||||
#undef INSTANTIATE_GL_IMPORTS
|
||||
|
||||
|
||||
// helper class for looking up function names
|
||||
// see http://andrewtolbert.com/svn/personal/OpenGLSuperBible/shared/gltools.cpp
|
||||
// also http://developer.apple.com/mac/library/DOCUMENTATION/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_entrypts/opengl_entrypts.html
|
||||
|
||||
class CFunctionImporter
|
||||
{
|
||||
public:
|
||||
CFBundleRef m_bundle;
|
||||
|
||||
CFunctionImporter( CFStringRef bundleID ) // for example CFSTR("com.apple.OpenGL")
|
||||
{
|
||||
m_bundle = CFBundleGetBundleWithIdentifier( bundleID );
|
||||
if ( m_bundle )
|
||||
CFRetain( m_bundle );
|
||||
}
|
||||
|
||||
~CFunctionImporter()
|
||||
{
|
||||
if( m_bundle )
|
||||
{
|
||||
CFRelease(m_bundle);
|
||||
m_bundle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void *FindFunctionByName(CFStringRef name) // ex CFSTR("glColorMaskedIndexedEXT")
|
||||
{
|
||||
void *result = NULL;
|
||||
if (m_bundle)
|
||||
{
|
||||
result = CFBundleGetFunctionPointerForName(m_bundle, name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void GLMSetupExtensions( void )
|
||||
{
|
||||
CFunctionImporter importer( CFSTR("com.apple.OpenGL") );
|
||||
|
||||
#define DO_IMPORT(name) name = (name##FuncPtr)importer.FindFunctionByName( CFSTR(#name) );
|
||||
|
||||
#ifndef GL_EXT_draw_buffers2
|
||||
// FIXME we're not checking for the extension string yet, we're just grabbing func ptrs
|
||||
DO_IMPORT(glColorMaskIndexedEXT);
|
||||
DO_IMPORT(glEnableIndexedEXT);
|
||||
DO_IMPORT(glDisableIndexedEXT);
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user