diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /sp/src/public/togl/linuxwin/glmgr.h | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/public/togl/linuxwin/glmgr.h')
| -rw-r--r-- | sp/src/public/togl/linuxwin/glmgr.h | 4518 |
1 files changed, 2259 insertions, 2259 deletions
diff --git a/sp/src/public/togl/linuxwin/glmgr.h b/sp/src/public/togl/linuxwin/glmgr.h index cc828636..2f555db9 100644 --- a/sp/src/public/togl/linuxwin/glmgr.h +++ b/sp/src/public/togl/linuxwin/glmgr.h @@ -1,2259 +1,2259 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// glmgr.h
-// singleton class, common basis for managing GL contexts
-// responsible for tracking adapters and contexts
-//
-//===============================================================================
-
-#ifndef GLMGR_H
-#define GLMGR_H
-
-#pragma once
-
-#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/vprof_telemetry.h"
-#include "materialsystem/IShader.h"
-#include "dxabstract_types.h"
-#include "tier0/icommandline.h"
-
-//===============================================================================
-
-#define GLM_OPENGL_VENDOR_ID 1
-#define GLM_OPENGL_DEFAULT_DEVICE_ID 1
-#define GLM_OPENGL_LOW_PERF_DEVICE_ID 2
-
-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 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 { GLdouble 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 { 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 { 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 { GLdouble 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
-
-// --- GLAlphaTestEnable ---
-FORCEINLINE void GLContextSet( GLAlphaTestEnable_t *src )
-{
- glSetEnable( GL_ALPHA_TEST, src->enable != 0 );
-}
-
-FORCEINLINE void GLContextGet( GLAlphaTestEnable_t *dst )
-{
- dst->enable = gGL->glIsEnabled( GL_ALPHA_TEST );
-}
-
-FORCEINLINE void GLContextGetDefault( GLAlphaTestEnable_t *dst )
-{
- dst->enable = GL_FALSE;
-}
-
-// --- GLAlphaTestFunc ---
-FORCEINLINE void GLContextSet( GLAlphaTestFunc_t *src )
-{
- gGL->glAlphaFunc( src->func, src->ref );
-}
-
-FORCEINLINE void GLContextGet( GLAlphaTestFunc_t *dst )
-{
- glGetEnumv( GL_ALPHA_TEST_FUNC, &dst->func );
- gGL->glGetFloatv( GL_ALPHA_TEST_REF, &dst->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_ARB, src->enable != 0 );
-}
-
-FORCEINLINE void GLContextGet( GLAlphaToCoverageEnable_t *dst )
-{
- dst->enable = gGL->glIsEnabled( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB );
-}
-
-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->glDepthRange ( src->flNear, src->flFar );
-}
-
-FORCEINLINE void GLContextGet( GLViewportDepthRange_t *dst )
-{
- gGL->glGetDoublev ( 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 )
-{
- gGL->glColorMaskIndexedEXT ( index, src->r, src->g, src->b, src->a );
-}
-
-FORCEINLINE void GLContextGetIndexed( GLColorMaskMultiple_t *dst, int index )
-{
- gGL->glGetBooleanIndexedvEXT ( GL_COLOR_WRITEMASK, index, (GLboolean*)&dst->r );
-}
-
-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;
- //pfnglGetFramebufferAttachmentParameteriv( 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 = 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->glClearDepth ( src->d );
-}
-
-FORCEINLINE void GLContextGet( GLClearDepth_t *dst )
-{
- gGL->glGetDoublev ( 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 32
-
-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;
-};
-
-//===========================================================================//
-
-#ifndef GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD
-#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160
-#endif
-
-#define GLMGR_PINNED_MEMORY_BUFFER_SIZE ( 6 * 1024 * 1024 )
-
-class CPinnedMemoryBuffer
-{
- CPinnedMemoryBuffer( const CPinnedMemoryBuffer & );
- CPinnedMemoryBuffer & operator= ( const CPinnedMemoryBuffer & );
-
-public:
- CPinnedMemoryBuffer() : m_pRawBuf( NULL ), m_pBuf( NULL ), m_nSize( 0 ), m_nOfs( 0 ), m_nBufferObj( 0 ), m_nSyncObj( 0 )
- {
- }
-
- ~CPinnedMemoryBuffer()
- {
- Deinit();
- }
-
- bool Init( uint nSize )
- {
- Deinit();
-
- // Guarantee 64KB alignment
- m_pRawBuf = malloc( nSize + 65535 );
- m_pBuf = reinterpret_cast<void *>((reinterpret_cast<uint64>(m_pRawBuf) + 65535) & (~65535));
- m_nSize = nSize;
- m_nOfs = 0;
-
- gGL->glGenBuffersARB( 1, &m_nBufferObj );
- gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj );
-
- gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nSize, m_pBuf, GL_STREAM_COPY );
-
- return true;
- }
-
- void Deinit()
- {
- if ( !m_pRawBuf )
- return;
-
- BlockUntilNotBusy();
-
- gGL->glBindBufferARB(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj );
-
- gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0, (void*)NULL, GL_STREAM_COPY );
-
- gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0 );
-
- gGL->glDeleteBuffersARB( 1, &m_nBufferObj );
- m_nBufferObj = 0;
-
- free( m_pRawBuf );
- m_pRawBuf = NULL;
- m_pBuf = NULL;
-
- m_nSize = 0;
- m_nOfs = 0;
- }
-
- inline uint GetSize() const { return m_nSize; }
- inline uint GetOfs() const { return m_nOfs; }
- inline uint GetBytesRemaining() const { return m_nSize - m_nOfs; }
- inline void *GetPtr() const { return m_pBuf; }
- inline GLuint GetHandle() const { return m_nBufferObj; }
-
- void InsertFence()
- {
- if ( m_nSyncObj )
- {
- gGL->glDeleteSync( m_nSyncObj );
- }
-
- m_nSyncObj = gGL->glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 );
- }
-
- void BlockUntilNotBusy()
- {
- if ( m_nSyncObj )
- {
- gGL->glClientWaitSync( m_nSyncObj, GL_SYNC_FLUSH_COMMANDS_BIT, 3000000000000ULL );
-
- gGL->glDeleteSync( m_nSyncObj );
-
- m_nSyncObj = 0;
- }
- m_nOfs = 0;
- }
-
- void Append( uint nSize )
- {
- m_nOfs += nSize;
- Assert( m_nOfs <= m_nSize );
- }
-
-private:
- void *m_pRawBuf;
- void *m_pBuf;
- uint m_nSize;
- uint m_nOfs;
-
- GLuint m_nBufferObj;
-
- GLsync m_nSyncObj;
-};
-
-//===========================================================================//
-
-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, 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 );
- 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 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
- 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 );
-
- 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 DWORD 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();
-
- FORCEINLINE GLuint FindSamplerObject( const GLMTexSamplingParams &desiredParams );
-
- 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->glBindBufferARB( GL_ARRAY_BUFFER_ARB, 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_EXT ); // 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_ARB ) || ( nGLBufType == GL_ELEMENT_ARRAY_BUFFER_ARB ) );
-
- const uint nIndex = ( nGLBufType == GL_ARRAY_BUFFER_ARB ) ? kGLMVertexBuffer : kGLMIndexBuffer;
- if ( ( bForce ) || ( m_nBoundGLBuffer[nIndex] != nGLName ) )
- {
- m_nBoundGLBuffer[nIndex] = nGLName;
- gGL->glBindBufferARB( 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 );
-
- CPinnedMemoryBuffer *GetCurPinnedMemoryBuffer( ) { return &m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer]; }
-
- // members------------------------------------------
-
- // context
- DWORD m_nCurOwnerThreadId;
- uint m_nThreadOwnershipReleaseCounter;
-
- bool m_bUseSamplerObjects;
- bool m_bPreferMapBufferRange;
-
- 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...
-
-#ifdef OSX
- CGLPixelFormatAttribute m_pixelFormatAttribs[100]; // more than enough
- PseudoNSGLContextPtr m_nsctx;
- CGLContextObj m_ctx;
-#elif defined( USE_SDL )
- int m_pixelFormatAttribs[100]; // more than enough
- PseudoNSGLContextPtr m_nsctx;
- void * m_ctx;
-#endif
- bool m_oneCtxEnable; // true if we use the window's context directly instead of making a second one shared against it
-
- 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
-
- // 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 ]; // two banks, but only the vertex one is used
- 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;
-
- 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;
-
- enum { cNumPinnedMemoryBuffers = 4 };
- CPinnedMemoryBuffer m_PinnedMemoryBuffers[cNumPinnedMemoryBuffers];
- uint m_nCurPinnedMemoryBuffer;
-
- 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
-};
-
-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*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf );
- }
-
-#if GLMDEBUG
- 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
-}
-
-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 ) )
- {
- if ( ( baseSlot + slotCount ) > DXABSTRACT_VS_FIRST_BONE_SLOT )
- {
- if ( baseSlot < DXABSTRACT_VS_FIRST_BONE_SLOT )
- {
- // The register set crosses between the constant buffers - should only happen at startup during init.
- m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, (int)baseSlot );
- m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, (int)MIN( baseSlot + slotCount, DXABSTRACT_VS_FIRST_BONE_SLOT ) );
- baseSlot = DXABSTRACT_VS_FIRST_BONE_SLOT;
- }
-
- int nNumActualBones = ( baseSlot + slotCount ) - DXABSTRACT_VS_FIRST_BONE_SLOT;
- m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone, nNumActualBones );
- }
- else
- {
- m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, (int)baseSlot );
- m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, (int)(baseSlot + slotCount) );
- }
- }
- 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 );
-
- 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 )
-{
- 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 ) );
-
- GLMTexSamplingParams ¶ms = 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;
-}
-
-FORCEINLINE void GLMContext::SetSamplerBorderColor( int sampler, DWORD Value )
-{
- m_samplers[sampler].m_samp.m_borderColor = Value;
-}
-
-FORCEINLINE void GLMContext::SetSamplerMipMapLODBias( int sampler, DWORD Value )
-{
- // not currently supported
-}
-
-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_ARB ) );
-
- GLuint nGLName = buff ? buff->m_nHandle : 0;
-
- if ( m_nBoundGLBuffer[ kGLMIndexBuffer] == nGLName )
- return;
-
- m_nBoundGLBuffer[ kGLMIndexBuffer] = nGLName;
- gGL->glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 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_ARB ) );
-
- GLuint nGLName = buff ? buff->m_nHandle : 0;
-
- if ( m_nBoundGLBuffer[ kGLMVertexBuffer] == nGLName )
- return;
-
- m_nBoundGLBuffer[ kGLMVertexBuffer] = nGLName;
- gGL->glBindBufferARB( GL_ARRAY_BUFFER_ARB, 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 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
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// glmgr.h +// singleton class, common basis for managing GL contexts +// responsible for tracking adapters and contexts +// +//=============================================================================== + +#ifndef GLMGR_H +#define GLMGR_H + +#pragma once + +#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/vprof_telemetry.h" +#include "materialsystem/IShader.h" +#include "dxabstract_types.h" +#include "tier0/icommandline.h" + +//=============================================================================== + +#define GLM_OPENGL_VENDOR_ID 1 +#define GLM_OPENGL_DEFAULT_DEVICE_ID 1 +#define GLM_OPENGL_LOW_PERF_DEVICE_ID 2 + +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 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 { GLdouble 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 { 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 { 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 { GLdouble 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 + +// --- GLAlphaTestEnable --- +FORCEINLINE void GLContextSet( GLAlphaTestEnable_t *src ) +{ + glSetEnable( GL_ALPHA_TEST, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLAlphaTestEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_ALPHA_TEST ); +} + +FORCEINLINE void GLContextGetDefault( GLAlphaTestEnable_t *dst ) +{ + dst->enable = GL_FALSE; +} + +// --- GLAlphaTestFunc --- +FORCEINLINE void GLContextSet( GLAlphaTestFunc_t *src ) +{ + gGL->glAlphaFunc( src->func, src->ref ); +} + +FORCEINLINE void GLContextGet( GLAlphaTestFunc_t *dst ) +{ + glGetEnumv( GL_ALPHA_TEST_FUNC, &dst->func ); + gGL->glGetFloatv( GL_ALPHA_TEST_REF, &dst->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_ARB, src->enable != 0 ); +} + +FORCEINLINE void GLContextGet( GLAlphaToCoverageEnable_t *dst ) +{ + dst->enable = gGL->glIsEnabled( GL_SAMPLE_ALPHA_TO_COVERAGE_ARB ); +} + +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->glDepthRange ( src->flNear, src->flFar ); +} + +FORCEINLINE void GLContextGet( GLViewportDepthRange_t *dst ) +{ + gGL->glGetDoublev ( 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 ) +{ + gGL->glColorMaskIndexedEXT ( index, src->r, src->g, src->b, src->a ); +} + +FORCEINLINE void GLContextGetIndexed( GLColorMaskMultiple_t *dst, int index ) +{ + gGL->glGetBooleanIndexedvEXT ( GL_COLOR_WRITEMASK, index, (GLboolean*)&dst->r ); +} + +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; + //pfnglGetFramebufferAttachmentParameteriv( 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 = 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->glClearDepth ( src->d ); +} + +FORCEINLINE void GLContextGet( GLClearDepth_t *dst ) +{ + gGL->glGetDoublev ( 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 32 + +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; +}; + +//===========================================================================// + +#ifndef GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD +#define GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD 0x9160 +#endif + +#define GLMGR_PINNED_MEMORY_BUFFER_SIZE ( 6 * 1024 * 1024 ) + +class CPinnedMemoryBuffer +{ + CPinnedMemoryBuffer( const CPinnedMemoryBuffer & ); + CPinnedMemoryBuffer & operator= ( const CPinnedMemoryBuffer & ); + +public: + CPinnedMemoryBuffer() : m_pRawBuf( NULL ), m_pBuf( NULL ), m_nSize( 0 ), m_nOfs( 0 ), m_nBufferObj( 0 ), m_nSyncObj( 0 ) + { + } + + ~CPinnedMemoryBuffer() + { + Deinit(); + } + + bool Init( uint nSize ) + { + Deinit(); + + // Guarantee 64KB alignment + m_pRawBuf = malloc( nSize + 65535 ); + m_pBuf = reinterpret_cast<void *>((reinterpret_cast<uint64>(m_pRawBuf) + 65535) & (~65535)); + m_nSize = nSize; + m_nOfs = 0; + + gGL->glGenBuffersARB( 1, &m_nBufferObj ); + gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj ); + + gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nSize, m_pBuf, GL_STREAM_COPY ); + + return true; + } + + void Deinit() + { + if ( !m_pRawBuf ) + return; + + BlockUntilNotBusy(); + + gGL->glBindBufferARB(GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, m_nBufferObj ); + + gGL->glBufferDataARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0, (void*)NULL, GL_STREAM_COPY ); + + gGL->glBindBufferARB( GL_EXTERNAL_VIRTUAL_MEMORY_BUFFER_AMD, 0 ); + + gGL->glDeleteBuffersARB( 1, &m_nBufferObj ); + m_nBufferObj = 0; + + free( m_pRawBuf ); + m_pRawBuf = NULL; + m_pBuf = NULL; + + m_nSize = 0; + m_nOfs = 0; + } + + inline uint GetSize() const { return m_nSize; } + inline uint GetOfs() const { return m_nOfs; } + inline uint GetBytesRemaining() const { return m_nSize - m_nOfs; } + inline void *GetPtr() const { return m_pBuf; } + inline GLuint GetHandle() const { return m_nBufferObj; } + + void InsertFence() + { + if ( m_nSyncObj ) + { + gGL->glDeleteSync( m_nSyncObj ); + } + + m_nSyncObj = gGL->glFenceSync( GL_SYNC_GPU_COMMANDS_COMPLETE, 0 ); + } + + void BlockUntilNotBusy() + { + if ( m_nSyncObj ) + { + gGL->glClientWaitSync( m_nSyncObj, GL_SYNC_FLUSH_COMMANDS_BIT, 3000000000000ULL ); + + gGL->glDeleteSync( m_nSyncObj ); + + m_nSyncObj = 0; + } + m_nOfs = 0; + } + + void Append( uint nSize ) + { + m_nOfs += nSize; + Assert( m_nOfs <= m_nSize ); + } + +private: + void *m_pRawBuf; + void *m_pBuf; + uint m_nSize; + uint m_nOfs; + + GLuint m_nBufferObj; + + GLsync m_nSyncObj; +}; + +//===========================================================================// + +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, 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 ); + 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 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 + 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 ); + + 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 DWORD 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(); + + FORCEINLINE GLuint FindSamplerObject( const GLMTexSamplingParams &desiredParams ); + + 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->glBindBufferARB( GL_ARRAY_BUFFER_ARB, 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_EXT ); // 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_ARB ) || ( nGLBufType == GL_ELEMENT_ARRAY_BUFFER_ARB ) ); + + const uint nIndex = ( nGLBufType == GL_ARRAY_BUFFER_ARB ) ? kGLMVertexBuffer : kGLMIndexBuffer; + if ( ( bForce ) || ( m_nBoundGLBuffer[nIndex] != nGLName ) ) + { + m_nBoundGLBuffer[nIndex] = nGLName; + gGL->glBindBufferARB( 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 ); + + CPinnedMemoryBuffer *GetCurPinnedMemoryBuffer( ) { return &m_PinnedMemoryBuffers[m_nCurPinnedMemoryBuffer]; } + + // members------------------------------------------ + + // context + DWORD m_nCurOwnerThreadId; + uint m_nThreadOwnershipReleaseCounter; + + bool m_bUseSamplerObjects; + bool m_bPreferMapBufferRange; + + 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... + +#ifdef OSX + CGLPixelFormatAttribute m_pixelFormatAttribs[100]; // more than enough + PseudoNSGLContextPtr m_nsctx; + CGLContextObj m_ctx; +#elif defined( USE_SDL ) + int m_pixelFormatAttribs[100]; // more than enough + PseudoNSGLContextPtr m_nsctx; + void * m_ctx; +#endif + bool m_oneCtxEnable; // true if we use the window's context directly instead of making a second one shared against it + + 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 + + // 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 ]; // two banks, but only the vertex one is used + 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; + + 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; + + enum { cNumPinnedMemoryBuffers = 4 }; + CPinnedMemoryBuffer m_PinnedMemoryBuffers[cNumPinnedMemoryBuffers]; + uint m_nCurPinnedMemoryBuffer; + + 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 +}; + +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*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + } + +#if GLMDEBUG + 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 +} + +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 ) ) + { + if ( ( baseSlot + slotCount ) > DXABSTRACT_VS_FIRST_BONE_SLOT ) + { + if ( baseSlot < DXABSTRACT_VS_FIRST_BONE_SLOT ) + { + // The register set crosses between the constant buffers - should only happen at startup during init. + m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, (int)baseSlot ); + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, (int)MIN( baseSlot + slotCount, DXABSTRACT_VS_FIRST_BONE_SLOT ) ); + baseSlot = DXABSTRACT_VS_FIRST_BONE_SLOT; + } + + int nNumActualBones = ( baseSlot + slotCount ) - DXABSTRACT_VS_FIRST_BONE_SLOT; + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone, nNumActualBones ); + } + else + { + m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = MIN( m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone, (int)baseSlot ); + m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = MAX( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone, (int)(baseSlot + slotCount) ); + } + } + 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 ); + + 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 ) +{ + 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 ) ); + + GLMTexSamplingParams ¶ms = 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; +} + +FORCEINLINE void GLMContext::SetSamplerBorderColor( int sampler, DWORD Value ) +{ + m_samplers[sampler].m_samp.m_borderColor = Value; +} + +FORCEINLINE void GLMContext::SetSamplerMipMapLODBias( int sampler, DWORD Value ) +{ + // not currently supported +} + +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_ARB ) ); + + GLuint nGLName = buff ? buff->m_nHandle : 0; + + if ( m_nBoundGLBuffer[ kGLMIndexBuffer] == nGLName ) + return; + + m_nBoundGLBuffer[ kGLMIndexBuffer] = nGLName; + gGL->glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB, 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_ARB ) ); + + GLuint nGLName = buff ? buff->m_nHandle : 0; + + if ( m_nBoundGLBuffer[ kGLMVertexBuffer] == nGLName ) + return; + + m_nBoundGLBuffer[ kGLMVertexBuffer] = nGLName; + gGL->glBindBufferARB( GL_ARRAY_BUFFER_ARB, 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 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 |