//========= 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.
//
// glmgr.h
// singleton class, common basis for managing GL contexts
// responsible for tracking adapters and contexts
//
//===============================================================================
# ifndef GLMGR_H
# define GLMGR_H
# pragma once
# undef HAVE_GL_ARB_SYNC
# ifndef OSX
# define HAVE_GL_ARB_SYNC 1
# endif
# include "glbase.h"
# include "glentrypoints.h"
# include "glmdebug.h"
# include "glmdisplay.h"
# include "glmgrext.h"
# include "glmgrbasics.h"
# include "cglmtex.h"
# include "cglmfbo.h"
# include "cglmprogram.h"
# include "cglmbuffer.h"
# include "cglmquery.h"
# include "tier0/tslist.h"
# include "tier0/vprof_telemetry.h"
# include "materialsystem/IShader.h"
# include "dxabstract_types.h"
# include "tier0/icommandline.h"
# undef FORCEINLINE
# define FORCEINLINE inline
//===============================================================================
# define GLM_OPENGL_VENDOR_ID 1
# define GLM_OPENGL_DEFAULT_DEVICE_ID 1
# define GLM_OPENGL_LOW_PERF_DEVICE_ID 2
# define GL_ALPHA_TEST_QCOM 0x0BC0
# define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
# define GL_ALPHA_TEST_REF_QCOM 0x0BC2
# define GLSL_VERSION "#version 300 es\n"
extern void GLMDebugPrintf ( const char * pMsg , . . . ) ;
extern uint g_nTotalDrawsOrClears , g_nTotalVBLockBytes , g_nTotalIBLockBytes ;
# if GL_TELEMETRY_GPU_ZONES
struct TelemetryGPUStats_t
{
uint m_nTotalBufferLocksAndUnlocks ;
uint m_nTotalTexLocksAndUnlocks ;
uint m_nTotalBlit2 ;
uint m_nTotalResolveTex ;
uint m_nTotalPresent ;
inline void Clear ( ) { memset ( this , 0 , sizeof ( * this ) ) ; }
inline uint GetTotal ( ) const { return m_nTotalBufferLocksAndUnlocks + m_nTotalTexLocksAndUnlocks + m_nTotalBlit2 + m_nTotalResolveTex + m_nTotalPresent ; }
} ;
extern TelemetryGPUStats_t g_TelemetryGPUStats ;
# endif
struct GLMRect ;
typedef void * PseudoGLContextPtr ;
// parrot the D3D present parameters, more or less... "adapter" translates into "active display index" per the m_activeDisplayCount below.
class GLMDisplayParams
{
public :
// presumption, these indices are in sync with the current display DB that GLMgr has handy
//int m_rendererIndex; // index of renderer (-1 if root context)
//int m_displayIndex; // index of display in renderer - for FS
//int m_modeIndex; // index of mode in display - for FS
void * m_focusWindow ; // (VD3DHWND aka WindowRef) - what window does this context display into
bool m_fsEnable ; // fullscreen on or not
bool m_vsyncEnable ; // vsync on or not
// height and width have to match the display mode info if full screen.
uint m_backBufferWidth ; // pixel width (aka screen h-resolution if full screen)
uint m_backBufferHeight ; // pixel height (aka screen v-resolution if full screen)
D3DFORMAT m_backBufferFormat ; // pixel format
uint m_multiSampleCount ; // 0 means no MSAA, 2 means 2x MSAA, etc
// uint m_multiSampleQuality; // no MSAA quality control yet
bool m_enableAutoDepthStencil ; // generally set to 'TRUE' per CShaderDeviceDx8::SetPresentParameters
D3DFORMAT m_autoDepthStencilFormat ;
uint m_fsRefreshHz ; // if full screen, this refresh rate (likely 0 for LCD's)
//uint m_rootRendererID; // only used if m_rendererIndex is -1.
//uint m_rootDisplayMask; // only used if m_rendererIndex is -1.
bool m_mtgl ; // enable multi threaded GL driver
} ;
//===============================================================================
class GLMgr
{
public :
//===========================================================================
// class methods - singleton
static void NewGLMgr ( void ) ; // instantiate singleton..
static GLMgr * aGLMgr ( void ) ; // return singleton..
static void DelGLMgr ( void ) ; // tear down singleton..
//===========================================================================
// plain methods
#if 0 // turned all these off while new approach is coded
void RefreshDisplayDB ( void ) ; // blow away old display DB, make a new one
GLMDisplayDB * GetDisplayDB ( void ) ; // get a ptr to the one GLMgr keeps. only valid til next refresh.
// eligible renderers will be ranked by desirability starting at index 0 within the db
// within each renderer, eligible displays will be ranked some kind of desirability (area? dist from menu bar?)
// within each display, eligible modes will be ranked by descending areas
// calls supplying indices are implicitly making reference to the current DB
bool CaptureDisplay ( int rendIndex , int displayIndex , bool captureAll ) ; // capture one display or all displays
void ReleaseDisplays ( void ) ; // release all captures
int GetDisplayMode ( int rendIndex , int displayIndex ) ; // retrieve current display res (returns modeIndex)
void SetDisplayMode ( GLMDisplayParams * params ) ; // set the display res (only useful for FS)
# endif
GLMContext * NewContext ( IDirect3DDevice9 * pDevice , GLMDisplayParams * params ) ; // this will have to change
void DelContext ( GLMContext * context ) ;
// with usage of CGLMacro.h we could dispense with the "current context" thing
// and just declare a member variable of GLMContext, allowing each glXXX call to be routed directly
// to the correct context
void SetCurrentContext ( GLMContext * context ) ; // make current in calling thread only
GLMContext * GetCurrentContext ( void ) ;
protected :
friend class GLMContext ;
GLMgr ( ) ;
~ GLMgr ( ) ;
} ;
//===========================================================================//
// helper function to do enable or disable in one step
FORCEINLINE void glSetEnable ( GLenum which , bool enable )
{
if ( enable )
gGL - > glEnable ( which ) ;
else
gGL - > glDisable ( which ) ;
}
// helper function for int vs enum clarity
FORCEINLINE void glGetEnumv ( GLenum which , GLenum * dst )
{
gGL - > glGetIntegerv ( which , ( int * ) dst ) ;
}
//===========================================================================//
//
// types to support the GLMContext
//
//===========================================================================//
// Each state set/get path we are providing caching for, needs its own struct and a comparison operator.
// we also provide an enum of how many such types there are, handy for building dirty masks etc.
// shorthand macros
# define EQ(fff) ( (src.fff) == (fff) )
//rasterizer
struct GLAlphaTestEnable_t { GLint enable ; inline bool operator = = ( const GLAlphaTestEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLAlphaTestFunc_t { GLenum func ; GLclampf ref ; inline bool operator = = ( const GLAlphaTestFunc_t & src ) const { return EQ ( func ) & & EQ ( ref ) ; } } ;
struct GLAlphaTest_t { GLint enable ; GLenum func ; GLclampf ref ; } ;
struct GLCullFaceEnable_t { GLint enable ; inline bool operator = = ( const GLCullFaceEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLCullFrontFace_t { GLenum value ; inline bool operator = = ( const GLCullFrontFace_t & src ) const { return EQ ( value ) ; } } ;
struct GLPolygonMode_t { GLenum values [ 2 ] ; inline bool operator = = ( const GLPolygonMode_t & src ) const { return EQ ( values [ 0 ] ) & & EQ ( values [ 1 ] ) ; } } ;
struct GLDepthBias_t { GLfloat factor ; GLfloat units ; inline bool operator = = ( const GLDepthBias_t & src ) const { return EQ ( factor ) & & EQ ( units ) ; } } ;
struct GLScissorEnable_t { GLint enable ; inline bool operator = = ( const GLScissorEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLScissorBox_t { GLint x , y ; GLsizei width , height ; inline bool operator = = ( const GLScissorBox_t & src ) const { return EQ ( x ) & & EQ ( y ) & & EQ ( width ) & & EQ ( height ) ; } } ;
struct GLAlphaToCoverageEnable_t { GLint enable ; inline bool operator = = ( const GLAlphaToCoverageEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLViewportBox_t { GLint x , y ; GLsizei width , height ; uint widthheight ; inline bool operator = = ( const GLViewportBox_t & src ) const { return EQ ( x ) & & EQ ( y ) & & EQ ( width ) & & EQ ( height ) ; } } ;
struct GLViewportDepthRange_t { GLfloat flNear , flFar ; inline bool operator = = ( const GLViewportDepthRange_t & src ) const { return EQ ( flNear ) & & EQ ( flFar ) ; } } ;
struct GLClipPlaneEnable_t { GLint enable ; inline bool operator = = ( const GLClipPlaneEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLClipPlaneEquation_t { GLfloat x , y , z , w ; inline bool operator = = ( const GLClipPlaneEquation_t & src ) const { return EQ ( x ) & & EQ ( y ) & & EQ ( z ) & & EQ ( w ) ; } } ;
//blend
struct GLColorMaskSingle_t { signed char r , g , b , a ; inline bool operator = = ( const GLColorMaskSingle_t & src ) const { return EQ ( r ) & & EQ ( g ) & & EQ ( b ) & & EQ ( a ) ; } } ;
struct GLColorMaskMultiple_t { signed char r , g , b , a ; inline bool operator = = ( const GLColorMaskMultiple_t & src ) const { return EQ ( r ) & & EQ ( g ) & & EQ ( b ) & & EQ ( a ) ; } } ;
struct GLBlendEnable_t { GLint enable ; inline bool operator = = ( const GLBlendEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLBlendFactor_t { GLenum srcfactor , dstfactor ; inline bool operator = = ( const GLBlendFactor_t & src ) const { return EQ ( srcfactor ) & & EQ ( dstfactor ) ; } } ;
struct GLBlendEquation_t { GLenum equation ; inline bool operator = = ( const GLBlendEquation_t & src ) const { return EQ ( equation ) ; } } ;
struct GLBlendColor_t { GLfloat r , g , b , a ; inline bool operator = = ( const GLBlendColor_t & src ) const { return EQ ( r ) & & EQ ( g ) & & EQ ( b ) & & EQ ( a ) ; } } ;
struct GLBlendEnableSRGB_t { GLint enable ; inline bool operator = = ( const GLBlendEnableSRGB_t & src ) const { return EQ ( enable ) ; } } ;
//depth
struct GLDepthTestEnable_t { GLint enable ; inline bool operator = = ( const GLDepthTestEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLDepthFunc_t { GLenum func ; inline bool operator = = ( const GLDepthFunc_t & src ) const { return EQ ( func ) ; } } ;
struct GLDepthMask_t { char mask ; inline bool operator = = ( const GLDepthMask_t & src ) const { return EQ ( mask ) ; } } ;
//stencil
struct GLStencilTestEnable_t { GLint enable ; inline bool operator = = ( const GLStencilTestEnable_t & src ) const { return EQ ( enable ) ; } } ;
struct GLStencilFunc_t { GLenum frontfunc , backfunc ; GLint ref ; GLuint mask ; inline bool operator = = ( const GLStencilFunc_t & src ) const { return EQ ( frontfunc ) & & EQ ( backfunc ) & & EQ ( ref ) & & EQ ( mask ) ; } } ;
struct GLStencilOp_t { GLenum sfail ; GLenum dpfail ; GLenum dppass ; inline bool operator = = ( const GLStencilOp_t & src ) const { return EQ ( sfail ) & & EQ ( dpfail ) & & EQ ( dppass ) ; } } ;
struct GLStencilWriteMask_t { GLint mask ; inline bool operator = = ( const GLStencilWriteMask_t & src ) const { return EQ ( mask ) ; } } ;
//clearing
struct GLClearColor_t { GLfloat r , g , b , a ; inline bool operator = = ( const GLClearColor_t & src ) const { return EQ ( r ) & & EQ ( g ) & & EQ ( b ) & & EQ ( a ) ; } } ;
struct GLClearDepth_t { GLfloat d ; inline bool operator = = ( const GLClearDepth_t & src ) const { return EQ ( d ) ; } } ;
struct GLClearStencil_t { GLint s ; inline bool operator = = ( const GLClearStencil_t & src ) const { return EQ ( s ) ; } } ;
# undef EQ
enum EGLMStateBlockType
{
kGLAlphaTestEnable ,
kGLAlphaTestFunc ,
kGLCullFaceEnable ,
kGLCullFrontFace ,
kGLPolygonMode ,
kGLDepthBias ,
kGLScissorEnable ,
kGLScissorBox ,
kGLViewportBox ,
kGLViewportDepthRange ,
kGLClipPlaneEnable ,
kGLClipPlaneEquation ,
kGLColorMaskSingle ,
kGLColorMaskMultiple ,
kGLBlendEnable ,
kGLBlendFactor ,
kGLBlendEquation ,
kGLBlendColor ,
kGLBlendEnableSRGB ,
kGLDepthTestEnable ,
kGLDepthFunc ,
kGLDepthMask ,
kGLStencilTestEnable ,
kGLStencilFunc ,
kGLStencilOp ,
kGLStencilWriteMask ,
kGLClearColor ,
kGLClearDepth ,
kGLClearStencil ,
kGLAlphaToCoverageEnable ,
kGLMStateBlockLimit
} ;
//===========================================================================//
// templated functions representing GL R/W bottlenecks
// one set of set/get/getdefault is instantiated for each of the GL*** types above.
// use these from the non array state objects
template < typename T > void GLContextSet ( T * src ) ;
template < typename T > void GLContextGet ( T * dst ) ;
template < typename T > void GLContextGetDefault ( T * dst ) ;
// use these from the array state objects
template < typename T > void GLContextSetIndexed ( T * src , int index ) ;
template < typename T > void GLContextGetIndexed ( T * dst , int index ) ;
template < typename T > void GLContextGetDefaultIndexed ( T * dst , int index ) ;
//===============================================================================
// template specializations for each type of state
static GLAlphaTest_t g_alpha_test ;
// --- GLAlphaTestEnable ---
FORCEINLINE void GLContextSet ( GLAlphaTestEnable_t * src )
{
if ( gGL - > m_bHave_GL_QCOM_alpha_test )
glSetEnable ( GL_ALPHA_TEST_QCOM , src - > enable ! = 0 ) ;
else
g_alpha_test . enable = src - > enable ;
}
FORCEINLINE void GLContextGet ( GLAlphaTestEnable_t * dst )
{
if ( gGL - > m_bHave_GL_QCOM_alpha_test )
dst - > enable = gGL - > glIsEnabled ( GL_ALPHA_TEST_QCOM ) ;
else
dst - > enable = g_alpha_test . enable ;
}
FORCEINLINE void GLContextGetDefault ( GLAlphaTestEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLAlphaTestFunc ---
FORCEINLINE void GLContextSet ( GLAlphaTestFunc_t * src )
{
if ( gGL - > m_bHave_GL_QCOM_alpha_test )
gGL - > glAlphaFuncQCOM ( src - > func , src - > ref ) ;
g_alpha_test . func = src - > func ;
g_alpha_test . ref = src - > ref ;
}
FORCEINLINE void GLContextGet ( GLAlphaTestFunc_t * dst )
{
if ( gGL - > m_bHave_GL_QCOM_alpha_test )
{
glGetEnumv ( GL_ALPHA_TEST_FUNC_QCOM , & dst - > func ) ;
gGL - > glGetFloatv ( GL_ALPHA_TEST_REF_QCOM , & dst - > ref ) ;
}
else
{
dst - > func = g_alpha_test . func ;
dst - > ref = g_alpha_test . ref ;
}
}
FORCEINLINE void GLContextGetDefault ( GLAlphaTestFunc_t * dst )
{
dst - > func = GL_ALWAYS ;
dst - > ref = 0.0f ;
}
// --- GLAlphaToCoverageEnable ---
FORCEINLINE void GLContextSet ( GLAlphaToCoverageEnable_t * src )
{
glSetEnable ( GL_SAMPLE_ALPHA_TO_COVERAGE , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLAlphaToCoverageEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_SAMPLE_ALPHA_TO_COVERAGE ) ;
}
FORCEINLINE void GLContextGetDefault ( GLAlphaToCoverageEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLCullFaceEnable ---
FORCEINLINE void GLContextSet ( GLCullFaceEnable_t * src )
{
glSetEnable ( GL_CULL_FACE , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLCullFaceEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_CULL_FACE ) ;
}
FORCEINLINE void GLContextGetDefault ( GLCullFaceEnable_t * dst )
{
dst - > enable = GL_TRUE ;
}
// --- GLCullFrontFace ---
FORCEINLINE void GLContextSet ( GLCullFrontFace_t * src )
{
gGL - > glFrontFace ( src - > value ) ; // legal values are GL_CW or GL_CCW
}
FORCEINLINE void GLContextGet ( GLCullFrontFace_t * dst )
{
glGetEnumv ( GL_FRONT_FACE , & dst - > value ) ;
}
FORCEINLINE void GLContextGetDefault ( GLCullFrontFace_t * dst )
{
dst - > value = GL_CCW ;
}
// --- GLPolygonMode ---
FORCEINLINE void GLContextSet ( GLPolygonMode_t * src )
{
// gGL->glPolygonMode( GL_FRONT, src->values[0] );
// gGL->glPolygonMode( GL_BACK, src->values[1] );
}
FORCEINLINE void GLContextGet ( GLPolygonMode_t * dst )
{
glGetEnumv ( GL_POLYGON_MODE , & dst - > values [ 0 ] ) ;
}
FORCEINLINE void GLContextGetDefault ( GLPolygonMode_t * dst )
{
dst - > values [ 0 ] = dst - > values [ 1 ] = GL_FILL ;
}
// --- GLDepthBias ---
// note the implicit enable / disable.
// if you set non zero values, it is enabled, otherwise not.
FORCEINLINE void GLContextSet ( GLDepthBias_t * src )
{
bool enable = ( src - > factor ! = 0.0f ) | | ( src - > units ! = 0.0f ) ;
glSetEnable ( GL_POLYGON_OFFSET_FILL , enable ) ;
gGL - > glPolygonOffset ( src - > factor , src - > units ) ;
}
FORCEINLINE void GLContextGet ( GLDepthBias_t * dst )
{
gGL - > glGetFloatv ( GL_POLYGON_OFFSET_FACTOR , & dst - > factor ) ;
gGL - > glGetFloatv ( GL_POLYGON_OFFSET_UNITS , & dst - > units ) ;
}
FORCEINLINE void GLContextGetDefault ( GLDepthBias_t * dst )
{
dst - > factor = 0.0 ;
dst - > units = 0.0 ;
}
// --- GLScissorEnable ---
FORCEINLINE void GLContextSet ( GLScissorEnable_t * src )
{
glSetEnable ( GL_SCISSOR_TEST , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLScissorEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_SCISSOR_TEST ) ;
}
FORCEINLINE void GLContextGetDefault ( GLScissorEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLScissorBox ---
FORCEINLINE void GLContextSet ( GLScissorBox_t * src )
{
gGL - > glScissor ( src - > x , src - > y , src - > width , src - > height ) ;
}
FORCEINLINE void GLContextGet ( GLScissorBox_t * dst )
{
gGL - > glGetIntegerv ( GL_SCISSOR_BOX , & dst - > x ) ;
}
FORCEINLINE void GLContextGetDefault ( GLScissorBox_t * dst )
{
// hmmmm, good question? we can't really know a good answer so we pick a silly one
// and the client better come back with a better answer later.
dst - > x = dst - > y = 0 ;
dst - > width = dst - > height = 16 ;
}
// --- GLViewportBox ---
FORCEINLINE void GLContextSet ( GLViewportBox_t * src )
{
Assert ( src - > width = = ( int ) ( src - > widthheight & 0xFFFF ) ) ;
Assert ( src - > height = = ( int ) ( src - > widthheight > > 16 ) ) ;
gGL - > glViewport ( src - > x , src - > y , src - > width , src - > height ) ;
}
FORCEINLINE void GLContextGet ( GLViewportBox_t * dst )
{
gGL - > glGetIntegerv ( GL_VIEWPORT , & dst - > x ) ;
dst - > widthheight = dst - > width | ( dst - > height < < 16 ) ;
}
FORCEINLINE void GLContextGetDefault ( GLViewportBox_t * dst )
{
// as with the scissor box, we don't know yet, so pick a silly one and change it later
dst - > x = dst - > y = 0 ;
dst - > width = dst - > height = 16 ;
dst - > widthheight = dst - > width | ( dst - > height < < 16 ) ;
}
// --- GLViewportDepthRange ---
FORCEINLINE void GLContextSet ( GLViewportDepthRange_t * src )
{
gGL - > glDepthRangef ( src - > flNear , src - > flFar ) ;
}
FORCEINLINE void GLContextGet ( GLViewportDepthRange_t * dst )
{
gGL - > glGetFloatv ( GL_DEPTH_RANGE , & dst - > flNear ) ;
}
FORCEINLINE void GLContextGetDefault ( GLViewportDepthRange_t * dst )
{
dst - > flNear = 0.0 ;
dst - > flFar = 1.0 ;
}
// --- GLClipPlaneEnable ---
FORCEINLINE void GLContextSetIndexed ( GLClipPlaneEnable_t * src , int index )
{
# if GLMDEBUG
if ( CommandLine ( ) - > FindParm ( " -caps_noclipplanes " ) )
{
if ( GLMKnob ( " caps-key " , NULL ) > 0.0 )
{
// caps ON means NO clipping
src - > enable = false ;
}
}
# endif
glSetEnable ( GL_CLIP_PLANE0 + index , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGetIndexed ( GLClipPlaneEnable_t * dst , int index )
{
dst - > enable = gGL - > glIsEnabled ( GL_CLIP_PLANE0 + index ) ;
}
FORCEINLINE void GLContextGetDefaultIndexed ( GLClipPlaneEnable_t * dst , int index )
{
dst - > enable = 0 ;
}
// --- GLClipPlaneEquation ---
FORCEINLINE void GLContextSetIndexed ( GLClipPlaneEquation_t * src , int index )
{
// shove into glGlipPlane
// GLdouble coeffs[4] = { src->x, src->y, src->z, src->w };
// gGL->glClipPlane( GL_CLIP_PLANE0 + index, coeffs );
}
FORCEINLINE void GLContextGetIndexed ( GLClipPlaneEquation_t * dst , int index )
{
DebuggerBreak ( ) ; // do this later
// glClipPlane( GL_CLIP_PLANE0 + index, coeffs );
// GLdouble coeffs[4] = { src->x, src->y, src->z, src->w };
}
FORCEINLINE void GLContextGetDefaultIndexed ( GLClipPlaneEquation_t * dst , int index )
{
dst - > x = 1.0 ;
dst - > y = 0.0 ;
dst - > z = 0.0 ;
dst - > w = 0.0 ;
}
// --- GLColorMaskSingle ---
FORCEINLINE void GLContextSet ( GLColorMaskSingle_t * src )
{
gGL - > glColorMask ( src - > r , src - > g , src - > b , src - > a ) ;
}
FORCEINLINE void GLContextGet ( GLColorMaskSingle_t * dst )
{
gGL - > glGetBooleanv ( GL_COLOR_WRITEMASK , ( GLboolean * ) & dst - > r ) ;
}
FORCEINLINE void GLContextGetDefault ( GLColorMaskSingle_t * dst )
{
dst - > r = dst - > g = dst - > b = dst - > a = 1 ;
}
// --- GLColorMaskMultiple ---
FORCEINLINE void GLContextSetIndexed ( GLColorMaskMultiple_t * src , int index )
{
GLint Rfbo = 0 , Dfbo = 0 ;
gGL - > glGetIntegerv ( GL_DRAW_FRAMEBUFFER_BINDING , & Dfbo ) ;
gGL - > glGetIntegerv ( GL_READ_FRAMEBUFFER_BINDING , & Rfbo ) ;
GLint target = Dfbo = = Rfbo ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER ;
gGL - > glBindFramebuffer ( target , index ) ;
gGL - > glColorMask ( src - > r , src - > g , src - > b , src - > a ) ;
gGL - > glBindFramebuffer ( target , Dfbo ) ;
}
FORCEINLINE void GLContextGetIndexed ( GLColorMaskMultiple_t * dst , int index )
{
GLint Rfbo = 0 , Dfbo = 0 ;
gGL - > glGetIntegerv ( GL_DRAW_FRAMEBUFFER_BINDING , & Dfbo ) ;
gGL - > glGetIntegerv ( GL_READ_FRAMEBUFFER_BINDING , & Rfbo ) ;
GLint target = Dfbo = = Rfbo ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER ;
gGL - > glBindFramebuffer ( target , index ) ;
gGL - > glGetBooleanv ( GL_COLOR_WRITEMASK , ( GLboolean * ) & dst - > r ) ;
gGL - > glBindFramebuffer ( target , Dfbo ) ;
}
FORCEINLINE void GLContextGetDefaultIndexed ( GLColorMaskMultiple_t * dst , int index )
{
dst - > r = dst - > g = dst - > b = dst - > a = 1 ;
}
// --- GLBlendEnable ---
FORCEINLINE void GLContextSet ( GLBlendEnable_t * src )
{
glSetEnable ( GL_BLEND , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLBlendEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_BLEND ) ;
}
FORCEINLINE void GLContextGetDefault ( GLBlendEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLBlendFactor ---
FORCEINLINE void GLContextSet ( GLBlendFactor_t * src )
{
gGL - > glBlendFunc ( src - > srcfactor , src - > dstfactor ) ;
}
FORCEINLINE void GLContextGet ( GLBlendFactor_t * dst )
{
glGetEnumv ( GL_BLEND_SRC , & dst - > srcfactor ) ;
glGetEnumv ( GL_BLEND_DST , & dst - > dstfactor ) ;
}
FORCEINLINE void GLContextGetDefault ( GLBlendFactor_t * dst )
{
dst - > srcfactor = GL_ONE ;
dst - > dstfactor = GL_ZERO ;
}
// --- GLBlendEquation ---
FORCEINLINE void GLContextSet ( GLBlendEquation_t * src )
{
gGL - > glBlendEquation ( src - > equation ) ;
}
FORCEINLINE void GLContextGet ( GLBlendEquation_t * dst )
{
glGetEnumv ( GL_BLEND_EQUATION , & dst - > equation ) ;
}
FORCEINLINE void GLContextGetDefault ( GLBlendEquation_t * dst )
{
dst - > equation = GL_FUNC_ADD ;
}
// --- GLBlendColor ---
FORCEINLINE void GLContextSet ( GLBlendColor_t * src )
{
gGL - > glBlendColor ( src - > r , src - > g , src - > b , src - > a ) ;
}
FORCEINLINE void GLContextGet ( GLBlendColor_t * dst )
{
gGL - > glGetFloatv ( GL_BLEND_COLOR , & dst - > r ) ;
}
FORCEINLINE void GLContextGetDefault ( GLBlendColor_t * dst )
{
//solid white
dst - > r = dst - > g = dst - > b = dst - > a = 1.0 ;
}
// --- GLBlendEnableSRGB ---
# define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
# define GL_COLOR_ATTACHMENT0 0x8CE0
FORCEINLINE void GLContextSet ( GLBlendEnableSRGB_t * src )
{
# if GLMDEBUG
// just check in debug... this is too expensive to look at on MTGL
if ( src - > enable )
{
GLboolean srgb_capable = false ;
gGL - > glGetBooleanv ( GL_FRAMEBUFFER_SRGB_CAPABLE_EXT , & srgb_capable ) ;
if ( src - > enable & & ! srgb_capable )
{
GLMPRINTF ( ( " -Z- srgb-state-set FBO conflict: attempt to enable SRGB on non SRGB capable FBO config " ) ) ;
}
}
# endif
// this query is not useful unless you have the ARB_framebuffer_srgb ext.
// GLint encoding = 0;
// gGL->glGetFramebufferAttachmentParameteriv( GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding );
glSetEnable ( GL_FRAMEBUFFER_SRGB_EXT , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLBlendEnableSRGB_t * dst )
{
// dst->enable = gGL->glIsEnabled( GL_FRAMEBUFFER_SRGB_EXT );
dst - > enable = true ; // wtf ?
}
FORCEINLINE void GLContextGetDefault ( GLBlendEnableSRGB_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLDepthTestEnable ---
FORCEINLINE void GLContextSet ( GLDepthTestEnable_t * src )
{
glSetEnable ( GL_DEPTH_TEST , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLDepthTestEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_DEPTH_TEST ) ;
}
FORCEINLINE void GLContextGetDefault ( GLDepthTestEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLDepthFunc ---
FORCEINLINE void GLContextSet ( GLDepthFunc_t * src )
{
gGL - > glDepthFunc ( src - > func ) ;
}
FORCEINLINE void GLContextGet ( GLDepthFunc_t * dst )
{
glGetEnumv ( GL_DEPTH_FUNC , & dst - > func ) ;
}
FORCEINLINE void GLContextGetDefault ( GLDepthFunc_t * dst )
{
dst - > func = GL_GEQUAL ;
}
// --- GLDepthMask ---
FORCEINLINE void GLContextSet ( GLDepthMask_t * src )
{
gGL - > glDepthMask ( src - > mask ) ;
}
FORCEINLINE void GLContextGet ( GLDepthMask_t * dst )
{
gGL - > glGetBooleanv ( GL_DEPTH_WRITEMASK , ( GLboolean * ) & dst - > mask ) ;
}
FORCEINLINE void GLContextGetDefault ( GLDepthMask_t * dst )
{
dst - > mask = GL_TRUE ;
}
// --- GLStencilTestEnable ---
FORCEINLINE void GLContextSet ( GLStencilTestEnable_t * src )
{
glSetEnable ( GL_STENCIL_TEST , src - > enable ! = 0 ) ;
}
FORCEINLINE void GLContextGet ( GLStencilTestEnable_t * dst )
{
dst - > enable = gGL - > glIsEnabled ( GL_STENCIL_TEST ) ;
}
FORCEINLINE void GLContextGetDefault ( GLStencilTestEnable_t * dst )
{
dst - > enable = GL_FALSE ;
}
// --- GLStencilFunc ---
FORCEINLINE void GLContextSet ( GLStencilFunc_t * src )
{
if ( src - > frontfunc = = src - > backfunc )
gGL - > glStencilFuncSeparate ( GL_FRONT_AND_BACK , src - > frontfunc , src - > ref , src - > mask ) ;
else
{
gGL - > glStencilFuncSeparate ( GL_FRONT , src - > frontfunc , src - > ref , src - > mask ) ;
gGL - > glStencilFuncSeparate ( GL_BACK , src - > backfunc , src - > ref , src - > mask ) ;
}
}
FORCEINLINE void GLContextGet ( GLStencilFunc_t * dst )
{
glGetEnumv ( GL_STENCIL_FUNC , & dst - > frontfunc ) ;
glGetEnumv ( GL_STENCIL_BACK_FUNC , & dst - > backfunc ) ;
gGL - > glGetIntegerv ( GL_STENCIL_REF , & dst - > ref ) ;
gGL - > glGetIntegerv ( GL_STENCIL_VALUE_MASK , ( GLint * ) & dst - > mask ) ;
}
FORCEINLINE void GLContextGetDefault ( GLStencilFunc_t * dst )
{
dst - > frontfunc = GL_ALWAYS ;
dst - > backfunc = GL_ALWAYS ;
dst - > ref = 0 ;
dst - > mask = 0xFFFFFFFF ;
}
// --- GLStencilOp --- indexed 0=front, 1=back
FORCEINLINE void GLContextSetIndexed ( GLStencilOp_t * src , int index )
{
GLenum face = ( index = = 0 ) ? GL_FRONT : GL_BACK ;
gGL - > glStencilOpSeparate ( face , src - > sfail , src - > dpfail , src - > dppass ) ;
}
FORCEINLINE void GLContextGetIndexed ( GLStencilOp_t * dst , int index )
{
glGetEnumv ( ( index = = 0 ) ? GL_STENCIL_FAIL : GL_STENCIL_BACK_FAIL , & dst - > sfail ) ;
glGetEnumv ( ( index = = 0 ) ? GL_STENCIL_PASS_DEPTH_FAIL : GL_STENCIL_BACK_PASS_DEPTH_FAIL , & dst - > dpfail ) ;
glGetEnumv ( ( index = = 0 ) ? GL_STENCIL_PASS_DEPTH_PASS : GL_STENCIL_BACK_PASS_DEPTH_PASS , & dst - > dppass ) ;
}
FORCEINLINE void GLContextGetDefaultIndexed ( GLStencilOp_t * dst , int index )
{
dst - > sfail = dst - > dpfail = dst - > dppass = GL_KEEP ;
}
// --- GLStencilWriteMask ---
FORCEINLINE void GLContextSet ( GLStencilWriteMask_t * src )
{
gGL - > glStencilMask ( src - > mask ) ;
}
FORCEINLINE void GLContextGet ( GLStencilWriteMask_t * dst )
{
gGL - > glGetIntegerv ( GL_STENCIL_WRITEMASK , & dst - > mask ) ;
}
FORCEINLINE void GLContextGetDefault ( GLStencilWriteMask_t * dst )
{
dst - > mask = 0xFFFFFFFF ;
}
// --- GLClearColor ---
FORCEINLINE void GLContextSet ( GLClearColor_t * src )
{
gGL - > glClearColor ( src - > r , src - > g , src - > b , src - > a ) ;
}
FORCEINLINE void GLContextGet ( GLClearColor_t * dst )
{
gGL - > glGetFloatv ( GL_COLOR_CLEAR_VALUE , & dst - > r ) ;
}
FORCEINLINE void GLContextGetDefault ( GLClearColor_t * dst )
{
dst - > r = dst - > g = dst - > b = 0.5 ;
dst - > a = 1.0 ;
}
// --- GLClearDepth ---
FORCEINLINE void GLContextSet ( GLClearDepth_t * src )
{
gGL - > glClearDepthf ( src - > d ) ;
}
FORCEINLINE void GLContextGet ( GLClearDepth_t * dst )
{
gGL - > glGetFloatv ( GL_DEPTH_CLEAR_VALUE , & dst - > d ) ;
}
FORCEINLINE void GLContextGetDefault ( GLClearDepth_t * dst )
{
dst - > d = 1.0 ;
}
// --- GLClearStencil ---
FORCEINLINE void GLContextSet ( GLClearStencil_t * src )
{
gGL - > glClearStencil ( src - > s ) ;
}
FORCEINLINE void GLContextGet ( GLClearStencil_t * dst )
{
gGL - > glGetIntegerv ( GL_STENCIL_CLEAR_VALUE , & dst - > s ) ;
}
FORCEINLINE void GLContextGetDefault ( GLClearStencil_t * dst )
{
dst - > s = 0 ;
}
//===========================================================================//
// caching state object template. One of these is instantiated in the context per unique struct type above
template < typename T > class GLState
{
public :
inline GLState ( )
{
memset ( & data , 0 , sizeof ( data ) ) ;
Default ( ) ;
}
FORCEINLINE void Flush ( )
{
// immediately blast out the state - it makes no sense to delta it or do anything fancy because shaderapi, dxabstract, and OpenGL itself does this for us (and OpenGL calls with multithreaded drivers are very cheap)
GLContextSet ( & data ) ;
}
// write: client src into cache
// common case is both false. dirty is calculated, context write is deferred.
FORCEINLINE void Write ( const T * src )
{
data = * src ;
Flush ( ) ;
}
// default: write default value to cache, optionally write through
inline void Default ( bool noDefer = false )
{
GLContextGetDefault ( & data ) ; // read default values directly to our cache copy
Flush ( ) ;
}
// read: sel = 0 for cache, 1 for context
inline void Read ( T * dst , int sel )
{
if ( sel = = 0 )
* dst = data ;
else
GLContextGet ( dst ) ;
}
// check: verify that context equals cache, return true if mismatched or if illegal values seen
inline bool Check ( void )
{
T temp ;
bool result ;
GLContextGet ( & temp ) ;
result = ! ( temp = = data ) ;
return result ;
}
FORCEINLINE const T & GetData ( ) const { return data ; }
protected :
T data ;
} ;
// caching state object template - with multiple values behind it that are indexed
template < typename T , int COUNT > class GLStateArray
{
public :
inline GLStateArray ( )
{
memset ( & data , 0 , sizeof ( data ) ) ;
Default ( ) ;
}
// write cache->context if dirty or forced.
FORCEINLINE void FlushIndex ( int index )
{
// immediately blast out the state - it makes no sense to delta it or do anything fancy because shaderapi, dxabstract, and OpenGL itself does this for us (and OpenGL calls with multithreaded drivers are very cheap)
GLContextSetIndexed ( & data [ index ] , index ) ;
} ;
// write: client src into cache
// common case is both false. dirty is calculated, context write is deferred.
FORCEINLINE void WriteIndex ( T * src , int index )
{
data [ index ] = * src ;
FlushIndex ( index ) ; // dirty becomes false
} ;
// write all slots in the array
FORCEINLINE void Flush ( )
{
for ( int i = 0 ; i < COUNT ; i + + )
{
FlushIndex ( i ) ;
}
}
// default: write default value to cache, optionally write through
inline void DefaultIndex ( int index )
{
GLContextGetDefaultIndexed ( & data [ index ] , index ) ; // read default values directly to our cache copy
Flush ( ) ;
} ;
inline void Default ( void )
{
for ( int i = 0 ; i < COUNT ; i + + )
{
DefaultIndex ( i ) ;
}
}
// read: sel = 0 for cache, 1 for context
inline void ReadIndex ( T * dst , int index , int sel )
{
if ( sel = = 0 )
* dst = data [ index ] ;
else
GLContextGetIndexed ( dst , index ) ;
} ;
// check: verify that context equals cache, return true if mismatched or if illegal values seen
inline bool CheckIndex ( int index )
{
T temp ;
bool result ;
GLContextGetIndexed ( & temp , index ) ;
result = ! ( temp = = data [ index ] ) ;
return result ;
} ;
inline bool Check ( void )
{
//T temp;
bool result = false ;
for ( int i = 0 ; i < COUNT ; i + + )
{
result | = CheckIndex ( i ) ;
}
return result ;
} ;
protected :
T data [ COUNT ] ;
} ;
//===========================================================================//
struct GLMTexSampler
{
CGLMTex * m_pBoundTex ; // tex which is actually bound now
GLMTexSamplingParams m_samp ; // current 2D sampler state
} ;
// GLMContext will maintain one of these structures inside the context to represent the current state.
// Client can supply a new one when it wants to change the setup.
//FIXME GLMContext can do the work to migrate from old setup to new setup as efficiently as possible (but it doesn't yet)
struct GLMVertexSetup
{
uint m_attrMask ; // which attrs are enabled (1<<n) mask where n is a GLMVertexAttributeIndex.
GLMVertexAttributeDesc m_attrs [ kGLMVertexAttributeIndexMax ] ;
// copied in from dxabstract, not strictly needed for operation, helps debugging
unsigned char m_vtxAttribMap [ 16 ] ;
/* high nibble is usage per _D3DDECLUSAGE
typedef enum _D3DDECLUSAGE
{
D3DDECLUSAGE_POSITION = 0 ,
D3DDECLUSAGE_BLENDWEIGHT = 1 ,
D3DDECLUSAGE_BLENDINDICES = 2 ,
D3DDECLUSAGE_NORMAL = 3 ,
D3DDECLUSAGE_PSIZE = 4 ,
D3DDECLUSAGE_TEXCOORD = 5 ,
D3DDECLUSAGE_TANGENT = 6 ,
D3DDECLUSAGE_BINORMAL = 7 ,
D3DDECLUSAGE_TESSFACTOR = 8 ,
D3DDECLUSAGE_PLUGH = 9 , // mystery value
D3DDECLUSAGE_COLOR = 10 ,
D3DDECLUSAGE_FOG = 11 ,
D3DDECLUSAGE_DEPTH = 12 ,
D3DDECLUSAGE_SAMPLE = 13 ,
} D3DDECLUSAGE ;
low nibble is usageindex ( i . e . POSITION0 , POSITION1 , etc )
array position is attrib number .
*/
} ;
//===========================================================================//
//FIXME magic numbers here
# define kGLMProgramParamFloat4Limit 256
# define kGLMProgramParamBoolLimit 16
# define kGLMProgramParamInt4Limit 16
# define kGLMVertexProgramParamFloat4Limit 256
# define kGLMFragmentProgramParamFloat4Limit 256
struct GLMProgramParamsF
{
float m_values [ kGLMProgramParamFloat4Limit ] [ 4 ] ; // float4's 256 of them
int m_firstDirtySlotNonBone ;
int m_dirtySlotHighWaterNonBone ; // index of slot past highest dirty non-bone register (assume 0 for base of range)
int m_dirtySlotHighWaterBone ; // index of slot past highest dirty bone register (0=first bone reg, which is DXABSTRACT_VS_FIRST_BONE_SLOT)
} ;
struct GLMProgramParamsB
{
int m_values [ kGLMProgramParamBoolLimit ] ; // bools, 4 of them
uint m_dirtySlotCount ;
} ;
struct GLMProgramParamsI
{
int m_values [ kGLMProgramParamInt4Limit ] [ 4 ] ; // int4s, 16 of them
uint m_dirtySlotCount ;
} ;
enum EGLMParamWriteMode
{
eParamWriteAllSlots , // glUniform4fv of the maximum size (not recommended if shader is down-sizing the decl)
eParamWriteShaderSlots , // glUniform4fv of the active slot count ("highwater")
eParamWriteShaderSlotsOptional , // glUniform4fv of the active slot count ("highwater") - but only if at least one has been written - it's optional
eParamWriteDirtySlotRange // glUniform4fv of the 0-N range where N is highest dirty slot
} ;
enum EGLMAttribWriteMode
{
eAttribWriteAll ,
eAttribWriteDirty
} ;
//===========================================================================//
# if GLMDEBUG
enum EGLMDebugCallSite
{
eBeginFrame , // inside begin frame func - frame number has been inc'd, batch number should be -1
eClear , // inside clear func
eDrawElements , // inside repeat loop, prior to draw call - batch numberhas been inc'd
eEndFrame , // end frame
ePresent // before showing pixels
} ;
// caller should zero one of these out and fill in the m_caller before invoking the hook
struct GLMDebugHookInfo
{
// info from the caller to the debug hook
EGLMDebugCallSite m_caller ;
// state the hook uses to keep track of progress within a single run of the caller
int m_iteration ; // which call to the hook is this. if it's zero, it precedes any action in the caller.
// bools used to communicate between caller and hook
bool m_loop ; // hook tells caller to loop around again (don't exit)
bool m_holding ; // current mood of hook, are we holding on this batch (i.e. rerun)
// specific info for a draw call
GLenum m_drawMode ;
GLuint m_drawStart ;
GLuint m_drawEnd ;
GLsizei m_drawCount ;
GLenum m_drawType ;
const GLvoid * m_drawIndices ;
} ;
# endif
//===========================================================================//
class CFlushDrawStatesStats
{
public :
CFlushDrawStatesStats ( )
{
Clear ( ) ;
}
void Clear ( )
{
memset ( this , 0 , sizeof ( * this ) ) ;
}
uint m_nTotalBatchFlushes ;
uint m_nTotalProgramPairChanges ;
uint m_nNumChangedSamplers ;
uint m_nNumSamplingParamsChanged ;
uint m_nIndexBufferChanged ;
uint m_nVertexBufferChanged ;
uint m_nFirstVSConstant ;
uint m_nNumVSConstants ;
uint m_nNumVSBoneConstants ;
uint m_nFirstPSConstant ;
uint m_nNumPSConstants ;
uint m_nNewPS ;
uint m_nNewVS ;
} ;
//===========================================================================//
class GLMContext
{
public :
// set/check current context (perq for many other calls)
void MakeCurrent ( bool bRenderThread = false ) ;
void ReleaseCurrent ( bool bRenderThread = false ) ;
// CheckCurrent has been removed (it no longer compiled on Linux). To minimize churn I'm leaving
// the inline NOP version.
// DO NOT change this to non-inlined. It's called all over the place from very hot codepaths.
FORCEINLINE void CheckCurrent ( void ) { }
void PopulateCaps ( void ) ; // fill out later portions of renderer info record which need context queries
void DumpCaps ( void ) ; // printf all the caps info (you can call this in release too)
const GLMRendererInfoFields & Caps ( void ) ; // peek at the caps record
// state cache/mirror
void SetDefaultStates ( void ) ;
void ForceFlushStates ( ) ;
void VerifyStates ( void ) ;
// textures
// Lock and Unlock reqs go directly to the tex object
CGLMTex * NewTex ( GLMTexLayoutKey * key , uint levels = 1 , const char * debugLabel = NULL ) ;
void DelTex ( CGLMTex * tex ) ;
// options for Blit (replacement for ResolveTex and BlitTex)
// pass NULL for dstTex if you want to target GL_BACK with the blit. You get y-flip with that, don't change the dstrect yourself.
void Blit2 ( CGLMTex * srcTex , GLMRect * srcRect , int srcFace , int srcMip , CGLMTex * dstTex , GLMRect * dstRect , int dstFace , int dstMip , uint filter ) ;
// tex blit (via FBO blit)
void BlitTex ( CGLMTex * srcTex , GLMRect * srcRect , int srcFace , int srcMip , CGLMTex * dstTex , GLMRect * dstRect , int dstFace , int dstMip , uint filter , bool useBlitFB = true ) ;
// MSAA resolve - we do this in GLMContext because it has to do a bunch of FBO/blit gymnastics
void ResolveTex ( CGLMTex * tex , bool forceDirty = false ) ;
// texture pre-load (residency forcing) - normally done one-time but you can force it
void PreloadTex ( CGLMTex * tex , bool force = false ) ;
// samplers
FORCEINLINE void SetSamplerTex ( int sampler , CGLMTex * tex ) ;
FORCEINLINE void SetSamplerDirty ( int sampler ) ;
FORCEINLINE void SetSamplerMinFilter ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerMagFilter ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerMipFilter ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerAddressU ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerAddressV ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerAddressW ( int sampler , GLenum Value ) ;
FORCEINLINE void SetSamplerStates ( int sampler , GLenum AddressU , GLenum AddressV , GLenum AddressW , GLenum minFilter , GLenum magFilter , GLenum mipFilter , int minLod , float lodBias ) ;
FORCEINLINE void SetSamplerBorderColor ( int sampler , DWORD Value ) ;
FORCEINLINE void SetSamplerMipMapLODBias ( int sampler , DWORD Value ) ;
FORCEINLINE void SetSamplerMaxMipLevel ( int sampler , DWORD Value ) ;
FORCEINLINE void SetSamplerMaxAnisotropy ( int sampler , DWORD Value ) ;
FORCEINLINE void SetSamplerSRGBTexture ( int sampler , DWORD Value ) ;
FORCEINLINE void SetShadowFilter ( int sampler , DWORD Value ) ;
// render targets (FBO's)
CGLMFBO * NewFBO ( void ) ;
void DelFBO ( CGLMFBO * fbo ) ;
// programs
CGLMProgram * NewProgram ( EGLMProgramType type , char * progString , const char * pShaderName ) ;
void DelProgram ( CGLMProgram * pProg ) ;
void NullProgram ( void ) ; // de-ac all shader state
FORCEINLINE void SetVertexProgram ( CGLMProgram * pProg ) ;
FORCEINLINE void SetFragmentProgram ( CGLMProgram * pProg ) ;
FORCEINLINE void SetProgram ( EGLMProgramType nProgType , CGLMProgram * pProg ) { m_drawingProgram [ nProgType ] = pProg ; m_bDirtyPrograms = true ; }
void SetDrawingLang ( EGLMProgramLang lang , bool immediate = false ) ; // choose ARB or GLSL. immediate=false defers lang change to top of frame
void LinkShaderPair ( CGLMProgram * vp , CGLMProgram * fp ) ; // ensure this combo has been linked and is in the GLSL pair cache
void ValidateShaderPair ( CGLMProgram * vp , CGLMProgram * fp ) ;
void ClearShaderPairCache ( void ) ; // call this to shoot down all the linked pairs
void QueryShaderPair ( int index , GLMShaderPairInfo * infoOut ) ; // this lets you query the shader pair cache for saving its state
// buffers
// Lock and Unlock reqs go directly to the buffer object
CGLMBuffer * NewBuffer ( EGLMBufferType type , uint size , uint options ) ;
void DelBuffer ( CGLMBuffer * buff ) ;
FORCEINLINE void SetIndexBuffer ( CGLMBuffer * buff ) { BindIndexBufferToCtx ( buff ) ; }
// FIXME: Remove this, it's no longer used
FORCEINLINE void SetVertexAttributes ( GLMVertexSetup * setup )
{
// we now just latch the vert setup and then execute on it at flushdrawstatestime if shaders are enabled.
if ( setup )
{
m_drawVertexSetup = * setup ;
}
else
{
memset ( & m_drawVertexSetup , 0 , sizeof ( m_drawVertexSetup ) ) ;
}
}
// note, no API is exposed for setting a single attribute source.
// come prepared with a complete block of attributes to use.
// Queries
CGLMQuery * NewQuery ( GLMQueryParams * params ) ;
void DelQuery ( CGLMQuery * query ) ;
// "slot" means a vec4-sized thing
// these write into .env parameter space
FORCEINLINE void SetProgramParametersF ( EGLMProgramType type , uint baseSlot , float * slotData , uint slotCount ) ;
FORCEINLINE void SetProgramParametersB ( EGLMProgramType type , uint baseSlot , int * slotData , uint boolCount ) ; // take "BOOL" aka int
FORCEINLINE void SetProgramParametersI ( EGLMProgramType type , uint baseSlot , int * slotData , uint slotCount ) ; // take int4s
// state sync
// If lazyUnbinding is true, unbound samplers will not actually be unbound to the GL device.
FORCEINLINE void FlushDrawStates ( uint nStartIndex , uint nEndIndex , uint nBaseVertex ) ; // pushes all drawing state - samplers, tex, programs, etc.
void FlushDrawStatesNoShaders ( ) ;
// drawing
# if 1 //ifndef OSX
FORCEINLINE void DrawRangeElements ( GLenum mode , GLuint start , GLuint end , GLsizei count , GLenum type , const GLvoid * indices , uint baseVertex , CGLMBuffer * pIndexBuf ) ;
void DrawRangeElementsNonInline ( GLenum mode , GLuint start , GLuint end , GLsizei count , GLenum type , const GLvoid * indices , uint baseVertex , CGLMBuffer * pIndexBuf ) ;
# else
void DrawRangeElements ( GLenum mode , GLuint start , GLuint end , GLsizei count , GLenum type , const GLvoid * indices , CGLMBuffer * pIndexBuf ) ;
# endif
void CheckNative ( void ) ;
// clearing
void Clear ( bool color , unsigned long colorValue , bool depth , float depthValue , bool stencil , unsigned int stencilValue , GLScissorBox_t * rect = NULL ) ;
// display
//void SetVSyncEnable( bool vsyncOn );
//void SetFullScreen( bool fsOn, int screenIndex ); // will be latched for next BeginFrame
//void ActivateFullScreen( bool fsOn, int screenIndex ); // will be called by BeginFrame
bool SetDisplayParams ( GLMDisplayParams * params ) ; // either the first time setup, or a change to new setup
void Present ( CGLMTex * tex ) ; // somewhat hardwired for the time being
// Called when IDirect3DDevice9::Reset() is called.
void Reset ( ) ;
// writers for the state block inputs
FORCEINLINE void WriteAlphaTestEnable ( GLAlphaTestEnable_t * src ) { m_AlphaTestEnable . Write ( src ) ; }
FORCEINLINE void WriteAlphaTestFunc ( GLAlphaTestFunc_t * src ) { m_AlphaTestFunc . Write ( src ) ; }
FORCEINLINE void WriteAlphaToCoverageEnable ( GLAlphaToCoverageEnable_t * src ) { m_AlphaToCoverageEnable . Write ( src ) ; }
FORCEINLINE void WriteCullFaceEnable ( GLCullFaceEnable_t * src ) { m_CullFaceEnable . Write ( src ) ; }
FORCEINLINE void WriteCullFrontFace ( GLCullFrontFace_t * src ) { m_CullFrontFace . Write ( src ) ; }
FORCEINLINE void WritePolygonMode ( GLPolygonMode_t * src ) { m_PolygonMode . Write ( src ) ; }
FORCEINLINE void WriteDepthBias ( GLDepthBias_t * src ) { m_DepthBias . Write ( src ) ; }
FORCEINLINE void WriteClipPlaneEnable ( GLClipPlaneEnable_t * src , int which ) { m_ClipPlaneEnable . WriteIndex ( src , which ) ; }
FORCEINLINE void WriteClipPlaneEquation ( GLClipPlaneEquation_t * src , int which ) { m_ClipPlaneEquation . WriteIndex ( src , which ) ; }
FORCEINLINE void WriteScissorEnable ( GLScissorEnable_t * src ) { m_ScissorEnable . Write ( src ) ; }
FORCEINLINE void WriteScissorBox ( GLScissorBox_t * src ) { m_ScissorBox . Write ( src ) ; }
FORCEINLINE void WriteViewportBox ( GLViewportBox_t * src ) { m_ViewportBox . Write ( src ) ; }
FORCEINLINE void WriteViewportDepthRange ( GLViewportDepthRange_t * src ) { m_ViewportDepthRange . Write ( src ) ; }
FORCEINLINE void WriteColorMaskSingle ( GLColorMaskSingle_t * src ) { m_ColorMaskSingle . Write ( src ) ; }
FORCEINLINE void WriteColorMaskMultiple ( GLColorMaskMultiple_t * src , int which ) { m_ColorMaskMultiple . WriteIndex ( src , which ) ; }
FORCEINLINE void WriteBlendEnable ( GLBlendEnable_t * src ) { m_BlendEnable . Write ( src ) ; }
FORCEINLINE void WriteBlendFactor ( GLBlendFactor_t * src ) { m_BlendFactor . Write ( src ) ; }
FORCEINLINE void WriteBlendEquation ( GLBlendEquation_t * src ) { m_BlendEquation . Write ( src ) ; }
FORCEINLINE void WriteBlendColor ( GLBlendColor_t * src ) { m_BlendColor . Write ( src ) ; }
FORCEINLINE void WriteBlendEnableSRGB ( GLBlendEnableSRGB_t * src )
{
if ( m_caps . m_hasGammaWrites ) // only if caps allow do we actually push it through to the extension
{
m_BlendEnableSRGB . Write ( src ) ;
}
else
{
m_FakeBlendEnableSRGB = src - > enable ! = 0 ;
}
// note however that we're still tracking what this mode should be, so FlushDrawStates can look at it and adjust the pixel shader
// if fake SRGB mode is in place (m_caps.m_hasGammaWrites is false)
}
FORCEINLINE void WriteDepthTestEnable ( GLDepthTestEnable_t * src ) { m_DepthTestEnable . Write ( src ) ; }
FORCEINLINE void WriteDepthFunc ( GLDepthFunc_t * src ) { m_DepthFunc . Write ( src ) ; }
FORCEINLINE void WriteDepthMask ( GLDepthMask_t * src ) { m_DepthMask . Write ( src ) ; }
FORCEINLINE void WriteStencilTestEnable ( GLStencilTestEnable_t * src ) { m_StencilTestEnable . Write ( src ) ; }
FORCEINLINE void WriteStencilFunc ( GLStencilFunc_t * src ) { m_StencilFunc . Write ( src ) ; }
FORCEINLINE void WriteStencilOp ( GLStencilOp_t * src , int which ) { m_StencilOp . WriteIndex ( src , which ) ; }
FORCEINLINE void WriteStencilWriteMask ( GLStencilWriteMask_t * src ) { m_StencilWriteMask . Write ( src ) ; }
FORCEINLINE void WriteClearColor ( GLClearColor_t * src ) { m_ClearColor . Write ( src ) ; }
FORCEINLINE void WriteClearDepth ( GLClearDepth_t * src ) { m_ClearDepth . Write ( src ) ; }
FORCEINLINE void WriteClearStencil ( GLClearStencil_t * src ) { m_ClearStencil . Write ( src ) ; }
// debug stuff
void BeginFrame ( void ) ;
void EndFrame ( void ) ;
// new interactive debug stuff
# if GLMDEBUG
void DebugDump ( GLMDebugHookInfo * info , uint options , uint vertDumpMode ) ;
void DebugHook ( GLMDebugHookInfo * info ) ;
void DebugPresent ( void ) ;
void DebugClear ( void ) ;
# endif
FORCEINLINE void SetMaxUsedVertexShaderConstantsHint ( uint nMaxConstants ) ;
FORCEINLINE uintp GetCurrentOwnerThreadId ( ) const { return m_nCurOwnerThreadId ; }
protected :
friend class GLMgr ; // only GLMgr can make GLMContext objects
friend class GLMRendererInfo ; // only GLMgr can make GLMContext objects
friend class CGLMTex ; // tex needs to be able to do binds
friend class CGLMFBO ; // fbo needs to be able to do binds
friend class CGLMProgram ;
friend class CGLMShaderPair ;
friend class CGLMShaderPairCache ;
friend class CGLMBuffer ;
friend class CGLMBufferSpanManager ;
friend class GLMTester ; // tester class needs access back into GLMContext
friend struct IDirect3D9 ;
friend struct IDirect3DDevice9 ;
friend struct IDirect3DQuery9 ;
// methods------------------------------------------
// old GLMContext( GLint displayMask, GLint rendererID, PseudoNSGLContextPtr nsglShareCtx );
GLMContext ( IDirect3DDevice9 * pDevice , GLMDisplayParams * params ) ;
~ GLMContext ( ) ;
# ifndef OSX
FORCEINLINE GLuint FindSamplerObject ( const GLMTexSamplingParams & desiredParams ) ;
# endif
FORCEINLINE void SetBufAndVertexAttribPointer ( uint nIndex , GLuint nGLName , GLuint stride , GLuint datatype , GLboolean normalized , GLuint nCompCount , const void * pBuf , uint nRevision )
{
VertexAttribs_t & curAttribs = m_boundVertexAttribs [ nIndex ] ;
if ( nGLName ! = m_nBoundGLBuffer [ kGLMVertexBuffer ] )
{
m_nBoundGLBuffer [ kGLMVertexBuffer ] = nGLName ;
gGL - > glBindBuffer ( GL_ARRAY_BUFFER , nGLName ) ;
}
else if ( ( curAttribs . m_pPtr = = pBuf ) & &
( curAttribs . m_revision = = nRevision ) & &
( curAttribs . m_stride = = stride ) & &
( curAttribs . m_datatype = = datatype ) & &
( curAttribs . m_normalized = = normalized ) & &
( curAttribs . m_nCompCount = = nCompCount ) )
{
return ;
}
curAttribs . m_nCompCount = nCompCount ;
curAttribs . m_datatype = datatype ;
curAttribs . m_normalized = normalized ;
curAttribs . m_stride = stride ;
curAttribs . m_pPtr = pBuf ;
curAttribs . m_revision = nRevision ;
gGL - > glVertexAttribPointer ( nIndex , nCompCount , datatype , normalized , stride , pBuf ) ;
}
struct CurAttribs_t
{
uint m_nTotalBufferRevision ;
IDirect3DVertexDeclaration9 * m_pVertDecl ;
D3DStreamDesc m_streams [ D3D_MAX_STREAMS ] ;
uint64 m_vtxAttribMap [ 2 ] ;
} ;
CurAttribs_t m_CurAttribs ;
FORCEINLINE void ClearCurAttribs ( )
{
m_CurAttribs . m_nTotalBufferRevision = 0 ;
m_CurAttribs . m_pVertDecl = NULL ;
memset ( m_CurAttribs . m_streams , 0 , sizeof ( m_CurAttribs . m_streams ) ) ;
m_CurAttribs . m_vtxAttribMap [ 0 ] = 0xBBBBBBBBBBBBBBBBULL ;
m_CurAttribs . m_vtxAttribMap [ 1 ] = 0xBBBBBBBBBBBBBBBBULL ;
}
FORCEINLINE void ReleasedShader ( ) { NullProgram ( ) ; }
// textures
FORCEINLINE void SelectTMU ( int tmu )
{
if ( tmu ! = m_activeTexture )
{
gGL - > glActiveTexture ( GL_TEXTURE0 + tmu ) ;
m_activeTexture = tmu ;
}
}
void BindTexToTMU ( CGLMTex * tex , int tmu ) ;
// render targets / FBO's
void BindFBOToCtx ( CGLMFBO * fbo , GLenum bindPoint = GL_FRAMEBUFFER ) ; // you can also choose GL_READ_FRAMEBUFFER_EXT / GL_DRAW_FRAMEBUFFER_EXT
// buffers
FORCEINLINE void BindGLBufferToCtx ( GLenum nGLBufType , GLuint nGLName , bool bForce = false )
{
Assert ( ( nGLBufType = = GL_ARRAY_BUFFER ) | | ( nGLBufType = = GL_ELEMENT_ARRAY_BUFFER ) ) ;
const uint nIndex = ( nGLBufType = = GL_ARRAY_BUFFER ) ? kGLMVertexBuffer : kGLMIndexBuffer ;
if ( ( bForce ) | | ( m_nBoundGLBuffer [ nIndex ] ! = nGLName ) )
{
m_nBoundGLBuffer [ nIndex ] = nGLName ;
gGL - > glBindBuffer ( nGLBufType , nGLName ) ;
}
}
void BindBufferToCtx ( EGLMBufferType type , CGLMBuffer * buff , bool force = false ) ; // does not twiddle any enables.
FORCEINLINE void BindIndexBufferToCtx ( CGLMBuffer * buff ) ;
FORCEINLINE void BindVertexBufferToCtx ( CGLMBuffer * buff ) ;
GLuint CreateTex ( GLenum texBind , GLenum internalFormat ) ;
void CleanupTex ( GLenum texBind , GLMTexLayout * pLayout , GLuint tex ) ;
void DestroyTex ( GLenum texBind , GLMTexLayout * pLayout , GLuint tex ) ;
GLuint FillTexCache ( bool holdOne , int newTextures ) ;
void PurgeTexCache ( ) ;
// debug font
void GenDebugFontTex ( void ) ;
void DrawDebugText ( float x , float y , float z , float drawCharWidth , float drawCharHeight , char * string ) ;
CPersistentBuffer * GetCurPersistentBuffer ( EGLMBufferType type ) { return & ( m_persistentBuffer [ m_nCurPersistentBuffer ] [ type ] ) ; }
// members------------------------------------------
// context
uintp m_nCurOwnerThreadId ;
uint m_nThreadOwnershipReleaseCounter ;
bool m_bUseSamplerObjects ;
bool m_bTexClientStorage ;
IDirect3DDevice9 * m_pDevice ;
GLMRendererInfoFields m_caps ;
bool m_displayParamsValid ; // is there a param block copied in yet
GLMDisplayParams m_displayParams ; // last known display config, either via constructor, or by SetDisplayParams...
# if defined( USE_SDL )
int m_pixelFormatAttribs [ 100 ] ; // more than enough
PseudoNSGLContextPtr m_nsctx ;
void * m_ctx ;
# endif
bool m_bUseBoneUniformBuffers ; // if true, we use two uniform buffers for vertex shader constants vs. one
// texture form table
CGLMTexLayoutTable * m_texLayoutTable ;
// context state mirrors
GLState < GLAlphaTestEnable_t > m_AlphaTestEnable ;
GLState < GLAlphaTestFunc_t > m_AlphaTestFunc ;
GLState < GLCullFaceEnable_t > m_CullFaceEnable ;
GLState < GLCullFrontFace_t > m_CullFrontFace ;
GLState < GLPolygonMode_t > m_PolygonMode ;
GLState < GLDepthBias_t > m_DepthBias ;
GLStateArray < GLClipPlaneEnable_t , kGLMUserClipPlanes > m_ClipPlaneEnable ;
GLStateArray < GLClipPlaneEquation_t , kGLMUserClipPlanes > m_ClipPlaneEquation ; // dxabstract puts them directly into param slot 253(0) and 254(1)
GLState < GLScissorEnable_t > m_ScissorEnable ;
GLState < GLScissorBox_t > m_ScissorBox ;
GLState < GLAlphaToCoverageEnable_t > m_AlphaToCoverageEnable ;
GLState < GLViewportBox_t > m_ViewportBox ;
GLState < GLViewportDepthRange_t > m_ViewportDepthRange ;
GLState < GLColorMaskSingle_t > m_ColorMaskSingle ;
GLStateArray < GLColorMaskMultiple_t , 8 > m_ColorMaskMultiple ; // need an official constant for the color buffers limit
GLState < GLBlendEnable_t > m_BlendEnable ;
GLState < GLBlendFactor_t > m_BlendFactor ;
GLState < GLBlendEquation_t > m_BlendEquation ;
GLState < GLBlendColor_t > m_BlendColor ;
GLState < GLBlendEnableSRGB_t > m_BlendEnableSRGB ; // write to this one to transmit intent to write SRGB encoded pixels to drawing FB
bool m_FakeBlendEnableSRGB ; // writes to above will be shunted here if fake SRGB is in effect.
GLState < GLDepthTestEnable_t > m_DepthTestEnable ;
GLState < GLDepthFunc_t > m_DepthFunc ;
GLState < GLDepthMask_t > m_DepthMask ;
GLState < GLStencilTestEnable_t > m_StencilTestEnable ; // global stencil test enable
GLState < GLStencilFunc_t > m_StencilFunc ; // holds front and back stencil funcs
GLStateArray < GLStencilOp_t , 2 > m_StencilOp ; // indexed: 0=front 1=back
GLState < GLStencilWriteMask_t > m_StencilWriteMask ;
GLState < GLClearColor_t > m_ClearColor ;
GLState < GLClearDepth_t > m_ClearDepth ;
GLState < GLClearStencil_t > m_ClearStencil ;
// texture bindings and sampler setup
int m_activeTexture ; // mirror for glActiveTexture
GLMTexSampler m_samplers [ GLM_SAMPLER_COUNT ] ;
uint8 m_nDirtySamplerFlags [ GLM_SAMPLER_COUNT ] ; // 0 if the sampler is dirty, 1 if not
uint32 m_nNumDirtySamplers ; // # of unique dirty sampler indices in m_nDirtySamplers
uint8 m_nDirtySamplers [ GLM_SAMPLER_COUNT + 1 ] ; // dirty sampler indices
void MarkAllSamplersDirty ( ) ;
struct SamplerHashEntry
{
GLuint m_samplerObject ;
GLMTexSamplingParams m_params ;
} ;
enum
{
cSamplerObjectHashBits = 9 , cSamplerObjectHashSize = 1 < < cSamplerObjectHashBits
} ;
SamplerHashEntry m_samplerObjectHash [ cSamplerObjectHashSize ] ;
uint m_nSamplerObjectHashNumEntries ;
// texture lock tracking - CGLMTex objects share usage of this
CUtlVector < GLMTexLockDesc > m_texLocks ;
// render target binding - check before draw
// similar to tex sampler mechanism, we track "bound" from "chosen for drawing" separately,
// so binding for creation/setup need not disrupt any notion of what will be used at draw time
CGLMFBO * m_boundDrawFBO ; // FBO on GL_DRAW_FRAMEBUFFER bind point
CGLMFBO * m_boundReadFBO ; // FBO on GL_READ_FRAMEBUFFER bind point
// ^ both are set if you bind to GL_FRAMEBUFFER_EXT
CGLMFBO * m_drawingFBO ; // what FBO should be bound at draw time (to both read/draw bp's).
CGLMFBO * m_blitReadFBO ;
CGLMFBO * m_blitDrawFBO ; // scratch FBO's for framebuffer blit
CGLMFBO * m_scratchFBO [ kGLMScratchFBOCount ] ; // general purpose FBO's for internal use
CUtlVector < CGLMFBO * > m_fboTable ; // each live FBO goes in the table
uint m_fragDataMask ;
// program bindings
EGLMProgramLang m_drawingLangAtFrameStart ; // selector for start of frame (spills into m_drawingLang)
EGLMProgramLang m_drawingLang ; // selector for which language we desire to draw with on the next batch
CGLMProgram * m_drawingProgram [ kGLMNumProgramTypes ] ;
bool m_bDirtyPrograms ;
GLMProgramParamsF m_programParamsF [ kGLMNumProgramTypes ] ;
GLMProgramParamsB m_programParamsB [ kGLMNumProgramTypes ] ;
GLMProgramParamsI m_programParamsI [ kGLMNumProgramTypes ] ; // two banks, but only the vertex one is used
EGLMParamWriteMode m_paramWriteMode ;
CGLMProgram * m_pNullFragmentProgram ; // write opaque black. Activate when caller asks for null FP
CGLMProgram * m_preloadTexVertexProgram ; // programs to help preload textures (dummies)
CGLMProgram * m_preload2DTexFragmentProgram ;
CGLMProgram * m_preload3DTexFragmentProgram ;
CGLMProgram * m_preloadCubeTexFragmentProgram ;
# if defined( OSX ) && defined( GLMDEBUG )
CGLMProgram * m_boundProgram [ kGLMNumProgramTypes ] ;
# endif
CGLMShaderPairCache * m_pairCache ; // GLSL only
CGLMShaderPair * m_pBoundPair ; // GLSL only
FORCEINLINE void NewLinkedProgram ( ) { ClearCurAttribs ( ) ; }
//uint m_boundPairRevision; // GLSL only
//GLhandleARB m_boundPairProgram; // GLSL only
// buffer bindings
GLuint m_nBoundGLBuffer [ kGLMNumBufferTypes ] ;
struct VertexAttribs_t
{
GLuint m_nCompCount ;
GLenum m_datatype ;
GLboolean m_normalized ;
GLuint m_stride ;
const void * m_pPtr ;
uint m_revision ;
} ;
VertexAttribs_t m_boundVertexAttribs [ kGLMVertexAttributeIndexMax ] ; // tracked per attrib for dupe-set-absorb
uint m_lastKnownVertexAttribMask ; // tracked for dupe-enable-absorb
int m_nNumSetVertexAttributes ;
// FIXME: Remove this, it's no longer used
GLMVertexSetup m_drawVertexSetup ;
EGLMAttribWriteMode m_attribWriteMode ;
bool m_slowCheckEnable ; // turn this on or no native checking is done ("-glmassertslow" or "-glmsspewslow")
bool m_slowAssertEnable ; // turn this on to assert on a non-native batch "-glmassertslow"
bool m_slowSpewEnable ; // turn this on to log non-native batches to stdout "-glmspewslow"
bool m_checkglErrorsAfterEveryBatch ; // turn this on to check for GL errors after each batch (slow) ("-glcheckerrors")
// debug font texture
CGLMTex * m_debugFontTex ; // might be NULL unless you call GenDebugFontTex
CGLMBuffer * m_debugFontIndices ; // up to 1024 indices (256 chars times 4)
CGLMBuffer * m_debugFontVertices ; // up to 1024 verts
// batch/frame debugging support
int m_debugFrameIndex ; // init to -1. Increment at BeginFrame
int m_nMaxUsedVertexProgramConstantsHint ;
uint32 m_dwRenderThreadId ;
volatile bool m_bIsThreading ;
uint m_nCurFrame ;
uint m_nBatchCounter ;
struct TextureEntry_t
{
GLenum m_nTexBind ;
GLenum m_nInternalFormat ;
GLuint m_nTexName ;
} ;
GLuint m_destroyPBO ;
CUtlVector < TextureEntry_t > m_availableTextures ;
enum { cNumPersistentBuffers = 3 } ;
CPersistentBuffer m_persistentBuffer [ cNumPersistentBuffers ] [ kGLMNumBufferTypes ] ;
uint m_nCurPersistentBuffer ;
void SaveColorMaskAndSetToDefault ( ) ;
void RestoreSavedColorMask ( ) ;
GLColorMaskSingle_t m_SavedColorMask ;
# if GLMDEBUG
// interactive (DebugHook) debug support
// using these you can implement frame advance, batch single step, and batch rewind (let it run til next frame and hold on prev batch #)
int m_holdFrameBegin ; // -1 if no hold req'd, otherwise # of frame to hold at (at beginframe time)
int m_holdFrameEnd ; // -1 if no hold req'd, otherwise # of frame to hold at (at endframe time)
int m_holdBatch , m_holdBatchFrame ; // -1 if no hold, else # of batch&frame to hold at (both must be set)
// these can be expired/cleared to -1 if the frame passes without a hit
// may be desirable to re-pause in that event, as user was expecting a hold to occur
bool m_debugDelayEnable ; // allow sleep delay
uint m_debugDelay ; // sleep time per hook call in microseconds (for usleep())
// pre-draw global toggles / options
bool m_autoClearColor , m_autoClearDepth , m_autoClearStencil ;
float m_autoClearColorValues [ 4 ] ;
// debug knobs
int m_selKnobIndex ;
float m_selKnobMinValue , m_selKnobMaxValue , m_selKnobIncrement ;
# endif
# if GL_BATCH_PERF_ANALYSIS
uint m_nTotalVSUniformCalls ;
uint m_nTotalVSUniformBoneCalls ;
uint m_nTotalVSUniformsSet ;
uint m_nTotalVSUniformsBoneSet ;
uint m_nTotalPSUniformCalls ;
uint m_nTotalPSUniformsSet ;
CFlushDrawStatesStats m_FlushStats ;
# endif
void ProcessTextureDeletes ( ) ;
CTSQueue < CGLMTex * > m_DeleteTextureQueue ;
} ;
# if 1 //ifndef OSX
FORCEINLINE void GLMContext : : DrawRangeElements ( GLenum mode , GLuint start , GLuint end , GLsizei count , GLenum type , const GLvoid * indices , uint baseVertex , CGLMBuffer * pIndexBuf )
{
# if GL_ENABLE_INDEX_VERIFICATION
DrawRangeElementsNonInline ( mode , start , end , count , type , indices , baseVertex , pIndexBuf ) ;
# else
# if GLMDEBUG
GLM_FUNC ;
# else
//tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s %d-%d count:%d mode:%d type:%d", __FUNCTION__, start, end, count, mode, type );
# endif
+ + m_nBatchCounter ;
SetIndexBuffer ( pIndexBuf ) ;
void * indicesActual = ( void * ) indices ;
if ( pIndexBuf - > m_bPseudo )
{
// you have to pass actual address, not offset
indicesActual = ( void * ) ( ( intp ) indicesActual + ( intp ) pIndexBuf - > m_pPseudoBuf ) ;
}
if ( pIndexBuf - > m_bUsingPersistentBuffer )
{
indicesActual = ( void * ) ( ( intp ) indicesActual + ( intp ) pIndexBuf - > m_nPersistentBufferStartOffset ) ;
}
//#if GLMDEBUG
#if 0
bool hasVP = m_drawingProgram [ kGLMVertexProgram ] ! = NULL ;
bool hasFP = m_drawingProgram [ kGLMFragmentProgram ] ! = NULL ;
// init debug hook information
GLMDebugHookInfo info ;
memset ( & info , 0 , sizeof ( info ) ) ;
info . m_caller = eDrawElements ;
// relay parameters we're operating under
info . m_drawMode = mode ;
info . m_drawStart = start ;
info . m_drawEnd = end ;
info . m_drawCount = count ;
info . m_drawType = type ;
info . m_drawIndices = indices ;
do
{
// obey global options re pre-draw clear
if ( m_autoClearColor | | m_autoClearDepth | | m_autoClearStencil )
{
GLMPRINTF ( ( " -- DrawRangeElements auto clear " ) ) ;
this - > DebugClear ( ) ;
}
// always sync with editable shader text prior to draw
# if GLMDEBUG
//FIXME disengage this path if context is in GLSL mode..
// it will need fixes to get the shader pair re-linked etc if edits happen anyway.
if ( m_drawingProgram [ kGLMVertexProgram ] )
{
m_drawingProgram [ kGLMVertexProgram ] - > SyncWithEditable ( ) ;
}
else
{
AssertOnce ( ! " drawing with no vertex program bound " ) ;
}
if ( m_drawingProgram [ kGLMFragmentProgram ] )
{
m_drawingProgram [ kGLMFragmentProgram ] - > SyncWithEditable ( ) ;
}
else
{
AssertOnce ( ! " drawing with no fragment program bound " ) ;
}
# endif
// do the drawing
if ( hasVP & & hasFP )
{
gGL - > glDrawRangeElementsBaseVertex ( mode , start , end , count , type , indicesActual , baseVertex ) ;
if ( m_slowCheckEnable )
{
CheckNative ( ) ;
}
}
this - > DebugHook ( & info ) ;
} while ( info . m_loop ) ;
# else
Assert ( m_drawingLang = = kGLMGLSL ) ;
if ( m_pBoundPair )
{
gGL - > glDrawRangeElementsBaseVertex ( mode , start , end , count , type , indicesActual , baseVertex ) ;
# if GLMDEBUG
if ( m_slowCheckEnable )
{
CheckNative ( ) ;
}
# endif
}
# endif
# endif // GL_ENABLE_INDEX_VERIFICATION
}
# endif // #ifndef OSX
FORCEINLINE void GLMContext : : SetVertexProgram ( CGLMProgram * pProg )
{
m_drawingProgram [ kGLMVertexProgram ] = pProg ;
m_bDirtyPrograms = true ;
}
FORCEINLINE void GLMContext : : SetFragmentProgram ( CGLMProgram * pProg )
{
m_drawingProgram [ kGLMFragmentProgram ] = pProg ? pProg : m_pNullFragmentProgram ;
m_bDirtyPrograms = true ;
}
// "slot" means a vec4-sized thing
// these write into .env parameter space
FORCEINLINE void GLMContext : : SetProgramParametersF ( EGLMProgramType type , uint baseSlot , float * slotData , uint slotCount )
{
# if GLMDEBUG
GLM_FUNC ;
# endif
Assert ( baseSlot < kGLMProgramParamFloat4Limit ) ;
Assert ( baseSlot + slotCount < = kGLMProgramParamFloat4Limit ) ;
# if GLMDEBUG
GLMPRINTF ( ( " -S-GLMContext::SetProgramParametersF %s slots %d - %d: " , ( type = = kGLMVertexProgram ) ? " VS " : " FS " , baseSlot , baseSlot + slotCount - 1 ) ) ;
for ( uint i = 0 ; i < slotCount ; i + + )
{
GLMPRINTF ( ( " -S- %03d: [ %7.4f %7.4f %7.4f %7.4f ] " ,
baseSlot + i ,
slotData [ i * 4 ] , slotData [ i * 4 + 1 ] , slotData [ i * 4 + 2 ] , slotData [ i * 4 + 3 ]
) ) ;
}
# endif
memcpy ( & m_programParamsF [ type ] . m_values [ baseSlot ] [ 0 ] , slotData , ( 4 * sizeof ( float ) ) * slotCount ) ;
if ( ( type = = kGLMVertexProgram ) & & ( m_bUseBoneUniformBuffers ) )
{
// changes here to handle vertex shaders which use constants before and after the bone array i.e. before c58 and after c216
// a better change may be to modify the shaders and place the bone consts at either start or end - would simplify this and the flush code
// the current supporting code (shader translator(dx9asmtogl2), param setting(here) and flushing(glmgr_flush.inl) should work unchanged, even if the const mapping is changed.
int firstDirty = ( int ) baseSlot ;
int highWater = ( int ) ( baseSlot + slotCount ) ;
if ( highWater < = DXABSTRACT_VS_FIRST_BONE_SLOT )
{
m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone , firstDirty ) ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone , highWater ) ;
}
else if ( highWater < = ( DXABSTRACT_VS_LAST_BONE_SLOT + 1 ) )
{
if ( firstDirty < DXABSTRACT_VS_FIRST_BONE_SLOT )
{
m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone , firstDirty ) ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone , MIN ( DXABSTRACT_VS_FIRST_BONE_SLOT , highWater ) ) ;
firstDirty = DXABSTRACT_VS_FIRST_BONE_SLOT ;
}
int nNumActualBones = ( firstDirty + slotCount ) - DXABSTRACT_VS_FIRST_BONE_SLOT ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterBone , nNumActualBones ) ;
}
else
{
const int maxBoneSlots = ( DXABSTRACT_VS_LAST_BONE_SLOT + 1 ) - DXABSTRACT_VS_FIRST_BONE_SLOT ;
if ( firstDirty > DXABSTRACT_VS_LAST_BONE_SLOT )
{
m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone , firstDirty - maxBoneSlots ) ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone , highWater - maxBoneSlots ) ;
}
else if ( firstDirty > = DXABSTRACT_VS_FIRST_BONE_SLOT )
{
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterBone = DXABSTRACT_VS_LAST_BONE_SLOT + 1 ;
m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone , DXABSTRACT_VS_FIRST_BONE_SLOT ) ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone , highWater - maxBoneSlots ) ;
}
else
{
int nNumActualBones = ( DXABSTRACT_VS_LAST_BONE_SLOT + 1 ) - DXABSTRACT_VS_FIRST_BONE_SLOT ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterBone , nNumActualBones ) ;
m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ kGLMVertexProgram ] . m_firstDirtySlotNonBone , firstDirty ) ;
m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ kGLMVertexProgram ] . m_dirtySlotHighWaterNonBone , highWater - maxBoneSlots ) ;
}
}
}
else
{
m_programParamsF [ type ] . m_dirtySlotHighWaterNonBone = MAX ( m_programParamsF [ type ] . m_dirtySlotHighWaterNonBone , ( int ) ( baseSlot + slotCount ) ) ;
m_programParamsF [ type ] . m_firstDirtySlotNonBone = MIN ( m_programParamsF [ type ] . m_firstDirtySlotNonBone , ( int ) baseSlot ) ;
}
}
FORCEINLINE void GLMContext : : SetProgramParametersB ( EGLMProgramType type , uint baseSlot , int * slotData , uint boolCount )
{
# if GLMDEBUG
GLM_FUNC ;
# endif
Assert ( m_drawingLang = = kGLMGLSL ) ;
Assert ( type = = kGLMVertexProgram | | type = = kGLMFragmentProgram ) ;
Assert ( baseSlot < kGLMProgramParamBoolLimit ) ;
Assert ( baseSlot + boolCount < = kGLMProgramParamBoolLimit ) ;
# if GLMDEBUG
GLMPRINTF ( ( " -S-GLMContext::SetProgramParametersB %s bools %d - %d: " , ( type = = kGLMVertexProgram ) ? " VS " : " FS " , baseSlot , baseSlot + boolCount - 1 ) ) ;
for ( uint i = 0 ; i < boolCount ; i + + )
{
GLMPRINTF ( ( " -S- %03d: %d (bool) " ,
baseSlot + i ,
slotData [ i ]
) ) ;
}
# endif
memcpy ( & m_programParamsB [ type ] . m_values [ baseSlot ] , slotData , sizeof ( int ) * boolCount ) ;
if ( ( baseSlot + boolCount ) > m_programParamsB [ type ] . m_dirtySlotCount )
m_programParamsB [ type ] . m_dirtySlotCount = baseSlot + boolCount ;
}
FORCEINLINE void GLMContext : : SetProgramParametersI ( EGLMProgramType type , uint baseSlot , int * slotData , uint slotCount ) // groups of 4 ints...
{
# if GLMDEBUG
GLM_FUNC ;
# endif
Assert ( m_drawingLang = = kGLMGLSL ) ;
Assert ( type = = kGLMVertexProgram ) ;
Assert ( baseSlot < kGLMProgramParamInt4Limit ) ;
Assert ( baseSlot + slotCount < = kGLMProgramParamInt4Limit ) ;
# if GLMDEBUG
GLMPRINTF ( ( " -S-GLMContext::SetProgramParametersI %s slots %d - %d: " , ( type = = kGLMVertexProgram ) ? " VS " : " FS " , baseSlot , baseSlot + slotCount - 1 ) ) ;
for ( uint i = 0 ; i < slotCount ; i + + )
{
GLMPRINTF ( ( " -S- %03d: %d %d %d %d (int4) " ,
baseSlot + i ,
slotData [ i * 4 ] , slotData [ i * 4 + 1 ] , slotData [ i * 4 + 2 ] , slotData [ i * 4 + 3 ]
) ) ;
}
# endif
memcpy ( & m_programParamsI [ type ] . m_values [ baseSlot ] [ 0 ] , slotData , ( 4 * sizeof ( int ) ) * slotCount ) ;
if ( ( baseSlot + slotCount ) > m_programParamsI [ type ] . m_dirtySlotCount )
{
m_programParamsI [ type ] . m_dirtySlotCount = baseSlot + slotCount ;
}
}
FORCEINLINE void GLMContext : : SetSamplerDirty ( int sampler )
{
Assert ( sampler < GLM_SAMPLER_COUNT ) ;
m_nDirtySamplers [ m_nNumDirtySamplers ] = sampler ;
m_nNumDirtySamplers + = m_nDirtySamplerFlags [ sampler ] ;
m_nDirtySamplerFlags [ sampler ] = 0 ;
}
FORCEINLINE void GLMContext : : SetSamplerTex ( int sampler , CGLMTex * tex )
{
Assert ( sampler < GLM_SAMPLER_COUNT ) ;
m_samplers [ sampler ] . m_pBoundTex = tex ;
if ( tex )
{
if ( ! gGL - > m_bHave_GL_EXT_direct_state_access )
{
if ( sampler ! = m_activeTexture )
{
gGL - > glActiveTexture ( GL_TEXTURE0 + sampler ) ;
m_activeTexture = sampler ;
}
gGL - > glBindTexture ( tex - > m_texGLTarget , tex - > m_texName ) ;
}
else
{
gGL - > glBindMultiTextureEXT ( GL_TEXTURE0 + sampler , tex - > m_texGLTarget , tex - > m_texName ) ;
}
}
if ( ! m_bUseSamplerObjects )
{
SetSamplerDirty ( sampler ) ;
}
}
FORCEINLINE void GLMContext : : SetSamplerMinFilter ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_minFilter = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerMagFilter ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_magFilter = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerMipFilter ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_mipFilter = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerAddressU ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_addressU = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerAddressV ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_addressV = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerAddressW ( int sampler , GLenum Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_addressW = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerStates ( int sampler , GLenum AddressU , GLenum AddressV , GLenum AddressW , GLenum minFilter , GLenum magFilter , GLenum mipFilter , int minLod , float lodBias )
{
Assert ( AddressU < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
Assert ( AddressV < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
Assert ( AddressW < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS ) ) ;
Assert ( minFilter < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS ) ) ;
Assert ( magFilter < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS ) ) ;
Assert ( mipFilter < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS ) ) ;
Assert ( minLod < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS ) ) ;
GLMTexSamplingParams & params = m_samplers [ sampler ] . m_samp ;
params . m_packed . m_addressU = AddressU ;
params . m_packed . m_addressV = AddressV ;
params . m_packed . m_addressW = AddressW ;
params . m_packed . m_minFilter = minFilter ;
params . m_packed . m_magFilter = magFilter ;
params . m_packed . m_mipFilter = mipFilter ;
params . m_packed . m_minLOD = minLod ;
params . m_lodBias = lodBias ;
}
FORCEINLINE void GLMContext : : SetSamplerBorderColor ( int sampler , DWORD Value )
{
m_samplers [ sampler ] . m_samp . m_borderColor = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerMipMapLODBias ( int sampler , DWORD Value )
{
typedef union {
DWORD asDword ;
float asFloat ;
} Convert_t ;
Convert_t c ;
c . asDword = Value ;
m_samplers [ sampler ] . m_samp . m_lodBias = c . asFloat ;
}
FORCEINLINE void GLMContext : : SetSamplerMaxMipLevel ( int sampler , DWORD Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_minLOD = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerMaxAnisotropy ( int sampler , DWORD Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_maxAniso = Value ;
}
FORCEINLINE void GLMContext : : SetSamplerSRGBTexture ( int sampler , DWORD Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_srgb = Value ;
}
FORCEINLINE void GLMContext : : SetShadowFilter ( int sampler , DWORD Value )
{
Assert ( Value < ( 1 < < GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS ) ) ;
m_samplers [ sampler ] . m_samp . m_packed . m_compareMode = Value ;
}
FORCEINLINE void GLMContext : : BindIndexBufferToCtx ( CGLMBuffer * buff )
{
GLMPRINTF ( ( " --- GLMContext::BindIndexBufferToCtx buff %p, GL name %d " , buff , ( buff ) ? buff - > m_nHandle : - 1 ) ) ;
Assert ( ! buff | | ( buff - > m_buffGLTarget = = GL_ELEMENT_ARRAY_BUFFER ) ) ;
GLuint nGLName = buff ? buff - > GetHandle ( ) : 0 ;
if ( m_nBoundGLBuffer [ kGLMIndexBuffer ] = = nGLName )
return ;
m_nBoundGLBuffer [ kGLMIndexBuffer ] = nGLName ;
gGL - > glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER , nGLName ) ;
}
FORCEINLINE void GLMContext : : BindVertexBufferToCtx ( CGLMBuffer * buff )
{
GLMPRINTF ( ( " --- GLMContext::BindVertexBufferToCtx buff %p, GL name %d " , buff , ( buff ) ? buff - > m_nHandle : - 1 ) ) ;
Assert ( ! buff | | ( buff - > m_buffGLTarget = = GL_ARRAY_BUFFER ) ) ;
GLuint nGLName = buff ? buff - > GetHandle ( ) : 0 ;
if ( m_nBoundGLBuffer [ kGLMVertexBuffer ] = = nGLName )
return ;
m_nBoundGLBuffer [ kGLMVertexBuffer ] = nGLName ;
gGL - > glBindBuffer ( GL_ARRAY_BUFFER , nGLName ) ;
}
FORCEINLINE void GLMContext : : SetMaxUsedVertexShaderConstantsHint ( uint nMaxConstants )
{
static bool bUseMaxVertexShadeConstantHints = ! CommandLine ( ) - > CheckParm ( " -disablemaxvertexshaderconstanthints " ) ;
if ( bUseMaxVertexShadeConstantHints )
{
m_nMaxUsedVertexProgramConstantsHint = nMaxConstants ;
}
}
struct GLMTestParams
{
GLMContext * m_ctx ;
int * m_testList ; // -1 termed
bool m_glErrToDebugger ;
bool m_glErrToConsole ;
bool m_intlErrToDebugger ;
bool m_intlErrToConsole ;
int m_frameCount ; // how many frames to test.
} ;
class GLMTester
{
public :
GLMTester ( GLMTestParams * params ) ;
~ GLMTester ( ) ;
// optionally callable by test routines to get basic drawables wired up
void StdSetup ( void ) ;
void StdCleanup ( void ) ;
// callable by test routines to clear the frame or present it
void Clear ( void ) ;
void Present ( int seed ) ;
// error reporting
void CheckGLError ( const char * comment ) ; // obey m_params setting for console / debugger response
void InternalError ( int errcode , char * comment ) ; // if errcode!=0, obey m_params setting for console / debugger response
void RunTests ( ) ;
void RunOneTest ( int testindex ) ;
// test routines themselves
void Test0 ( ) ;
void Test1 ( ) ;
void Test2 ( ) ;
void Test3 ( ) ;
GLMTestParams m_params ; // copy of caller's params, do not mutate...
// std-setup stuff
int m_drawWidth , m_drawHeight ;
CGLMFBO * m_drawFBO ;
CGLMTex * m_drawColorTex ;
CGLMTex * m_drawDepthTex ;
} ;
class CShowPixelsParams
{
public :
GLuint m_srcTexName ;
int m_width , m_height ;
bool m_vsyncEnable ;
bool m_fsEnable ; // want receiving view to be full screen. for now, just target the main screen. extend later.
bool m_useBlit ; // use FBO blit - sending context says it is available.
bool m_noBlit ; // the back buffer has already been populated by the caller (perhaps via direct MSAA resolve from multisampled RT tex)
bool m_onlySyncView ; // react to full/windowed state change only, do not present bits
} ;
# define kMaxCrawlFrames 100
# define kMaxCrawlText (kMaxCrawlFrames * 256)
class CStackCrawlParams
{
public :
uint m_frameLimit ; // input: max frames to retrieve
uint m_frameCount ; // output: frames found
void * m_crawl [ kMaxCrawlFrames ] ; // call site addresses
char * m_crawlNames [ kMaxCrawlFrames ] ; // pointers into text following, one per decoded name
char m_crawlText [ kMaxCrawlText ] ;
} ;
# endif // GLMGR_H