Copy original togl to track changes

This commit is contained in:
nillerusr 2021-11-21 00:48:13 +03:00
parent d947e5e20e
commit 76bfcf40ca
39 changed files with 38554 additions and 0 deletions

View file

@ -0,0 +1,2 @@
#include "togl/linuxwin/glfuncs.h"

View file

@ -0,0 +1,262 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmprogram.h
// GLMgr buffers (index / vertex)
// ... maybe add PBO later as well
//===============================================================================
#ifndef CGLMBUFFER_H
#define CGLMBUFFER_H
#pragma once
//===============================================================================
extern bool g_bUsePseudoBufs;
// forward declarations
class GLMContext;
enum EGLMBufferType
{
kGLMVertexBuffer,
kGLMIndexBuffer,
kGLMUniformBuffer, // for bindable uniform
kGLMPixelBuffer, // for PBO
kGLMNumBufferTypes
};
// pass this in "options" to constructor to make a dynamic buffer
#define GLMBufferOptionDynamic 0x00000001
struct GLMBuffLockParams
{
uint m_nOffset;
uint m_nSize;
bool m_bNoOverwrite;
bool m_bDiscard;
};
#define GL_STATIC_BUFFER_SIZE ( 2048 * 1024 )
#define GL_MAX_STATIC_BUFFERS 2
extern void glBufferSubDataMaxSize( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data, uint nMaxSizePerCall = 128 * 1024 );
//===========================================================================//
// Creates an immutable storage for a buffer object
// https://www.opengl.org/registry/specs/ARB/buffer_storage.txt
class CPersistentBuffer
{
public:
CPersistentBuffer();
~CPersistentBuffer();
void Init( EGLMBufferType type,uint nSize );
void Deinit();
void InsertFence();
void BlockUntilNotBusy();
void Append( uint nSize );
inline uint GetBytesRemaining() const { return m_nSize - m_nOffset; }
inline uint GetOffset() const { return m_nOffset; }
inline void *GetPtr() const { return m_pImmutablePersistentBuf; }
inline GLuint GetHandle() const { return m_nHandle; }
private:
CPersistentBuffer( const CPersistentBuffer & );
CPersistentBuffer & operator= (const CPersistentBuffer &);
uint m_nSize;
EGLMBufferType m_type;
GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB
GLuint m_nHandle; // handle of this program in the GL context
// Holds a pointer to the persistently mapped buffer
void* m_pImmutablePersistentBuf;
uint m_nOffset;
#ifdef HAVE_GL_ARB_SYNC
GLsync m_nSyncObj;
#endif
};
//===============================================================================
#if GL_ENABLE_INDEX_VERIFICATION
struct GLDynamicBuf_t
{
GLenum m_nGLType;
uint m_nHandle;
uint m_nActualBufSize;
uint m_nSize;
uint m_nLockOffset;
uint m_nLockSize;
};
class CGLMBufferSpanManager
{
CGLMBufferSpanManager( const CGLMBufferSpanManager& );
CGLMBufferSpanManager& operator= ( const CGLMBufferSpanManager& );
public:
CGLMBufferSpanManager();
~CGLMBufferSpanManager();
void Init( GLMContext *pContext, EGLMBufferType nBufType, uint nInitialCapacity, uint nBufSize, bool bDynamic );
void Deinit();
inline GLMContext *GetContext() const { return m_pCtx; }
inline GLenum GetGLBufType() const { return ( m_nBufType == kGLMVertexBuffer ) ? GL_ARRAY_BUFFER_ARB : GL_ELEMENT_ARRAY_BUFFER_ARB; }
struct ActiveSpan_t
{
uint m_nStart;
uint m_nEnd;
GLDynamicBuf_t m_buf;
bool m_bOriginalAlloc;
inline ActiveSpan_t() { }
inline ActiveSpan_t( uint nStart, uint nEnd, GLDynamicBuf_t &buf, bool bOriginalAlloc ) : m_nStart( nStart ), m_nEnd( nEnd ), m_buf( buf ), m_bOriginalAlloc( bOriginalAlloc ) { Assert( nStart <= nEnd ); }
};
ActiveSpan_t *AddSpan( uint nOffset, uint nMaxSize, uint nActualSize, bool bDiscard, bool bNoOverwrite );
void DiscardAllSpans();
bool IsValid( uint nOffset, uint nSize ) const;
private:
bool AllocDynamicBuf( uint nSize, GLDynamicBuf_t &buf );
void ReleaseDynamicBuf( GLDynamicBuf_t &buf );
GLMContext *m_pCtx;
EGLMBufferType m_nBufType;
uint m_nBufSize;
bool m_bDynamic;
CUtlVector<ActiveSpan_t> m_ActiveSpans;
CUtlVector<ActiveSpan_t> m_DeletedSpans;
int m_nSpanEndMax;
int m_nNumAllocatedBufs;
int m_nTotalBytesAllocated;
};
#endif // GL_ENABLE_INDEX_VERIFICATION
class CGLMBuffer
{
public:
void Lock( GLMBuffLockParams *pParams, char **pAddressOut );
void Unlock( int nActualSize = -1, const void *pActualData = NULL );
GLuint GetHandle() const;
friend class GLMContext; // only GLMContext can make CGLMBuffer objects
friend class GLMTester;
friend struct IDirect3D9;
friend struct IDirect3DDevice9;
CGLMBuffer( GLMContext *pCtx, EGLMBufferType type, uint size, uint options );
~CGLMBuffer();
void SetModes( bool bAsyncMap, bool bExplicitFlush, bool bForce = false );
void FlushRange( uint offset, uint size );
#if GL_ENABLE_INDEX_VERIFICATION
bool IsSpanValid( uint nOffset, uint nSize ) const;
#endif
GLMContext *m_pCtx; // link back to parent context
EGLMBufferType m_type;
uint m_nSize;
uint m_nActualSize;
bool m_bDynamic;
GLenum m_buffGLTarget; // GL_ARRAY_BUFFER_ARB / GL_ELEMENT_BUFFER_ARB
GLuint m_nHandle; // name of this program in the context
uint m_nRevision; // bump anytime the size changes or buffer is orphaned
bool m_bEnableAsyncMap; // mirror of the buffer state
bool m_bEnableExplicitFlush; // mirror of the buffer state
bool m_bMapped; // is it currently mapped
uint m_dirtyMinOffset; // when equal, range is empty
uint m_dirtyMaxOffset;
float *m_pLastMappedAddress;
int m_nPinnedMemoryOfs;
uint m_nPersistentBufferStartOffset;
bool m_bUsingPersistentBuffer;
bool m_bPseudo; // true if the m_name is 0, and the backing is plain RAM
// in pseudo mode, there is just one RAM buffer that acts as the backing.
// expectation is that this mode would only be used for dynamic indices.
// since indices have to be consumed (copied to command stream) prior to return from a drawing call,
// there's no need to do any fencing or multibuffering. orphaning in particular becomes a no-op.
char *m_pActualPseudoBuf; // storage for pseudo buffer
char *m_pPseudoBuf; // storage for pseudo buffer
char *m_pStaticBuffer;
GLMBuffLockParams m_LockParams;
static char ALIGN16 m_StaticBuffers[ GL_MAX_STATIC_BUFFERS ][ GL_STATIC_BUFFER_SIZE ] ALIGN16_POST;
static bool m_bStaticBufferUsed[ GL_MAX_STATIC_BUFFERS ];
#if GL_ENABLE_INDEX_VERIFICATION
CGLMBufferSpanManager m_BufferSpanManager;
#endif
#if GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION
uint m_nDirtyRangeStart;
uint m_nDirtyRangeEnd;
#endif
};
#endif // CGLMBUFFER_H

View file

@ -0,0 +1,104 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmfbo.h
// GLMgr FBO's (render targets)
//
//===============================================================================
#ifndef CGLMFBO_H
#define CGLMFBO_H
#pragma once
// good FBO references / recaps
// http://www.songho.ca/opengl/gl_fbo.html
// http://www.gamedev.net/reference/articles/article2331.asp
// ext links
// http://www.opengl.org/registry/specs/EXT/framebuffer_object.txt
// http://www.opengl.org/registry/specs/EXT/framebuffer_multisample.txt
//===============================================================================
// tokens not in the SDK headers
#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT
#define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9
#endif
//===============================================================================
// forward declarations
class GLMContext;
enum EGLMFBOAttachment
{
kAttColor0, kAttColor1, kAttColor2, kAttColor3,
kAttDepth, kAttStencil, kAttDepthStencil,
kAttCount
};
struct GLMFBOTexAttachParams
{
CGLMTex *m_tex;
int m_face; // keep zero if not cube map
int m_mip; // keep zero if notmip mapped
int m_zslice; // keep zero if not a 3D tex
};
class CGLMFBO
{
friend class GLMContext;
friend class GLMTester;
friend class CGLMTex;
friend struct IDirect3D9;
friend struct IDirect3DDevice9;
public:
CGLMFBO( GLMContext *ctx );
~CGLMFBO( );
protected:
void TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT );
void TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint = GL_FRAMEBUFFER_EXT );
// you can also pass GL_READ_FRAMEBUFFER_EXT or GL_DRAW_FRAMEBUFFER_EXT to selectively bind the receiving FBO to one or the other.
void TexScrub( CGLMTex *tex );
// search and destroy any attachment for the named texture
bool IsReady( void ); // aka FBO completeness check - ready to draw
GLMContext *m_ctx; // link back to parent context
GLuint m_name; // name of this FBO in the context
GLMFBOTexAttachParams m_attach[ kAttCount ]; // indexed by EGLMFBOAttachment
};
#endif

View file

@ -0,0 +1,458 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmprogram.h
// GLMgr programs (ARBVP/ARBfp)
//
//===============================================================================
#ifndef CGLMPROGRAM_H
#define CGLMPROGRAM_H
#include <sys/stat.h>
#pragma once
// good ARB program references
// http://petewarden.com/notes/archives/2005/05/fragment_progra_2.html
// http://petewarden.com/notes/archives/2005/06/fragment_progra_3.html
// ext links
// http://www.opengl.org/registry/specs/ARB/vertex_program.txt
// http://www.opengl.org/registry/specs/ARB/fragment_program.txt
// http://www.opengl.org/registry/specs/EXT/gpu_program_parameters.txt
//===============================================================================
// tokens not in the SDK headers
//#ifndef GL_DEPTH_STENCIL_ATTACHMENT_EXT
// #define GL_DEPTH_STENCIL_ATTACHMENT_EXT 0x84F9
//#endif
//===============================================================================
// forward declarations
class GLMContext;
class CGLMShaderPair;
class CGLMShaderPairCache;
// CGLMProgram can contain two flavors of the same program, one in assembler, one in GLSL.
// these flavors are pretty different in terms of the API's that are used to activate them -
// for example, assembler programs can just get bound to the context, whereas GLSL programs
// have to be linked. To some extent we try to hide that detail inside GLM.
// for now, make CGLMProgram a container, it does not set policy or hold a preference as to which
// flavor you want to use. GLMContext has to handle that.
enum EGLMProgramType
{
kGLMVertexProgram,
kGLMFragmentProgram,
kGLMNumProgramTypes
};
enum EGLMProgramLang
{
kGLMARB,
kGLMGLSL,
kGLMNumProgramLangs
};
struct GLMShaderDesc
{
union
{
GLuint arb; // ARB program object name
GLhandleARB glsl; // GLSL shader object handle (void*)
} m_object;
// these can change if shader text is edited
bool m_textPresent; // is this flavor(lang) of text present in the buffer?
int m_textOffset; // where is it
int m_textLength; // how big
bool m_compiled; // has this text been through a compile attempt
bool m_valid; // and if so, was the compile successful
int m_slowMark; // has it been flagged during a non native draw batch before. increment every time it's slow.
int m_highWater; // count of vec4's in the major uniform array ("vc" on vs, "pc" on ps)
// written by dxabstract.... gross!
int m_VSHighWaterBone; // count of vec4's in the bone-specific uniform array (only valid for vertex shaders)
};
GLenum GLMProgTypeToARBEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target
GLenum GLMProgTypeToGLSLEnum( EGLMProgramType type ); // map vert/frag to ARB asm bind target
#define GL_SHADER_PAIR_CACHE_STATS 0
class CGLMProgram
{
public:
friend class CGLMShaderPairCache;
friend class CGLMShaderPair;
friend class GLMContext; // only GLMContext can make CGLMProgram objects
friend class GLMTester;
friend struct IDirect3D9;
friend struct IDirect3DDevice9;
//===============================
// constructor is very light, it just makes one empty program object per flavor.
CGLMProgram( GLMContext *ctx, EGLMProgramType type );
~CGLMProgram( );
void SetProgramText ( char *text ); // import text to GLM object - invalidate any prev compiled program
void SetShaderName ( const char *name ); // only used for debugging/telemetry markup
void CompileActiveSources ( void ); // compile only the flavors that were provided.
void Compile ( EGLMProgramLang lang );
bool CheckValidity ( EGLMProgramLang lang );
void LogSlow ( EGLMProgramLang lang ); // detailed spew when called for first time; one liner or perhaps silence after that
void GetLabelIndexCombo ( char *labelOut, int labelOutMaxChars, int *indexOut, int *comboOut );
void GetComboIndexNameString ( char *stringOut, int stringOutMaxChars ); // mmmmmmmm-nnnnnnnn-filename
#if GLMDEBUG
bool PollForChanges( void ); // check mirror for changes.
void ReloadStringFromEditable( void ); // populate m_string from editable item (react to change)
bool SyncWithEditable( void );
#endif
//===============================
// common stuff
GLMContext *m_ctx; // link back to parent context
EGLMProgramType m_type; // vertex or pixel
unsigned long m_nHashTag; // serial number for hashing
char *m_text; // copy of text passed into constructor. Can change if editable shaders is enabled.
// note - it can contain multiple flavors, so use CGLMTextSectioner to scan it and locate them
#if GLMDEBUG
CGLMEditableTextItem *m_editable; // editable text item for debugging
#endif
GLMShaderDesc m_descs[ kGLMNumProgramLangs ];
uint m_samplerMask; // (1<<n) mask of sampler active locs, if this is a fragment shader (dxabstract sets this field)
uint m_samplerTypes; // SAMPLER_2D, etc.
uint m_fragDataMask; // (1<<n) mask of gl_FragData[n] outputs referenced, if this is a fragment shader (dxabstract sets this field)
uint m_numDrawBuffers; // number of draw buffers used
GLenum m_drawBuffers[4]; // GL_COLOR_ATTACHMENT0_EXT1, etc
uint m_nNumUsedSamplers;
uint m_maxSamplers;
uint m_maxVertexAttrs;
uint m_nCentroidMask;
uint m_nShadowDepthSamplerMask;
bool m_bTranslatedProgram;
char m_shaderName[64];
// Cache label string from the shader text
// example:
// trans#2871 label:vs-file vertexlit_and_unlit_generic_vs20 vs-index 294912 vs-combo 1234
char m_labelName[1024];
int m_labelIndex;
int m_labelCombo;
};
//===============================================================================
struct GLMShaderPairInfo
{
int m_status; // -1 means req'd index was out of bounds (loop stop..) 0 means not present. 1 means present/active.
char m_vsName[ 128 ];
int m_vsStaticIndex;
int m_vsDynamicIndex;
char m_psName[ 128 ];
int m_psStaticIndex;
int m_psDynamicIndex;
};
class CGLMShaderPair // a container for a linked GLSL shader pair, and metadata obtained post-link
{
public:
friend class CGLMProgram;
friend class GLMContext;
friend class CGLMShaderPairCache;
//===============================
// constructor just sets up a GLSL program object and leaves it empty.
CGLMShaderPair( GLMContext *ctx );
~CGLMShaderPair( );
bool SetProgramPair ( CGLMProgram *vp, CGLMProgram *fp );
// true result means successful link and query
// Note that checking the link status and querying the uniform can be optionally
// deferred to take advantage of multi-threaded compilation in the driver
bool RefreshProgramPair ( void );
// re-link and re-query the uniforms
bool ValidateProgramPair( void );
// true result means successful link and query
FORCEINLINE void UpdateScreenUniform( uint nWidthHeight )
{
if ( m_nScreenWidthHeight == nWidthHeight )
return;
m_nScreenWidthHeight = nWidthHeight;
float fWidth = (float)( nWidthHeight & 0xFFFF ), fHeight = (float)( nWidthHeight >> 16 );
// Apply half pixel offset to output vertices to account for the pixel center difference between D3D9 and OpenGL.
// We output vertices in clip space, which ranges from [-1,1], so 1.0/width in clip space transforms into .5/width in screenspace, see: "Viewports and Clipping (Direct3D 9)" in the DXSDK
float v[4] = { 1.0f / fWidth, 1.0f / fHeight, fWidth, fHeight };
if ( m_locVertexScreenParams >= 0 )
gGL->glUniform4fv( m_locVertexScreenParams, 1, v );
}
//===============================
// common stuff
GLMContext *m_ctx; // link back to parent context
CGLMProgram *m_vertexProg;
CGLMProgram *m_fragmentProg;
GLhandleARB m_program; // linked program object
// need meta data for attribs / samplers / params
// actually we only need it for samplers and params.
// attributes are hardwired.
// vertex stage uniforms
GLint m_locVertexParams; // "vc" per dx9asmtogl2 convention
GLint m_locVertexBoneParams; // "vcbones"
GLint m_locVertexInteger0; // "i0"
enum { cMaxVertexShaderBoolUniforms = 4, cMaxFragmentShaderBoolUniforms = 1 };
GLint m_locVertexBool[cMaxVertexShaderBoolUniforms]; // "b0", etc.
GLint m_locFragmentBool[cMaxFragmentShaderBoolUniforms]; // "fb0", etc.
bool m_bHasBoolOrIntUniforms;
// fragment stage uniforms
GLint m_locFragmentParams; // "pc" per dx9asmtogl2 convention
int m_NumUniformBufferParams[kGLMNumProgramTypes];
GLint m_UniformBufferParams[kGLMNumProgramTypes][256];
GLint m_locFragmentFakeSRGBEnable; // "flSRGBWrite" - set to 1.0 to effect sRGB encoding on output
float m_fakeSRGBEnableValue; // shadow to avoid redundant sets of the m_locFragmentFakeSRGBEnable uniform
// init it to -1.0 at link or relink, so it will trip on any legit incoming value (0.0 or 1.0)
GLint m_locSamplers[ GLM_SAMPLER_COUNT ]; // "sampler0 ... sampler1..."
// other stuff
bool m_valid; // true on successful link
bool m_bCheckLinkStatus;
uint m_revision; // if this pair is relinked, bump this number.
GLint m_locVertexScreenParams; // vcscreen
uint m_nScreenWidthHeight;
};
//===============================================================================
// N-row, M-way associative cache with LRU per row.
// still needs some metric dump ability and some parameter tuning.
// extra credit would be to make an auto-tuner.
struct CGLMPairCacheEntry
{
long long m_lastMark; // a mark of zero means an empty entry
CGLMProgram *m_vertexProg;
CGLMProgram *m_fragmentProg;
uint m_extraKeyBits;
CGLMShaderPair *m_pair;
};
class CGLMShaderPairCache // cache for linked GLSL shader pairs
{
public:
protected:
friend class CGLMShaderPair;
friend class CGLMProgram;
friend class GLMContext;
//===============================
CGLMShaderPairCache( GLMContext *ctx );
~CGLMShaderPairCache( );
FORCEINLINE CGLMShaderPair *SelectShaderPair ( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits );
void QueryShaderPair ( int index, GLMShaderPairInfo *infoOut );
// shoot down linked pairs that use the program in the arg
// return true if any had to be skipped due to conflict with currently bound pair
bool PurgePairsWithShader( CGLMProgram *prog );
// purge everything (when would GLM know how to do this ? at context destroy time, but any other times?)
// return true if any had to be skipped due to conflict with currently bound pair
bool Purge ( void );
// stats
void DumpStats ( void );
//===============================
FORCEINLINE uint HashRowIndex( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ) const;
FORCEINLINE CGLMPairCacheEntry* HashRowPtr( uint hashRowIndex ) const;
FORCEINLINE void HashRowProbe( CGLMPairCacheEntry *row, CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int &hitway, int &emptyway, int &oldestway );
CGLMShaderPair *SelectShaderPairInternal( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int rowIndex );
//===============================
// common stuff
GLMContext *m_ctx; // link back to parent context
long long m_mark;
uint m_rowsLg2;
uint m_rows;
uint m_rowsMask;
uint m_waysLg2;
uint m_ways;
uint m_entryCount;
CGLMPairCacheEntry *m_entries; // array[ m_rows ][ m_ways ]
uint *m_evictions; // array[ m_rows ];
#if GL_SHADER_PAIR_CACHE_STATS
uint *m_hits; // array[ m_rows ];
#endif
};
FORCEINLINE uint CGLMShaderPairCache::HashRowIndex( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits ) const
{
return ( vp->m_nHashTag + fp->m_nHashTag + extraKeyBits * 7 ) & m_rowsMask;
}
FORCEINLINE CGLMPairCacheEntry* CGLMShaderPairCache::HashRowPtr( uint hashRowIndex ) const
{
return &m_entries[ hashRowIndex * m_ways ];
}
FORCEINLINE void CGLMShaderPairCache::HashRowProbe( CGLMPairCacheEntry *row, CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits, int& hitway, int& emptyway, int& oldestway )
{
hitway = -1;
emptyway = -1;
oldestway = -1;
// scan this row to see if the desired pair is present
CGLMPairCacheEntry *cursor = row;
long long oldestmark = 0xFFFFFFFFFFFFFFFFLL;
for( uint way = 0; way < m_ways; ++way )
{
if ( cursor->m_lastMark != 0 ) // occupied slot
{
// check if this is the oldest one on the row - only occupied slots are checked
if ( cursor->m_lastMark < oldestmark )
{
oldestway = way;
oldestmark = cursor->m_lastMark;
}
if ( ( cursor->m_vertexProg == vp ) && ( cursor->m_fragmentProg == fp ) && ( cursor->m_extraKeyBits == extraKeyBits ) ) // match?
{
// found it
hitway = way;
break;
}
}
else
{
// empty way, log it if first one seen
if (emptyway<0)
{
emptyway = way;
}
}
cursor++;
}
}
FORCEINLINE CGLMShaderPair *CGLMShaderPairCache::SelectShaderPair( CGLMProgram *vp, CGLMProgram *fp, uint extraKeyBits )
{
// select row where pair would be found if it exists
uint rowIndex = HashRowIndex( vp, fp, extraKeyBits );
CGLMPairCacheEntry *pCursor = HashRowPtr( rowIndex );
if ( ( pCursor->m_fragmentProg != fp ) || ( pCursor->m_vertexProg != vp ) || ( pCursor->m_extraKeyBits != extraKeyBits ) )
{
CGLMPairCacheEntry *pLastCursor = pCursor + m_ways;
++pCursor;
while ( pCursor != pLastCursor )
{
if ( ( pCursor->m_fragmentProg == fp ) && ( pCursor->m_vertexProg == vp ) && ( pCursor->m_extraKeyBits == extraKeyBits ) ) // match?
break;
++pCursor;
};
if ( pCursor == pLastCursor )
return SelectShaderPairInternal( vp, fp, extraKeyBits, rowIndex );
}
// found it. mark it and return
pCursor->m_lastMark = m_mark++;
#if GL_SHADER_PAIR_CACHE_STATS
// count the hit
m_hits[ rowIndex ] ++;
#endif
return pCursor->m_pair;
}
#endif

View file

@ -0,0 +1,108 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmquery.h
// GLMgr queries
//
//===============================================================================
#ifndef CGLMQUERY_H
#define CGLMQUERY_H
#pragma once
//===============================================================================
// forward declarations
class GLMContext;
class CGLMQuery;
//===============================================================================
enum EGLMQueryType
{
EOcclusion,
EFence,
EGLMQueryCount
};
struct GLMQueryParams
{
EGLMQueryType m_type;
};
class CGLMQuery
{
// leave everything public til it's running
public:
friend class GLMContext; // only GLMContext can make CGLMTex objects
friend struct IDirect3DDevice9;
friend struct IDirect3DQuery9;
GLMContext *m_ctx; // link back to parent context
GLMQueryParams m_params; // params created with
GLuint m_name; // name of the query object per se - could be fence, could be query object ... NOT USED WITH GL_ARB_sync!
#ifdef HAVE_GL_ARB_SYNC
GLsync m_syncobj; // GL_ARB_sync object. NOT USED WITH GL_NV_fence or GL_APPLE_fence!
#else
GLuint m_syncobj;
#endif
bool m_started;
bool m_stopped;
bool m_done;
bool m_nullQuery; // was gl_nullqueries true at Start time - if so, continue to act like a null query through Stop/IsDone/Complete time
// restated - only Start should examine the convar.
static uint s_nTotalOcclusionQueryCreatesOrDeletes;
CGLMQuery( GLMContext *ctx, GLMQueryParams *params );
~CGLMQuery( );
// for an occlusion query:
// Start = BeginQuery query-start goes into stream
// Stop = EndQuery query-end goes into stream - a fence is also set so we can probe for completion
// IsDone = TestFence use the added fence to ask if query-end has passed (i.e. will Complete block?)
// Complete = GetQueryObjectuivARB(uint id, enum pname, uint *params) - extract the sample count
// for a fence query:
// Start = SetFence fence goes into command stream
// Stop = NOP fences are self finishing - no need to call Stop on a fence
// IsDone = TestFence ask if fence passed
// Complete = FinishFence
void Start ( void );
void Stop ( void );
bool IsDone ( void );
void Complete ( uint *result );
// accessors for the started/stopped state
bool IsStarted ( void );
bool IsStopped ( void );
};
#endif

View file

@ -0,0 +1,547 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmtex.h
// GLMgr textures
//
//===============================================================================
#ifndef CGLMTEX_H
#define CGLMTEX_H
#pragma once
#ifdef OSX
#include "glmgrbasics.h"
#endif
#include "tier1/utlhash.h"
#include "tier1/utlmap.h"
//===============================================================================
// forward declarations
class GLMContext;
class GLMTester;
class CGLMTexLayoutTable;
class CGLMTex;
class CGLMFBO;
struct IDirect3DSurface9;
#if GLMDEBUG
extern CGLMTex *g_pFirstCGMLTex;
#endif
// For GL_EXT_texture_sRGB_decode
#ifndef GL_TEXTURE_SRGB_DECODE_EXT
#define GL_TEXTURE_SRGB_DECODE_EXT 0x8A48
#endif
#ifndef GL_DECODE_EXT
#define GL_DECODE_EXT 0x8A49
#endif
#ifndef GL_SKIP_DECODE_EXT
#define GL_SKIP_DECODE_EXT 0x8A4A
#endif
//===============================================================================
struct GLMTexFormatDesc
{
const char *m_formatSummary; // for debug visibility
D3DFORMAT m_d3dFormat; // what D3D knows it as; see public/bitmap/imageformat.h
GLenum m_glIntFormat; // GL internal format
GLenum m_glIntFormatSRGB; // internal format if SRGB flavor
GLenum m_glDataFormat; // GL data format
GLenum m_glDataType; // GL data type
int m_chunkSize; // 1 or 4 - 4 is used for compressed textures
int m_bytesPerSquareChunk; // how many bytes for the smallest quantum (m_chunkSize x m_chunkSize)
// this description lets us calculate size cleanly without conditional logic for compression
};
const GLMTexFormatDesc *GetFormatDesc( D3DFORMAT format );
//===============================================================================
// utility function for generating slabs of texels. mostly for test.
typedef struct
{
// in
D3DFORMAT m_format;
void *m_dest; // dest address
int m_chunkCount; // square chunk count (single texels or compressed blocks)
int m_byteCountLimit; // caller expectation of max number of bytes to write out
float r,g,b,a; // color desired
// out
int m_bytesWritten;
} GLMGenTexelParams;
// return true if successful
bool GLMGenTexels( GLMGenTexelParams *params );
//===============================================================================
struct GLMTexLayoutSlice
{
int m_xSize,m_ySize,m_zSize; //texel dimensions of this slice
int m_storageOffset; //where in the storage slab does this slice live
int m_storageSize; //how much storage does this slice occupy
};
enum EGLMTexFlags
{
kGLMTexMipped = 0x01,
kGLMTexMippedAuto = 0x02,
kGLMTexRenderable = 0x04,
kGLMTexIsStencil = 0x08,
kGLMTexIsDepth = 0x10,
kGLMTexSRGB = 0x20,
kGLMTexMultisampled = 0x40, // has an RBO backing it. Cannot combine with Mipped, MippedAuto. One slice maximum, only targeting GL_TEXTURE_2D.
// actually not 100% positive on the mipmapping, the RBO itself can't be mipped, but the resulting texture could
// have mipmaps generated.
};
//===============================================================================
struct GLMTexLayoutKey
{
// input values: held const, these are the hash key for the form map
GLenum m_texGLTarget; // flavor of texture: GL_TEXTURE_2D, GL_TEXTURE_3D, GLTEXTURE_CUBE_MAP
D3DFORMAT m_texFormat; // D3D texel format
unsigned long m_texFlags; // mipped, autogen mips, render target, ... ?
unsigned long m_texSamples; // zero for a plain tex, 2/4/6/8 for "MSAA tex" (RBO backed)
int m_xSize,m_ySize,m_zSize; // size of base mip
};
bool LessFunc_GLMTexLayoutKey( const GLMTexLayoutKey &a, const GLMTexLayoutKey &b );
#define GLM_TEX_MAX_MIPS 14
#define GLM_TEX_MAX_FACES 6
#define GLM_TEX_MAX_SLICES (GLM_TEX_MAX_MIPS * GLM_TEX_MAX_FACES)
#pragma warning( push )
#pragma warning( disable : 4200 )
struct GLMTexLayout
{
char *m_layoutSummary; // for debug visibility
// const inputs used for hashing
GLMTexLayoutKey m_key;
// refcount
int m_refCount;
// derived values:
GLMTexFormatDesc *m_format; // format specific info
int m_mipCount; // derived by starying at base size and working down towards 1x1
int m_faceCount; // 1 for 2d/3d, 6 for cubemap
int m_sliceCount; // product of faces and mips
int m_storageTotalSize; // size of storage slab required
// slice array
GLMTexLayoutSlice m_slices[0]; // dynamically allocated 2-d array [faces][mips]
};
#pragma warning( pop )
class CGLMTexLayoutTable
{
public:
CGLMTexLayoutTable();
GLMTexLayout *NewLayoutRef( GLMTexLayoutKey *pDesiredKey ); // pass in a pointer to layout key - receive ptr to completed layout
void DelLayoutRef( GLMTexLayout *layout ); // pass in pointer to completed layout. refcount is dropped.
void DumpStats( void );
protected:
CUtlMap< GLMTexLayoutKey, GLMTexLayout* > m_layoutMap;
};
//===============================================================================
// a sampler specifies desired state for drawing on a given sampler index
// this is the combination of a texture choice and a set of sampler parameters
// see http://msdn.microsoft.com/en-us/library/bb172602(VS.85).aspx
struct GLMTexLockParams
{
// input params which identify the slice of interest
CGLMTex *m_tex;
int m_face;
int m_mip;
// identifies the region of the slice
GLMRegion m_region;
// tells GLM to force re-read of the texels back from GL
// i.e. "I know I stepped on those texels with a draw or blit - the GLM copy is stale"
bool m_readback;
};
struct GLMTexLockDesc
{
GLMTexLockParams m_req; // form of the lock request
bool m_active; // set true at lock time. cleared at unlock time.
int m_sliceIndex; // which slice in the layout
int m_sliceBaseOffset; // where is that in the texture data
int m_sliceRegionOffset; // offset to the start (lowest address corner) of the region requested
};
//===============================================================================
#define GLM_SAMPLER_COUNT 16
#define GLM_MAX_PIXEL_TEX_SAMPLERS 16
#define GLM_MAX_VERTEX_TEX_SAMPLERS 0
typedef CBitVec<GLM_SAMPLER_COUNT> CTexBindMask;
enum EGLMTexSliceFlag
{
kSliceValid = 0x01, // slice has been teximage'd in whole at least once - set to 0 initially
kSliceStorageValid = 0x02, // if backing store is available, this slice's data is a valid copy - set to 0 initially
kSliceLocked = 0x04, // are one or more locks outstanding on this slice
kSliceFullyDirty = 0x08, // does the slice need to be fully downloaded at unlock time (disregard dirty rects)
};
//===============================================================================
#define GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS (2)
#define GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS (2)
#define GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS (2)
#define GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS (2)
#define GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS (4)
#define GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS (5)
#define GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS (1)
#define GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS (1)
struct GLMTexPackedSamplingParams
{
uint32 m_addressU : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS;
uint32 m_addressV : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS;
uint32 m_addressW : GLM_PACKED_SAMPLER_PARAMS_ADDRESS_BITS;
uint32 m_minFilter : GLM_PACKED_SAMPLER_PARAMS_MIN_FILTER_BITS;
uint32 m_magFilter : GLM_PACKED_SAMPLER_PARAMS_MAG_FILTER_BITS;
uint32 m_mipFilter : GLM_PACKED_SAMPLER_PARAMS_MIP_FILTER_BITS;
uint32 m_minLOD : GLM_PACKED_SAMPLER_PARAMS_MIN_LOD_BITS;
uint32 m_maxAniso : GLM_PACKED_SAMPLER_PARAMS_MAX_ANISO_BITS;
uint32 m_compareMode : GLM_PACKED_SAMPLER_PARAMS_COMPARE_MODE_BITS;
uint32 m_srgb : GLM_PACKED_SAMPLER_PARAMS_SRGB_BITS;
uint32 m_isValid : 1;
};
struct GLMTexSamplingParams
{
union
{
GLMTexPackedSamplingParams m_packed;
uint32 m_bits;
};
uint32 m_borderColor;
float m_lodBias;
FORCEINLINE bool operator== (const GLMTexSamplingParams& rhs ) const
{
return ( m_bits == rhs.m_bits ) && ( m_borderColor == rhs.m_borderColor ) && ( m_lodBias == rhs.m_lodBias );
}
FORCEINLINE void SetToDefaults()
{
m_bits = 0;
m_borderColor = 0;
m_lodBias = 0.0f;
m_packed.m_addressU = D3DTADDRESS_WRAP;
m_packed.m_addressV = D3DTADDRESS_WRAP;
m_packed.m_addressW = D3DTADDRESS_WRAP;
m_packed.m_minFilter = D3DTEXF_POINT;
m_packed.m_magFilter = D3DTEXF_POINT;
m_packed.m_mipFilter = D3DTEXF_NONE;
m_packed.m_maxAniso = 1;
m_packed.m_compareMode = 0;
m_packed.m_isValid = true;
}
#ifndef OSX
FORCEINLINE void SetToSamplerObject( GLuint nSamplerObject ) const
{
static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 };
static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR };
static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter].
{
/* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT
/* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling
};
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso );
float flBorderColor[4] = { 0, 0, 0, 0 };
if ( m_borderColor )
{
flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R
flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G
flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B
flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A
}
gGL->glSamplerParameterfv( nSamplerObject, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD );
gGL->glSamplerParameterfv( nSamplerObject, GL_TEXTURE_LOD_BIAS, &m_lodBias );
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE );
gGL->glSamplerParameterf( nSamplerObject, GL_TEXTURE_LOD_BIAS, m_lodBias );
if ( m_packed.m_compareMode )
{
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
}
if ( gGL->m_bHave_GL_EXT_texture_sRGB_decode )
{
gGL->glSamplerParameteri( nSamplerObject, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT );
}
}
#endif // !OSX
inline void DeltaSetToTarget( GLenum target, const GLMTexSamplingParams &curState )
{
static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 };
static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR };
static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter].
{
/* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT
/* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling
};
if ( m_packed.m_addressU != curState.m_packed.m_addressU )
{
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] );
}
if ( m_packed.m_addressV != curState.m_packed.m_addressV )
{
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] );
}
if ( m_packed.m_addressW != curState.m_packed.m_addressW )
{
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] );
}
if ( ( m_packed.m_minFilter != curState.m_packed.m_minFilter ) ||
( m_packed.m_magFilter != curState.m_packed.m_magFilter ) ||
( m_packed.m_mipFilter != curState.m_packed.m_mipFilter ) ||
( m_packed.m_maxAniso != curState.m_packed.m_maxAniso ) )
{
gGL->glTexParameteri( target, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] );
gGL->glTexParameteri( target, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] );
gGL->glTexParameteri( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso );
}
if ( m_borderColor != curState.m_borderColor )
{
float flBorderColor[4] = { 0, 0, 0, 0 };
if ( m_borderColor )
{
flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R
flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G
flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B
flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A
}
gGL->glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out
}
if ( m_packed.m_minLOD != curState.m_packed.m_minLOD )
{
gGL->glTexParameteri( target, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD );
}
if ( m_lodBias != curState.m_lodBias )
{
// Could use TexParameterf instead, but we don't currently grab it. This works fine, too.
gGL->glTexParameterfv( target, GL_TEXTURE_LOD_BIAS, &m_lodBias );
}
if ( m_packed.m_compareMode != curState.m_packed.m_compareMode )
{
gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE );
if ( m_packed.m_compareMode )
{
gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
}
}
if ( ( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) && ( m_packed.m_srgb != curState.m_packed.m_srgb ) )
{
gGL->glTexParameteri( target, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT );
}
}
inline void SetToTarget( GLenum target )
{
static const GLenum dxtogl_addressMode[] = { GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER, (GLenum)-1 };
static const GLenum dxtogl_magFilter[4] = { GL_NEAREST, GL_NEAREST, GL_LINEAR, GL_LINEAR };
static const GLenum dxtogl_minFilter[4][4] = // indexed by _D3DTEXTUREFILTERTYPE on both axes: [row is min filter][col is mip filter].
{
/* min = D3DTEXF_NONE */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 }, // D3DTEXF_NONE we just treat like POINT
/* min = D3DTEXF_POINT */ { GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_LINEAR */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 },
/* min = D3DTEXF_ANISOTROPIC */ { GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, (GLenum)-1 }, // no diff from prior row, set maxAniso to effect the sampling
};
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_S, dxtogl_addressMode[m_packed.m_addressU] );
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_T, dxtogl_addressMode[m_packed.m_addressV] );
gGL->glTexParameteri( target, GL_TEXTURE_WRAP_R, dxtogl_addressMode[m_packed.m_addressW] );
gGL->glTexParameteri( target, GL_TEXTURE_MIN_FILTER, dxtogl_minFilter[m_packed.m_minFilter][m_packed.m_mipFilter] );
gGL->glTexParameteri( target, GL_TEXTURE_MAG_FILTER, dxtogl_magFilter[m_packed.m_magFilter] );
gGL->glTexParameteri( target, GL_TEXTURE_MAX_ANISOTROPY_EXT, m_packed.m_maxAniso );
float flBorderColor[4] = { 0, 0, 0, 0 };
if ( m_borderColor )
{
flBorderColor[0] = ((m_borderColor >> 16) & 0xFF) * (1.0f/255.0f); //R
flBorderColor[1] = ((m_borderColor >> 8) & 0xFF) * (1.0f/255.0f); //G
flBorderColor[2] = ((m_borderColor ) & 0xFF) * (1.0f/255.0f); //B
flBorderColor[3] = ((m_borderColor >> 24) & 0xFF) * (1.0f/255.0f); //A
}
gGL->glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, flBorderColor ); // <-- this crashes ATI's driver, remark it out
gGL->glTexParameteri( target, GL_TEXTURE_MIN_LOD, m_packed.m_minLOD );
gGL->glTexParameterfv( target, GL_TEXTURE_LOD_BIAS, &m_lodBias );
gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_MODE_ARB, m_packed.m_compareMode ? GL_COMPARE_R_TO_TEXTURE_ARB : GL_NONE );
if ( m_packed.m_compareMode )
{
gGL->glTexParameteri( target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL );
}
if ( gGL->m_bHave_GL_EXT_texture_sRGB_decode )
{
gGL->glTexParameteri( target, GL_TEXTURE_SRGB_DECODE_EXT, m_packed.m_srgb ? GL_DECODE_EXT : GL_SKIP_DECODE_EXT );
}
}
};
//===============================================================================
class CGLMTex
{
public:
void Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut, int *zStrideOut );
void Unlock( GLMTexLockParams *params );
GLuint GetTexName() { return m_texName; }
protected:
friend class GLMContext; // only GLMContext can make CGLMTex objects
friend class GLMTester;
friend class CGLMFBO;
friend struct IDirect3DDevice9;
friend struct IDirect3DBaseTexture9;
friend struct IDirect3DTexture9;
friend struct IDirect3DSurface9;
friend struct IDirect3DCubeTexture9;
friend struct IDirect3DVolumeTexture9;
CGLMTex( GLMContext *ctx, GLMTexLayout *layout, uint levels, const char *debugLabel = NULL );
~CGLMTex( );
int CalcSliceIndex( int face, int mip );
void CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut );
void ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true );
void WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice=true, bool noDataWrite=false );
// last param lets us send NULL data ptr (only legal with uncompressed formats, beware)
// this helps out ResetSRGB.
#if defined( OSX )
void HandleSRGBMismatch( bool srgb, int &srgbFlipCount );
void ResetSRGB( bool srgb, bool noDataWrite );
// re-specify texture format to match desired sRGB form
// noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's
#endif
bool IsRBODirty() const;
void ForceRBONonDirty();
void ForceRBODirty();
// re-specify texture format to match desired sRGB form
// noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's
GLuint m_texName; // name of this texture in the context
GLenum m_texGLTarget;
uint m_nSamplerType; // SAMPLER_2D, etc.
GLMTexSamplingParams m_SamplingParams;
GLMTexLayout *m_layout; // layout of texture (shared across all tex with same layout)
uint m_nLastResolvedBatchCounter;
int m_minActiveMip;//index of lowest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL.
int m_maxActiveMip;//index of highest mip that has been written. used to drive setting of GL_TEXTURE_MAX_LEVEL.
GLMContext *m_ctx; // link back to parent context
CGLMFBO *m_pBlitSrcFBO;
CGLMFBO *m_pBlitDstFBO;
GLuint m_rboName; // name of MSAA RBO backing the tex if MSAA enabled (or zero)
int m_rtAttachCount; // how many RT's have this texture attached somewhere
char *m_backing; // backing storage if available
int m_lockCount; // lock reqs are stored in the GLMContext for tracking
CUtlVector<unsigned char> m_sliceFlags;
char *m_debugLabel; // strdup() of debugLabel passed in, or NULL
bool m_texClientStorage; // was CS selected for texture
bool m_texPreloaded; // has it been kicked into VRAM with GLMContext::PreloadTex yet
int m_srgbFlipCount;
#if GLMDEBUG
CGLMTex *m_pPrevTex;
CGLMTex *m_pNextTex;
#endif
};
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,117 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glbase.h
//
//===============================================================================
#ifndef GLBASE_H
#define GLBASE_H
#ifdef DX_TO_GL_ABSTRACTION
#undef HAVE_GL_ARB_SYNC
#ifndef OSX
#define HAVE_GL_ARB_SYNC 1
#endif
#ifdef USE_SDL
#include "SDL_opengl.h"
#endif
#ifdef OSX
#include <OpenGL/CGLCurrent.h>
#include <ApplicationServices/ApplicationServices.h>
#endif
#ifdef DX_TO_GL_ABSTRACTION
#ifndef WIN32
#define Debugger DebuggerBreak
#endif
#undef CurrentTime
#if defined( USE_SDL )
#include "SDL.h"
#endif
#endif
//===============================================================================
// glue to call out to Obj-C land (these are in glmgrcocoa.mm)
#ifdef OSX
typedef void _PseudoNSGLContext; // aka NSOpenGLContext
typedef _PseudoNSGLContext *PseudoNSGLContextPtr;
CGLContextObj GetCGLContextFromNSGL( PseudoNSGLContextPtr nsglCtx );
#endif
// Set TOGL_SUPPORT_NULL_DEVICE to 1 to support the NULL ref device
#define TOGL_SUPPORT_NULL_DEVICE 0
#if TOGL_SUPPORT_NULL_DEVICE
#define TOGL_NULL_DEVICE_CHECK if( m_params.m_deviceType == D3DDEVTYPE_NULLREF ) return S_OK;
#define TOGL_NULL_DEVICE_CHECK_RET_VOID if( m_params.m_deviceType == D3DDEVTYPE_NULLREF ) return;
#else
#define TOGL_NULL_DEVICE_CHECK
#define TOGL_NULL_DEVICE_CHECK_RET_VOID
#endif
// GL_ENABLE_INDEX_VERIFICATION enables index range verification on all dynamic IB/VB's (obviously slow)
#define GL_ENABLE_INDEX_VERIFICATION 0
// GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION (currently win32 only) - If 1, VirtualAlloc/VirtualProtect is used to detect cases where the app locks a buffer, copies the ptr away, unlocks, then tries to later write to the buffer.
#define GL_ENABLE_UNLOCK_BUFFER_OVERWRITE_DETECTION 0
#define GL_BATCH_TELEMETRY_ZONES 0
// GL_BATCH_PERF_ANALYSIS - Enables gl_batch_vis, and various per-batch telemetry statistics messages.
#define GL_BATCH_PERF_ANALYSIS 0
#define GL_BATCH_PERF_ANALYSIS_WRITE_PNGS 0
// GL_TELEMETRY_ZONES - Causes every single OpenGL call to generate a telemetry event
#define GL_TELEMETRY_ZONES 0
// GL_DUMP_ALL_API_CALLS - Causes a debug message to be printed for every API call if s_bDumpCalls bool is set to 1
#define GL_DUMP_ALL_API_CALLS 0
// Must also enable PIX_ENABLE to use GL_TELEMETRY_GPU_ZONES.
#define GL_TELEMETRY_GPU_ZONES 0
// Records global # of OpenGL calls/total cycles spent inside GL
#define GL_TRACK_API_TIME GL_BATCH_PERF_ANALYSIS
#define GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS ( GL_TELEMETRY_ZONES || GL_TRACK_API_TIME || GL_DUMP_ALL_API_CALLS )
#if GL_BATCH_PERF_ANALYSIS
#define GL_BATCH_PERF(...) __VA_ARGS__
#else
#define GL_BATCH_PERF(...)
#endif
#define kGLMUserClipPlanes 2
#define kGLMScratchFBOCount 4
#endif // DX_TO_GL_ABSTRACTION
#endif // GLBASE_H

View file

@ -0,0 +1,403 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glentrypoints.h
//
//===============================================================================
#ifndef GLENTRYPOINTS_H
#define GLENTRYPOINTS_H
#pragma once
#ifdef DX_TO_GL_ABSTRACTION
#include "tier0/platform.h"
#include "tier0/vprof_telemetry.h"
#include "interface.h"
#include "togl/rendermechanism.h"
void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired, void *fallback=NULL);
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
class CGLExecuteHelperBase
{
public:
inline void StartCall(const char *pName);
inline void StopCall(const char *pName);
#if GL_TRACK_API_TIME
TmU64 m_nStartTime;
#endif
};
template < class FunctionType, typename Result >
class CGLExecuteHelper : public CGLExecuteHelperBase
{
public:
inline CGLExecuteHelper(FunctionType pFn, const char *pName ) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(); StopCall(pName); }
template<typename A> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a); StopCall(pName); }
template<typename A, typename B> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b); StopCall(pName); }
template<typename A, typename B, typename C> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c); StopCall(pName); }
template<typename A, typename B, typename C, typename D> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) : m_pFn( pFn ) { StartCall(pName); m_Result = (*m_pFn)(a, b, c, d, e, f, g, h, i, j); StopCall(pName); }
inline operator Result() const { return m_Result; }
inline operator char*() const { return (char*)m_Result; }
FunctionType m_pFn;
Result m_Result;
};
template < class FunctionType>
class CGLExecuteHelper<FunctionType, void> : public CGLExecuteHelperBase
{
public:
inline CGLExecuteHelper(FunctionType pFn, const char *pName ) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(); StopCall(pName); }
template<typename A> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a); StopCall(pName); }
template<typename A, typename B> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b); StopCall(pName); }
template<typename A, typename B, typename C> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c); StopCall(pName); }
template<typename A, typename B, typename C, typename D> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h, i); StopCall(pName); }
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J> inline CGLExecuteHelper(FunctionType pFn, const char *pName, A a, B b, C c, D d, E e, F f, G g, H h, I i, J j) : m_pFn( pFn ) { StartCall(pName); (*m_pFn)(a, b, c, d, e, f, g, h, i, j); StopCall(pName); }
FunctionType m_pFn;
};
#endif
template < class FunctionType, typename Result >
class CDynamicFunctionOpenGLBase
{
public:
// Construct with a NULL function pointer. You must manually call
// Lookup() before you can call a dynamic function through this interface.
CDynamicFunctionOpenGLBase() : m_pFn(NULL) {}
// Construct and do a lookup right away. You will need to make sure that
// the lookup actually succeeded, as the gl library might have failed to load
// or (fn) might not exist in it.
CDynamicFunctionOpenGLBase(const char *fn, FunctionType fallback=NULL) : m_pFn(NULL)
{
Lookup(fn, fallback);
}
// Construct and do a lookup right away. See comments in Lookup() about what (okay) does.
CDynamicFunctionOpenGLBase(const char *fn, bool &okay, FunctionType fallback=NULL) : m_pFn(NULL)
{
Lookup(fn, okay, fallback);
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// This allows you to chain lookups like this:
// bool okay = true;
// x.Lookup(lib, "x", okay);
// y.Lookup(lib, "y", okay);
// z.Lookup(lib, "z", okay);
// if (okay) { printf("All functions were loaded successfully!\n"); }
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return (okay)).
bool Lookup(const char *fn, bool &okay, FunctionType fallback=NULL)
{
if (!okay)
return false;
else if (this->m_pFn == NULL)
{
this->m_pFn = (FunctionType) VoidFnPtrLookup_GlMgr(fn, okay, false, (void *) fallback);
this->SetFuncName( fn );
}
okay = m_pFn != NULL;
return okay;
}
// Load library if necessary, look up symbol. Returns true and sets
// m_pFn on successful lookup, returns false otherwise. If the
// function pointer is already looked up, this return true immediately.
// Use Reset() first if you want to look up the symbol again.
// This function will return false immediately unless (okay) is true.
// If you supply a fallback, it'll be used if the lookup fails (and if
// non-NULL, means this will always return true).
bool Lookup(const char *fn, FunctionType fallback=NULL)
{
bool okay = true;
return Lookup(fn, okay, fallback);
}
// Invalidates the current lookup. Makes the function pointer NULL. You
// will need to call Lookup() before you can call a dynamic function
// through this interface again.
void Reset() { m_pFn = NULL; }
// Force this to be a specific function pointer.
void Force(FunctionType ptr) { m_pFn = ptr; }
// Retrieve the actual function pointer.
FunctionType Pointer() const { return m_pFn; }
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
#if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS
#define GL_FUNC_NAME m_szName
#else
#define GL_FUNC_NAME ""
#endif
inline CGLExecuteHelper<FunctionType, Result> operator() () const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME ); }
template<typename T>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a); }
template<typename T, typename U>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b); }
template<typename T, typename U, typename V>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c ) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c); }
template<typename T, typename U, typename V, typename W>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d); }
template<typename T, typename U, typename V, typename W, typename X>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e); }
template<typename T, typename U, typename V, typename W, typename X, typename Y>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e, Y f) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f); }
template<typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e, Y f, Z g) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g); }
template<typename T, typename U, typename V, typename W, typename X, typename Y, typename Z, typename A>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e, Y f, Z g, A h) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h); }
template<typename T, typename U, typename V, typename W, typename X, typename Y, typename Z, typename A, typename B>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e, Y f, Z g, A h, B i) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h, i); }
template<typename T, typename U, typename V, typename W, typename X, typename Y, typename Z, typename A, typename B, typename C>
inline CGLExecuteHelper<FunctionType, Result> operator() (T a, U b, V c, W d, X e, Y f, Z g, A h, B i, C j) const { return CGLExecuteHelper<FunctionType, Result>(m_pFn, GL_FUNC_NAME, a, b, c, d, e, f, g, h, i, j); }
#else
operator FunctionType() const { return m_pFn; }
#endif
// Can be used to verify that we have an actual function looked up and
// ready to call: if (!MyDynFunc) { printf("Function not found!\n"); }
operator bool () const { return m_pFn != NULL; }
bool operator !() const { return m_pFn == NULL; }
protected:
FunctionType m_pFn;
#if GL_TELEMETRY_ZONES || GL_DUMP_ALL_API_CALLS
char m_szName[32];
inline void SetFuncName(const char *pFn) { V_strncpy( m_szName, pFn, sizeof( m_szName ) ); }
#else
inline void SetFuncName(const char *pFn) { (void)pFn; }
#endif
};
// This works a lot like CDynamicFunctionMustInit, but we use SDL_GL_GetProcAddress().
template < const bool bRequired, class FunctionType, typename Result >
class CDynamicFunctionOpenGL : public CDynamicFunctionOpenGLBase< FunctionType, Result >
{
private: // forbid default constructor.
CDynamicFunctionOpenGL() {}
public:
CDynamicFunctionOpenGL(const char *fn, FunctionType fallback=NULL)
{
bool okay = true;
Lookup(fn, okay, fallback);
this->SetFuncName( fn );
}
CDynamicFunctionOpenGL(const char *fn, bool &okay, FunctionType fallback=NULL)
{
Lookup(fn, okay, fallback);
this->SetFuncName( fn );
}
// Please note this is not virtual.
// !!! FIXME: we might want to fall back and try "EXT" or "ARB" versions in some case.
bool Lookup(const char *fn, bool &okay, FunctionType fallback=NULL)
{
if (this->m_pFn == NULL)
{
this->m_pFn = (FunctionType) VoidFnPtrLookup_GlMgr(fn, okay, bRequired, (void *) fallback);
this->SetFuncName( fn );
}
return okay;
}
};
enum GLDriverStrings_t
{
cGLVendorString,
cGLRendererString,
cGLVersionString,
cGLExtensionsString,
cGLTotalDriverStrings
};
enum GLDriverProvider_t
{
cGLDriverProviderUnknown,
cGLDriverProviderNVIDIA,
cGLDriverProviderAMD,
cGLDriverProviderIntel,
cGLDriverProviderIntelOpenSource,
cGLDriverProviderApple,
cGLTotalDriverProviders
};
// This provides all the entry points for a given OpenGL context.
// ENTRY POINTS ARE ONLY VALID FOR THE CONTEXT THAT WAS CURRENT WHEN
// YOU LOOKED THEM UP. 99% of the time, this is not a problem, but
// that 1% is really hard to track down. Always access the GL
// through this class!
class COpenGLEntryPoints
{
COpenGLEntryPoints( const COpenGLEntryPoints & );
COpenGLEntryPoints &operator= ( const COpenGLEntryPoints & );
public:
// The GL context you are looking up entry points for must be current when you construct this object!
COpenGLEntryPoints();
~COpenGLEntryPoints();
void ClearEntryPoints();
uint64 m_nTotalGLCycles, m_nTotalGLCalls;
int m_nOpenGLVersionMajor; // if GL_VERSION is 2.1.0, this will be set to 2.
int m_nOpenGLVersionMinor; // if GL_VERSION is 2.1.0, this will be set to 1.
int m_nOpenGLVersionPatch; // if GL_VERSION is 2.1.0, this will be set to 0.
bool m_bHave_OpenGL;
char *m_pGLDriverStrings[cGLTotalDriverStrings];
GLDriverProvider_t m_nDriverProvider;
#ifdef OSX
#define GL_EXT(x,glmajor,glminor) bool m_bHave_##x;
#define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (*) arg, ret > fn;
#define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (*) arg, void > fn;
#else
#define GL_EXT(x,glmajor,glminor) bool m_bHave_##x;
#define GL_FUNC(ext,req,ret,fn,arg,call) CDynamicFunctionOpenGL< req, ret (APIENTRY *) arg, ret > fn;
#define GL_FUNC_VOID(ext,req,fn,arg,call) CDynamicFunctionOpenGL< req, void (APIENTRY *) arg, void > fn;
#endif
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
bool HasSwapTearExtension() const
{
#ifdef _WIN32
return m_bHave_WGL_EXT_swap_control_tear;
#else
return m_bHave_GLX_EXT_swap_control_tear;
#endif
}
};
// This will be set to the current OpenGL context's entry points.
extern COpenGLEntryPoints *gGL;
typedef void * (*GL_GetProcAddressCallbackFunc_t)(const char *, bool &, const bool, void *);
#ifdef TOGL_DLL_EXPORT
DLL_EXPORT COpenGLEntryPoints *ToGLConnectLibraries( CreateInterfaceFn factory );
DLL_EXPORT void ToGLDisconnectLibraries();
DLL_EXPORT COpenGLEntryPoints *GetOpenGLEntryPoints(GL_GetProcAddressCallbackFunc_t callback);
DLL_EXPORT void ClearOpenGLEntryPoints();
#else
DLL_IMPORT COpenGLEntryPoints *ToGLConnectLibraries( CreateInterfaceFn factory );
DLL_IMPORT void ToGLDisconnectLibraries();
DLL_IMPORT COpenGLEntryPoints *GetOpenGLEntryPoints(GL_GetProcAddressCallbackFunc_t callback);
DLL_IMPORT void ClearOpenGLEntryPoints();
#endif
#if GL_USE_EXECUTE_HELPER_FOR_ALL_API_CALLS
inline void CGLExecuteHelperBase::StartCall(const char *pName)
{
(void)pName;
#if GL_TELEMETRY_ZONES
tmEnter( TELEMETRY_LEVEL3, TMZF_NONE, pName );
#endif
#if GL_TRACK_API_TIME
m_nStartTime = tmFastTime();
#endif
#if GL_DUMP_ALL_API_CALLS
static bool s_bDumpCalls;
if ( s_bDumpCalls )
{
char buf[128];
buf[0] = 'G';
buf[1] = 'L';
buf[2] = ':';
size_t l = strlen( pName );
memcpy( buf + 3, pName, l );
buf[3 + l] = '\n';
buf[4 + l] = '\0';
Plat_DebugString( buf );
}
#endif
}
inline void CGLExecuteHelperBase::StopCall(const char *pName)
{
#if GL_TRACK_API_TIME
uint64 nTotalCycles = tmFastTime() - m_nStartTime;
#endif
#if GL_TELEMETRY_ZONES
tmLeave( TELEMETRY_LEVEL3 );
#endif
#if GL_TRACK_API_TIME
//double flMilliseconds = g_Telemetry.flRDTSCToMilliSeconds * nTotalCycles;
if (gGL)
{
gGL->m_nTotalGLCycles += nTotalCycles;
gGL->m_nTotalGLCalls++;
}
#endif
}
#endif
#endif // DX_TO_GL_ABSTRACTION
#endif // GLENTRYPOINTS_H

View file

@ -0,0 +1,277 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// !!! FIXME: Some of these aren't base OpenGL...pick out the extensions.
// !!! FIXME: Also, look up these -1, -1 versions numbers.
GL_FUNC(OpenGL,true,GLenum,glGetError,(void),())
GL_FUNC_VOID(OpenGL,true,glActiveTexture,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glAlphaFunc,(GLenum a,GLclampf b),(a,b))
GL_FUNC_VOID(OpenGL,true,glAttachObjectARB,(GLhandleARB a,GLhandleARB b),(a,b))
GL_FUNC_VOID(OpenGL,true,glBegin,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glBindAttribLocationARB,(GLhandleARB a,GLuint b,const GLcharARB *c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glBindBufferARB,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glBindProgramARB,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glBindTexture,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glBlendColor,(GLclampf a,GLclampf b,GLclampf c,GLclampf d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glBlendEquation,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glBlendFunc,(GLenum a,GLenum b),(a,b))
GL_FUNC_VOID(OpenGL,true,glBufferDataARB,(GLenum a,GLsizeiptrARB b,const GLvoid *c,GLenum d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glClear,(GLbitfield a),(a))
GL_FUNC_VOID(OpenGL,true,glClearColor,(GLclampf a,GLclampf b,GLclampf c,GLclampf d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glClearDepth,(GLclampd a),(a))
GL_FUNC_VOID(OpenGL,true,glClearStencil,(GLint a),(a))
GL_FUNC_VOID(OpenGL,true,glClipPlane,(GLenum a,const GLdouble *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glColorMask,(GLboolean a,GLboolean b,GLboolean c,GLboolean d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glCompileShaderARB,(GLhandleARB a),(a))
GL_FUNC_VOID(OpenGL,true,glCompressedTexImage2D,(GLenum a,GLint b,GLenum c,GLsizei d,GLsizei e,GLint f,GLsizei g,const GLvoid *h),(a,b,c,d,e,f,g,h))
GL_FUNC_VOID(OpenGL,true,glCompressedTexImage3D,(GLenum a,GLint b,GLenum c,GLsizei d,GLsizei e,GLsizei f,GLint g,GLsizei h,const GLvoid *i),(a,b,c,d,e,f,g,h,i))
GL_FUNC(OpenGL,true,GLhandleARB,glCreateProgramObjectARB,(void),())
GL_FUNC(OpenGL,true,GLhandleARB,glCreateShaderObjectARB,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glDeleteBuffersARB,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDeleteObjectARB,(GLhandleARB a),(a))
GL_FUNC_VOID(OpenGL,true,glDeleteProgramsARB,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDeleteQueriesARB,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDeleteShader,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glDeleteTextures,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDepthFunc,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glDepthMask,(GLboolean a),(a))
GL_FUNC_VOID(OpenGL,true,glDepthRange,(GLclampd a,GLclampd b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDetachObjectARB,(GLhandleARB a,GLhandleARB b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDisable,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glDisableVertexAttribArray,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glDrawArrays,(GLenum a,GLint b,GLsizei c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glDrawBuffer,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glDrawBuffers,(GLsizei a,const GLenum *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glDrawRangeElements,(GLenum a,GLuint b,GLuint c,GLsizei d,GLenum e,const GLvoid *f),(a,b,c,d,e,f))
#ifndef OSX // 10.6/GL 2.1 compatability
GL_FUNC_VOID(OpenGL,true,glDrawRangeElementsBaseVertex,(GLenum a,GLuint b,GLuint c,GLsizei d,GLenum e,const GLvoid *f, GLenum g),(a,b,c,d,e,f,g))
#endif
GL_FUNC_VOID(OpenGL,true,glEnable,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glEnableVertexAttribArray,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glEnd,(void),())
GL_FUNC_VOID(OpenGL,true,glFinish,(void),())
GL_FUNC_VOID(OpenGL,true,glFlush,(void),())
GL_FUNC_VOID(OpenGL,true,glFrontFace,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glGenBuffersARB,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGenProgramsARB,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGenQueriesARB,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGenTextures,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGetBooleanv,(GLenum a,GLboolean *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGetCompressedTexImage,(GLenum a,GLint b,GLvoid *c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glGetDoublev,(GLenum a,GLdouble *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGetFloatv,(GLenum a,GLfloat *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGetInfoLogARB,(GLhandleARB a,GLsizei b,GLsizei *c,GLcharARB *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glGetIntegerv,(GLenum a,GLint *b),(a,b))
GL_FUNC_VOID(OpenGL,true,glGetObjectParameterivARB,(GLhandleARB a,GLenum b,GLint *c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glGetProgramivARB,(GLenum a,GLenum b,GLint *c),(a,b,c))
GL_FUNC(OpenGL,true,const GLubyte *,glGetString,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glGetTexImage,(GLenum a,GLint b,GLenum c,GLenum d,GLvoid *e),(a,b,c,d,e))
GL_FUNC(OpenGL,true,GLint,glGetUniformLocationARB,(GLhandleARB a,const GLcharARB *b),(a,b))
GL_FUNC(OpenGL,true,GLboolean,glIsEnabled,(GLenum a),(a))
GL_FUNC(OpenGL,true,GLboolean,glIsTexture,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glLinkProgramARB,(GLhandleARB a),(a))
GL_FUNC(OpenGL,true,GLvoid*,glMapBufferARB,(GLenum a,GLenum b),(a,b))
GL_FUNC_VOID(OpenGL,true,glOrtho,(GLdouble a,GLdouble b,GLdouble c,GLdouble d,GLdouble e,GLdouble f),(a,b,c,d,e,f))
GL_FUNC_VOID(OpenGL,true,glPixelStorei,(GLenum a,GLint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glPolygonMode,(GLenum a,GLenum b),(a,b))
GL_FUNC_VOID(OpenGL,true,glPolygonOffset,(GLfloat a,GLfloat b),(a,b))
GL_FUNC_VOID(OpenGL,true,glPopAttrib,(void),())
GL_FUNC_VOID(OpenGL,true,glProgramStringARB,(GLenum a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glPushAttrib,(GLbitfield a),(a))
GL_FUNC_VOID(OpenGL,true,glReadBuffer,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glScissor,(GLint a,GLint b,GLsizei c,GLsizei d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glShaderSourceARB,(GLhandleARB a,GLsizei b,const GLcharARB **c,const GLint *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glStencilFunc,(GLenum a,GLint b,GLuint c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glStencilMask,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glStencilOp,(GLenum a,GLenum b,GLenum c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glTexCoord2f,(GLfloat a,GLfloat b),(a,b))
GL_FUNC_VOID(OpenGL,true,glTexImage2D,(GLenum a,GLint b,GLint c,GLsizei d,GLsizei e,GLint f,GLenum g,GLenum h,const GLvoid *i),(a,b,c,d,e,f,g,h,i))
GL_FUNC_VOID(OpenGL,true,glTexImage3D,(GLenum a,GLint b,GLint c,GLsizei d,GLsizei e,GLsizei f,GLint g,GLenum h,GLenum i,const GLvoid *j),(a,b,c,d,e,f,g,h,i,j))
GL_FUNC_VOID(OpenGL,true,glTexParameterfv,(GLenum a,GLenum b,const GLfloat *c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glTexParameteri,(GLenum a,GLenum b,GLint c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glTexSubImage2D,(GLenum a,GLint b,GLint c,GLint d,GLsizei e,GLsizei f,GLenum g,GLenum h,const GLvoid *i),(a,b,c,d,e,f,g,h,i))
GL_FUNC_VOID(OpenGL,true,glUniform1f,(GLint a,GLfloat b),(a,b))
GL_FUNC_VOID(OpenGL,true,glUniform1i,(GLint a,GLint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glUniform1iARB,(GLint a,GLint b),(a,b))
GL_FUNC_VOID(OpenGL,true,glUniform4fv,(GLint a,GLsizei b,const GLfloat *c),(a,b,c))
GL_FUNC(OpenGL,true,GLboolean,glUnmapBuffer,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glUseProgram,(GLuint a),(a))
GL_FUNC_VOID(OpenGL,true,glVertex3f,(GLfloat a,GLfloat b,GLfloat c),(a,b,c))
GL_FUNC_VOID(OpenGL,true,glVertexAttribPointer,(GLuint a,GLint b,GLenum c,GLboolean d,GLsizei e,const GLvoid *f),(a,b,c,d,e,f))
GL_FUNC_VOID(OpenGL,true,glViewport,(GLint a,GLint b,GLsizei c,GLsizei d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glEnableClientState,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glDisableClientState,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glClientActiveTexture,(GLenum a),(a))
GL_FUNC_VOID(OpenGL,true,glVertexPointer,(GLint a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glTexCoordPointer,(GLint a,GLenum b,GLsizei c,const GLvoid *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glProgramEnvParameters4fvEXT,(GLenum a,GLuint b,GLsizei c,const GLfloat *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glColor4sv,(const GLshort *a),(a))
GL_FUNC_VOID(OpenGL,true,glStencilOpSeparate,(GLenum a,GLenum b,GLenum c,GLenum d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glStencilFuncSeparate,(GLenum a,GLenum b,GLint c,GLuint d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glGetTexLevelParameteriv,(GLenum a,GLint b,GLenum c,GLint *d),(a,b,c,d))
GL_FUNC_VOID(OpenGL,true,glColor4f,(GLfloat a,GLfloat b,GLfloat c,GLfloat d),(a,b,c,d))
GL_EXT(GL_EXT_framebuffer_object,-1,-1)
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glBindFramebufferEXT,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glBindRenderbufferEXT,(GLenum a,GLuint b),(a,b))
GL_FUNC(GL_EXT_framebuffer_object,false,GLenum,glCheckFramebufferStatusEXT,(GLenum a),(a))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glDeleteRenderbuffersEXT,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferRenderbufferEXT,(GLenum a,GLenum b,GLenum c,GLuint d),(a,b,c,d))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferTexture2DEXT,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e),(a,b,c,d,e))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glFramebufferTexture3DEXT,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e,GLint f),(a,b,c,d,e,f))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glGenFramebuffersEXT,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glGenRenderbuffersEXT,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(GL_EXT_framebuffer_object,false,glDeleteFramebuffersEXT,(GLsizei a,const GLuint *b),(a,b))
GL_EXT(GL_EXT_framebuffer_blit,-1,-1)
GL_FUNC_VOID(GL_EXT_framebuffer_blit,false,glBlitFramebufferEXT,(GLint a,GLint b,GLint c,GLint d,GLint e,GLint f,GLint g,GLint h,GLbitfield i,GLenum j),(a,b,c,d,e,f,g,h,i,j))
GL_EXT(GL_EXT_framebuffer_multisample,-1,-1)
GL_FUNC_VOID(GL_EXT_framebuffer_multisample,false,glRenderbufferStorageMultisampleEXT,(GLenum a,GLsizei b,GLenum c,GLsizei d,GLsizei e),(a,b,c,d,e))
GL_EXT(GL_APPLE_fence,-1,-1)
GL_FUNC(GL_APPLE_fence,false,GLboolean,glTestFenceAPPLE,(GLuint a),(a))
GL_FUNC_VOID(GL_APPLE_fence,false,glSetFenceAPPLE,(GLuint a),(a))
GL_FUNC_VOID(GL_APPLE_fence,false,glFinishFenceAPPLE,(GLuint a),(a))
GL_FUNC_VOID(GL_APPLE_fence,false,glDeleteFencesAPPLE,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(GL_APPLE_fence,false,glGenFencesAPPLE,(GLsizei a,GLuint *b),(a,b))
GL_EXT(GL_NV_fence,-1,-1)
GL_FUNC(GL_NV_fence,false,GLboolean,glTestFenceNV,(GLuint a),(a))
GL_FUNC_VOID(GL_NV_fence,false,glSetFenceNV,(GLuint a,GLenum b),(a,b))
GL_FUNC_VOID(GL_NV_fence,false,glFinishFenceNV,(GLuint a),(a))
GL_FUNC_VOID(GL_NV_fence,false,glDeleteFencesNV,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(GL_NV_fence,false,glGenFencesNV,(GLsizei a,GLuint *b),(a,b))
GL_EXT(GL_ARB_sync,3,2)
#ifdef HAVE_GL_ARB_SYNC
GL_FUNC_VOID(GL_ARB_sync,false,glGetSynciv,(GLsync a, GLenum b, GLsizei c, GLsizei *d, GLint *e),(a,b,c,d,e))
GL_FUNC(GL_ARB_sync,false,GLenum,glClientWaitSync,(GLsync a, GLbitfield b, GLuint64 c),(a,b,c))
GL_FUNC_VOID(GL_ARB_sync,false,glWaitSync,(GLsync a, GLbitfield b, GLuint64 c),(a,b,c))
GL_FUNC_VOID(GL_ARB_sync,false,glDeleteSync,(GLsync a),(a))
GL_FUNC(GL_ARB_sync,false,GLsync,glFenceSync,(GLenum a, GLbitfield b),(a,b))
#endif
GL_EXT(GL_EXT_draw_buffers2,-1,-1)
GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glColorMaskIndexedEXT,(GLuint a,GLboolean b,GLboolean c,GLboolean d,GLboolean e),(a,b,c,d,e))
GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glEnableIndexedEXT,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glDisableIndexedEXT,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(GL_EXT_draw_buffers2,true,glGetBooleanIndexedvEXT,(GLenum a,GLuint b,GLboolean *c),(a,b,c))
GL_EXT(GL_EXT_bindable_uniform,-1,-1)
GL_FUNC_VOID(GL_EXT_bindable_uniform,false,glUniformBufferEXT,(GLuint a,GLint b,GLuint c),(a,b,c))
GL_FUNC(GL_EXT_bindable_uniform,false,int,glGetUniformBufferSizeEXT,(GLenum a, GLenum b),(a,b))
GL_FUNC(GL_EXT_bindable_uniform,false,GLintptr,glGetUniformOffsetEXT,(GLenum a, GLenum b),(a,b))
GL_EXT(GL_APPLE_flush_buffer_range,-1,-1)
GL_FUNC_VOID(GL_APPLE_flush_buffer_range,false,glBufferParameteriAPPLE,(GLenum a,GLenum b,GLint c),(a,b,c))
GL_FUNC_VOID(GL_APPLE_flush_buffer_range,false,glFlushMappedBufferRangeAPPLE,(GLenum a,GLintptr b,GLsizeiptr c),(a,b,c))
GL_EXT(GL_ARB_map_buffer_range,-1,-1)
GL_FUNC(GL_ARB_map_buffer_range,false,void*,glMapBufferRange,(GLenum a,GLintptr b,GLsizeiptr c,GLbitfield d),(a,b,c,d))
GL_FUNC_VOID(GL_ARB_map_buffer_range,false,glFlushMappedBufferRange,(GLenum a,GLintptr b,GLsizeiptr c),(a,b,c))
GL_EXT(GL_ARB_vertex_buffer_object,-1,-1)
GL_FUNC_VOID(GL_ARB_vertex_buffer_object,true,glBufferSubData,(GLenum a,GLintptr b,GLsizeiptr c,const GLvoid *d),(a,b,c,d))
GL_EXT(GL_ARB_occlusion_query,-1,-1)
GL_FUNC_VOID(GL_ARB_occlusion_query,false,glBeginQueryARB,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(GL_ARB_occlusion_query,false,glEndQueryARB,(GLenum a),(a))
GL_FUNC_VOID(GL_ARB_occlusion_query,false,glGetQueryObjectivARB,(GLuint a,GLenum b,GLint *c),(a,b,c))
GL_FUNC_VOID(GL_ARB_occlusion_query,false,glGetQueryObjectuivARB,(GLuint a,GLenum b,GLuint *c),(a,b,c))
GL_EXT(GL_APPLE_texture_range,-1,-1)
GL_FUNC_VOID(GL_APPLE_texture_range,false,glTextureRangeAPPLE,(GLenum a,GLsizei b,void *c),(a,b,c))
GL_FUNC_VOID(GL_APPLE_texture_range,false,glGetTexParameterPointervAPPLE,(GLenum a,GLenum b,void* *c),(a,b,c))
GL_EXT(GL_APPLE_client_storage,-1,-1)
GL_EXT(GL_ARB_uniform_buffer,-1,-1)
GL_EXT(GL_ARB_vertex_array_bgra,-1,-1)
GL_EXT(GL_EXT_vertex_array_bgra,-1,-1)
GL_EXT(GL_ARB_framebuffer_object,3,0)
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBindFramebuffer,(GLenum a,GLuint b),(a,b))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBindRenderbuffer,(GLenum a,GLuint b),(a,b))
GL_FUNC(GL_ARB_framebuffer_object,false,GLenum,glCheckFramebufferStatus,(GLenum a),(a))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glDeleteRenderbuffers,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferRenderbuffer,(GLenum a,GLenum b,GLenum c,GLuint d),(a,b,c,d))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferTexture2D,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e),(a,b,c,d,e))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glFramebufferTexture3D,(GLenum a,GLenum b,GLenum c,GLuint d,GLint e,GLint f),(a,b,c,d,e,f))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glGenFramebuffers,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glGenRenderbuffers,(GLsizei a,GLuint *b),(a,b))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glDeleteFramebuffers,(GLsizei a,const GLuint *b),(a,b))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glBlitFramebuffer,(GLint a,GLint b,GLint c,GLint d,GLint e,GLint f,GLint g,GLint h,GLbitfield i,GLenum j),(a,b,c,d,e,f,g,h,i,j))
GL_FUNC_VOID(GL_ARB_framebuffer_object,false,glRenderbufferStorageMultisample,(GLenum a,GLsizei b,GLenum c,GLsizei d,GLsizei e),(a,b,c,d,e))
GL_EXT(GL_GREMEDY_string_marker,-1,-1)
GL_FUNC_VOID(GL_GREMEDY_string_marker,false,glStringMarkerGREMEDY,(GLsizei a,const void *b),(a,b))
GL_EXT(GL_ARB_debug_output,-1,-1)
#ifdef OSX
GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageCallbackARB,(void ( *a)(GLenum, GLenum , GLuint , GLenum , GLsizei , const GLchar* , GLvoid*) ,void* b),(a,b))
#else
GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageCallbackARB,(void (APIENTRY *a)(GLenum, GLenum , GLuint , GLenum , GLsizei , const GLchar* , GLvoid*) ,void* b),(a,b))
#endif
GL_FUNC_VOID(GL_ARB_debug_output,false,glDebugMessageControlARB,(GLenum a, GLenum b, GLenum c, GLsizei d, const GLuint* e, GLboolean f),(a,b,c,d,e,f))
GL_EXT(GL_EXT_direct_state_access,-1,-1)
GL_FUNC_VOID(GL_EXT_direct_state_access,false,glBindMultiTextureEXT,(GLenum a,GLuint b, GLuint c),(a,b,c))
GL_EXT(GL_NV_bindless_texture,-1,-1)
#ifndef OSX
GL_FUNC_VOID(OpenGL, true, glGenSamplers, (GLuint a, GLuint *b), (a, b))
GL_FUNC_VOID(OpenGL, true, glDeleteSamplers, (GLsizei a, const GLuint *b), (a, b))
GL_FUNC_VOID(OpenGL, true, glBindSampler, (GLuint a, GLuint b), (a, b))
GL_FUNC_VOID(OpenGL, true, glSamplerParameteri, (GLuint a, GLenum b, GLint c), (a, b, c))
GL_FUNC_VOID(OpenGL, true, glSamplerParameterf, (GLuint a, GLenum b, GLfloat c), (a, b, c))
GL_FUNC_VOID(OpenGL, true, glSamplerParameterfv, (GLuint a, GLenum b, const GLfloat *c), (a, b, c))
GL_FUNC(GL_NV_bindless_texture, false, GLuint64, glGetTextureHandleNV, (GLuint texture), (texture))
GL_FUNC(GL_NV_bindless_texture, false, GLuint64, glGetTextureSamplerHandleNV, (GLuint texture, GLuint sampler), (texture, sampler))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glMakeTextureHandleResidentNV, (GLuint64 handle), (handle))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glMakeTextureHandleNonResidentNV, (GLuint64 handle), (handle))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glUniformHandleui64NV, (GLint location, GLuint64 value), (location, value))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glUniformHandleui64vNV, (int location, GLsizei count, const GLuint64 *value), (location count, value))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glProgramUniformHandleui64NV, (GLuint program, GLint location, GLuint64 value), (program, location, value))
GL_FUNC_VOID(GL_NV_bindless_texture, false, glProgramUniformHandleui64vNV, (GLuint program, GLint location, GLsizei count, const GLuint64 *values), (program, location, count, values))
GL_FUNC(GL_NV_bindless_texture, false, GLboolean, glIsTextureHandleResidentNV, (GLuint64 handle), (handle))
GL_FUNC_VOID(OpenGL,true,glGenQueries,(GLsizei n, GLuint *ids), (n, ids))
GL_FUNC_VOID(OpenGL,true,glDeleteQueries,(GLsizei n, const GLuint *ids),(n, ids))
GL_FUNC_VOID(OpenGL,true,glBeginQuery,(GLenum target, GLuint id), (target, id))
GL_FUNC_VOID(OpenGL,true,glEndQuery,(GLenum target), (target))
GL_FUNC_VOID(OpenGL,true,glQueryCounter,(GLuint id, GLenum target), (id, target))
GL_FUNC_VOID(OpenGL,true,glGetQueryObjectiv,(GLuint id, GLenum pname, GLint *params), (id, pname, params))
GL_FUNC_VOID(OpenGL,true,glGetQueryObjectui64v,(GLuint id, GLenum pname, GLuint64 *params), (id, pname, params))
GL_FUNC_VOID(OpenGL,true,glCopyBufferSubData,(GLenum readtarget, GLenum writetarget, GLintptr readoffset, GLintptr writeoffset, GLsizeiptr size),(readtarget, writetarget, readoffset, writeoffset, size))
#endif // !OSX
GL_EXT(GL_AMD_pinned_memory,-1,-1)
GL_EXT(GL_EXT_framebuffer_multisample_blit_scaled,-1,-1)
#ifndef OSX
GL_FUNC_VOID(OpenGL,true,glGenVertexArrays,(GLsizei n, GLuint *arrays),(n, arrays))
GL_FUNC_VOID(OpenGL,true,glDeleteVertexArrays,(GLsizei n, GLuint *arrays),(n, arrays))
GL_FUNC_VOID(OpenGL,true,glBindVertexArray,(GLuint a),(a))
#endif // !OSX
GL_EXT(GL_EXT_texture_sRGB_decode,-1,-1)
GL_FUNC_VOID(OpenGL,true,glPushClientAttrib,(GLbitfield a),(a))
GL_FUNC_VOID(OpenGL,true,glPopClientAttrib,(void),())
GL_EXT(GL_NVX_gpu_memory_info,-1,-1)
GL_EXT(GL_ATI_meminfo,-1,-1)
GL_EXT(GL_EXT_texture_compression_s3tc,-1,-1)
GL_EXT(GL_EXT_texture_compression_dxt1,-1,-1)
GL_EXT(GL_ANGLE_texture_compression_dxt3,-1,-1)
GL_EXT(GL_ANGLE_texture_compression_dxt5,-1,-1)
GL_EXT( GL_ARB_buffer_storage, 4, 4 )
GL_FUNC_VOID( GL_ARB_buffer_storage, false, glBufferStorage, (GLenum target, GLsizeiptr size, const void *data, GLbitfield flags), (target, size, data, flags) )
// This one is an OS extension. We'll add a little helper function to look for it.
#ifdef _WIN32
GL_EXT(WGL_EXT_swap_control_tear,-1,-1)
#else
GL_EXT(GLX_EXT_swap_control_tear,-1,-1)
#endif

View file

@ -0,0 +1,181 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef GLMDEBUG_H
#define GLMDEBUG_H
#include "tier0/platform.h"
#if defined( OSX )
#include <stdarg.h>
#endif
// include this anywhere you need to be able to compile-out code related specifically to GLM debugging.
// we expect DEBUG to be driven by the build system so you can include this header anywhere.
// when we come out, GLMDEBUG will be defined to a value - 0, 1, or 2
// 0 means no GLM debugging is possible
// 1 means it's possible and resulted from being a debug build
// 2 means it's possible and resulted from being manually forced on for a release build
#ifdef POSIX
#ifndef GLMDEBUG
#ifdef DEBUG
#define GLMDEBUG 1 // normally 1 here, testing
#else
// #define GLMDEBUG 2 // don't check this in enabled..
#endif
#ifndef GLMDEBUG
#define GLMDEBUG 0
#endif
#endif
#else
#ifndef GLMDEBUG
#define GLMDEBUG 0
#endif
#endif
//===============================================================================
// debug channels
enum EGLMDebugChannel
{
ePrintf,
eDebugger,
eGLProfiler
};
#if GLMDEBUG
// make all these prototypes disappear in non GLMDEBUG
void GLMDebugInitialize( bool forceReinit=false );
bool GLMDetectOGLP( void );
bool GLMDetectGDB( void );
uint GLMDetectAvailableChannels( void );
uint GLMDebugChannelMask( uint *newValue = NULL );
// note that GDB and OGLP can both come and go during run - forceCheck will allow that to be detected.
// mask returned is in form of 1<<n, n from EGLMDebugChannel
#endif
//===============================================================================
// debug message flavors
enum EGLMDebugFlavor
{
eAllFlavors, // 0
eDebugDump, // 1 debug dump flavor -D-
eTenure, // 2 code tenures > <
eComment, // 3 one off messages ---
eMatrixData, // 4 matrix data -M-
eShaderData, // 5 shader data (params) -S-
eFrameBufData, // 6 FBO data (attachments) -F-
eDXStuff, // 7 dxabstract spew -X-
eAllocations, // 8 tracking allocs and frees -A-
eSlowness, // 9 slow things happening (srgb flips..) -Z-
eDefaultFlavor, // not specified (no marker)
eFlavorCount
};
uint GLMDebugFlavorMask( uint *newValue = NULL );
// make all these prototypes disappear in non GLMDEBUG
#if GLMDEBUG
// these are unconditional outputs, they don't interrogate the string
void GLMStringOut( const char *string );
void GLMStringOutIndented( const char *string, int indentColumns );
#ifdef TOGL_DLL_EXPORT
// these will look at the string to guess its flavor: <, >, ---, -M-, -S-
DLL_EXPORT void GLMPrintfVA( const char *fmt, va_list vargs );
DLL_EXPORT void GLMPrintf( const char *fmt, ... );
#else
DLL_IMPORT void GLMPrintfVA( const char *fmt, va_list vargs );
DLL_IMPORT void GLMPrintf( const char *fmt, ... );
#endif
// these take an explicit flavor with a default value
void GLMPrintStr( const char *str, EGLMDebugFlavor flavor = eDefaultFlavor );
#define GLMPRINTTEXT_NUMBEREDLINES 0x80000000
void GLMPrintText( const char *str, EGLMDebugFlavor flavor = eDefaultFlavor, uint options=0 ); // indent each newline
int GLMIncIndent( int indentDelta );
int GLMGetIndent( void );
void GLMSetIndent( int indent );
#endif
// helpful macro if you are in a position to call GLM functions directly (i.e. you live in materialsystem / shaderapidx9)
#if GLMDEBUG
#define GLMPRINTF(args) GLMPrintf args
#define GLMPRINTSTR(args) GLMPrintStr args
#define GLMPRINTTEXT(args) GLMPrintText args
#else
#define GLMPRINTF(args)
#define GLMPRINTSTR(args)
#define GLMPRINTTEXT(args)
#endif
//===============================================================================
// knob twiddling
#ifdef TOGL_DLL_EXPORT
DLL_EXPORT float GLMKnob( char *knobname, float *setvalue ); // Pass NULL to not-set the knob value
DLL_EXPORT float GLMKnobToggle( char *knobname );
#else
DLL_IMPORT float GLMKnob( char *knobname, float *setvalue ); // Pass NULL to not-set the knob value
DLL_IMPORT float GLMKnobToggle( char *knobname );
#endif
//===============================================================================
// other stuff
#if GLMDEBUG
void GLMTriggerDebuggerBreak();
inline void GLMDebugger( void )
{
if (GLMDebugChannelMask() & (1<<eDebugger))
{
DebuggerBreak();
}
if (GLMDebugChannelMask() & (1<<eGLProfiler))
{
GLMTriggerDebuggerBreak();
}
}
#else
#define GLMDebugger() do { } while(0)
#endif
// helpers for CGLSetOption - no op if no profiler
void GLMProfilerClearTrace( void );
void GLMProfilerEnableTrace( bool enable );
// helpers for CGLSetParameter - no op if no profiler
void GLMProfilerDumpState( void );
void CheckGLError( int line );
#endif // GLMDEBUG_H

View file

@ -0,0 +1,201 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glmdisplay.h
// display related stuff - used by both GLMgr and the CocoaMgr
//
//===============================================================================
#ifndef GLMDISPLAY_H
#define GLMDISPLAY_H
#pragma once
#ifdef USE_SDL
#include "SDL_opengl.h"
#endif
#ifdef OSX
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <OpenGL/CGLTypes.h>
#include <OpenGL/CGLRenderers.h>
#include <OpenGL/CGLCurrent.h>
#endif
#ifdef MAC_OS_X_VERSION_10_9
typedef uint32_t CGDirectDisplayID;
typedef uint32_t CGOpenGLDisplayMask;
typedef double CGRefreshRate;
#endif
typedef void _PseudoNSGLContext; // aka NSOpenGLContext
typedef _PseudoNSGLContext *PseudoNSGLContextPtr;
struct GLMDisplayModeInfoFields
{
uint m_modePixelWidth;
uint m_modePixelHeight;
uint m_modeRefreshHz;
// are we even going to talk about bit depth... not yet
};
struct GLMDisplayInfoFields
{
#ifdef OSX
CGDirectDisplayID m_cgDisplayID;
CGOpenGLDisplayMask m_glDisplayMask; // result of CGDisplayIDToOpenGLDisplayMask on the cg_displayID.
#endif
uint m_displayPixelWidth;
uint m_displayPixelHeight;
};
struct GLMRendererInfoFields
{
/*properties of interest and their desired values.
kCGLRPFullScreen = 54, true
kCGLRPAccelerated = 73, true
kCGLRPWindow = 80, true
kCGLRPRendererID = 70, informational
kCGLRPDisplayMask = 84, informational
kCGLRPBufferModes = 100, informational
kCGLRPColorModes = 103, informational
kCGLRPAccumModes = 104, informational
kCGLRPDepthModes = 105, informational
kCGLRPStencilModes = 106, informational
kCGLRPMaxAuxBuffers = 107, informational
kCGLRPMaxSampleBuffers = 108, informational
kCGLRPMaxSamples = 109, informational
kCGLRPSampleModes = 110, informational
kCGLRPSampleAlpha = 111, informational
kCGLRPVideoMemory = 120, informational
kCGLRPTextureMemory = 121, informational
kCGLRPRendererCount = 128 number of renderers in the CGLRendererInfoObj under examination
kCGLRPOffScreen = 53, D/C
kCGLRPRobust = 75, FALSE or D/C - aka we're asking for no-fallback
kCGLRPBackingStore = 76, D/C
kCGLRPMPSafe = 78, D/C
kCGLRPMultiScreen = 81, D/C
kCGLRPCompliant = 83, D/C
*/
//--------------------------- info we have from CGL renderer queries, IOKit, Gestalt
//--------------------------- these are set up in the displayDB by CocoaMgr
GLint m_fullscreen;
GLint m_accelerated;
GLint m_windowed;
GLint m_rendererID;
GLint m_displayMask;
GLint m_bufferModes;
GLint m_colorModes;
GLint m_accumModes;
GLint m_depthModes;
GLint m_stencilModes;
GLint m_maxAuxBuffers;
GLint m_maxSampleBuffers;
GLint m_maxSamples;
GLint m_sampleModes;
GLint m_sampleAlpha;
GLint m_vidMemory;
GLint m_texMemory;
uint m_pciVendorID;
uint m_pciDeviceID;
char m_pciModelString[64];
char m_driverInfoString[64];
//--------------------------- OS version related - set up by CocoaMgr
// OS version found
uint m_osComboVersion; // 0x00XXYYZZ : XX major, YY minor, ZZ minor minor : 10.6.3 --> 0x000A0603. 10.5.8 --> 0x000A0508.
//--------------------------- shorthands - also set up by CocoaMgr - driven by vendorid / deviceid
bool m_ati;
bool m_atiR5xx;
bool m_atiR6xx;
bool m_atiR7xx;
bool m_atiR8xx;
bool m_atiNewer;
bool m_intel;
bool m_intel95x;
bool m_intel3100;
bool m_intelHD4000;
bool m_nv;
bool m_nvG7x;
bool m_nvG8x;
bool m_nvNewer;
//--------------------------- context query results - left blank in the display DB - but valid in a GLMContext (call ctx->Caps() to get a const ref)
// booleans
bool m_hasGammaWrites; // aka glGetBooleanv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT) / glEnable(GL_FRAMEBUFFER_SRGB_EXT)
bool m_hasMixedAttachmentSizes; // aka ARB_fbo in 10.6.3 - test for min OS vers, then exported ext string
bool m_hasBGRA; // aka GL_BGRA vertex attribs in 10.6.3 - - test for min OS vers, then exported ext string
bool m_hasNewFullscreenMode; // aka 10.6.x "big window" fullscreen mode
bool m_hasNativeClipVertexMode; // aka GLSL gl_ClipVertex does not fall back to SW- OS version and folklore-based
bool m_hasOcclusionQuery; // occlusion query: do you speak it ?!
bool m_hasFramebufferBlit; // framebuffer blit: know what I'm sayin?!
bool m_hasPerfPackage1; // means new MTGL, fast OQ, fast uniform upload, NV can resolve flipped (late summer 2010 post 10.6.4 update)
// counts
int m_maxAniso; // aniso limit - context query
// other exts
bool m_hasBindableUniforms;
int m_maxVertexBindableUniforms;
int m_maxFragmentBindableUniforms;
int m_maxBindableUniformSize;
bool m_hasUniformBuffers;
// runtime options that aren't negotiable once set
bool m_hasDualShaders; // must supply CLI arg "-glmdualshaders" or we go GLSL only
//--------------------------- " can'ts " - specific problems that need to be worked around
bool m_cantBlitReliably; // Intel chipsets have problems blitting sRGB sometimes
bool m_cantAttachSRGB; // NV G8x on 10.5.8 can't have srgb tex on FBO color - separate issue from hasGammaWrites
bool m_cantResolveFlipped; // happens on NV in 10.6.4 and prior - console variable "gl_can_resolve_flipped" can overrule
bool m_cantResolveScaled; // happens everywhere per GL spec but may be relaxed some day - console variable "gl_can_resolve_scaled" can overrule
bool m_costlyGammaFlips; // this means that sRGB sampling state affects shader code gen, resulting in state-dependent code regen
//--------------------------- " bads " - known bad drivers
bool m_badDriver1064NV; // this is the bad NVIDIA driver on 10.6.4 - stutter, tex corruption, black screen issues
bool m_badDriver108Intel; // this is the bad Intel HD4000 driver on 10.8 - intermittent crash on GLSL compilation.
};
#endif

View file

@ -0,0 +1,157 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef GLMDISPLAYDB_H
#define GLMDISPLAYDB_H
#include "tier1/utlvector.h"
//===============================================================================
// modes, displays, and renderers
//===============================================================================
// GLMDisplayModeInfoFields is in glmdisplay.h
class GLMDisplayMode
{
public:
GLMDisplayModeInfoFields m_info;
GLMDisplayMode( uint width, uint height, uint refreshHz );
GLMDisplayMode() { };
~GLMDisplayMode( void );
void Init( uint width, uint height, uint refreshHz );
void Dump( int which );
};
//===============================================================================
// GLMDisplayInfoFields is in glmdisplay.h
class GLMDisplayInfo
{
public:
GLMDisplayInfoFields m_info;
CUtlVector< GLMDisplayMode* > *m_modes; // starts out NULL, set by PopulateModes
GLMDisplayMode m_DesktopMode;
#ifdef OSX
GLMDisplayInfo( CGDirectDisplayID displayID, CGOpenGLDisplayMask displayMask );
#else
GLMDisplayInfo( void );
#endif
~GLMDisplayInfo( void );
void PopulateModes( void );
void Dump( int which );
#ifdef OSX
private:
int m_display;
#endif
};
//===============================================================================
// GLMRendererInfoFields is in glmdisplay.h
class GLMRendererInfo
{
public:
GLMRendererInfoFields m_info;
#ifdef OSX
CUtlVector< GLMDisplayInfo* > *m_displays; // starts out NULL, set by PopulateDisplays
#else
GLMDisplayInfo *m_display;
#endif
#ifdef OSX
GLMRendererInfo ( GLMRendererInfoFields *info );
#else
GLMRendererInfo ();
#endif
~GLMRendererInfo ( void );
#ifndef OSX
void Init( GLMRendererInfoFields *info );
#endif
void PopulateDisplays();
void Dump( int which );
};
//===============================================================================
#ifdef OSX
// this is just a tuple describing fake adapters which are really renderer/display pairings.
// dxabstract bridges the gap between the d3d adapter-centric world and the GL renderer+display world.
// this makes it straightforward to handle cases like two video cards with two displays on one, and one on the other -
// you get three fake adapters which represent each useful screen.
// the constraint that dxa will have to follow though, is that if the user wants to change their
// display selection for full screen, they would only be able to pick on that has the same underlying renderer.
// can't change fakeAdapter from one to another with different GL renderer under it. Screen hop but no card hop.
struct GLMFakeAdapter
{
int m_rendererIndex;
int m_displayIndex;
};
#endif
class GLMDisplayDB
{
public:
#ifdef OSX
CUtlVector< GLMRendererInfo* > *m_renderers; // starts out NULL, set by PopulateRenderers
CUtlVector< GLMFakeAdapter > m_fakeAdapters;
#else
GLMRendererInfo m_renderer;
#endif
GLMDisplayDB ( void );
~GLMDisplayDB ( void );
virtual void PopulateRenderers( void );
virtual void PopulateFakeAdapters( uint realRendererIndex ); // fake adapters = one real adapter times however many displays are on it
virtual void Populate( void );
// The info-get functions return false on success.
virtual int GetFakeAdapterCount( void );
virtual bool GetFakeAdapterInfo( int fakeAdapterIndex, int *rendererOut, int *displayOut, GLMRendererInfoFields *rendererInfoOut, GLMDisplayInfoFields *displayInfoOut );
virtual int GetRendererCount( void );
virtual bool GetRendererInfo( int rendererIndex, GLMRendererInfoFields *infoOut );
virtual int GetDisplayCount( int rendererIndex );
virtual bool GetDisplayInfo( int rendererIndex, int displayIndex, GLMDisplayInfoFields *infoOut );
virtual int GetModeCount( int rendererIndex, int displayIndex );
virtual bool GetModeInfo( int rendererIndex, int displayIndex, int modeIndex, GLMDisplayModeInfoFields *infoOut );
virtual void Dump( void );
};
#endif // GLMDISPLAYDB_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,332 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glmgrbasics.h
// types, common headers, forward declarations, utilities
//
//===============================================================================
#ifndef GLMBASICS_H
#define GLMBASICS_H
#pragma once
#ifdef USE_SDL
#include "SDL_opengl.h"
#endif
#ifdef OSX
#include <OpenGL/CGLTypes.h>
#include <OpenGL/CGLRenderers.h>
#include <OpenGL/CGLCurrent.h>
#include <AvailabilityMacros.h>
#ifndef MAC_OS_X_VERSION_10_9
#include <OpenGL/CGLProfiler.h>
#include <ApplicationServices/ApplicationServices.h>
#endif
#endif
#include "tier0/platform.h"
#include "bitmap/imageformat.h"
#include "bitvec.h"
#include "tier1/checksum_md5.h"
#include "tier1/utlvector.h"
#include "tier1/convar.h"
#include <sys/stat.h>
#include "dxabstract_types.h"
struct GLMRect;
typedef void *PseudoGLContextPtr;
// types
// 3-d integer box (used for texture lock/unlock etc)
struct GLMRegion
{
int xmin,xmax;
int ymin,ymax;
int zmin,zmax;
};
struct GLMRect // follows GL convention - if coming from the D3D rect you will need to fiddle the Y's
{
int xmin; // left
int ymin; // bottom
int xmax; // right
int ymax; // top
};
// macros
//#define GLMassert(x) assert(x)
// forward decls
class GLMgr; // singleton
class GLMContext; // GL context
class CGLMContextTester; // testing class
class CGLMTex;
class CGLMFBO;
class CGLMProgram;
class CGLMBuffer;
// utilities
typedef enum
{
// D3D codes
eD3D_DEVTYPE,
eD3D_FORMAT,
eD3D_RTYPE,
eD3D_USAGE,
eD3D_RSTATE, // render state
eD3D_SIO, // D3D shader bytecode
eD3D_VTXDECLUSAGE,
// CGL codes
eCGL_RENDID,
// OpenGL error codes
eGL_ERROR,
// OpenGL enums
eGL_ENUM,
eGL_RENDERER
} GLMThing_t;
// these will look at the string to guess its flavor: <, >, ---, -M-, -S-
#ifdef TOGL_DLL_EXPORT
DLL_EXPORT const char* GLMDecode( GLMThing_t type, unsigned long value ); // decode a numeric const
#else
DLL_IMPORT const char* GLMDecode( GLMThing_t type, unsigned long value ); // decode a numeric const
#endif
const char* GLMDecodeMask( GLMThing_t type, unsigned long value ); // decode a bitmask
FORCEINLINE void GLMStop( void ) { DXABSTRACT_BREAK_ON_ERROR(); }
void GLMEnableTrace( bool on );
//===============================================================================
// output functions
// expose these in release now
// Mimic PIX events so we can decorate debug spew
DLL_EXPORT void GLMBeginPIXEvent( const char *str );
DLL_EXPORT void GLMEndPIXEvent( void );
class CScopedGLMPIXEvent
{
CScopedGLMPIXEvent( const CScopedGLMPIXEvent & );
CScopedGLMPIXEvent& operator= ( const CScopedGLMPIXEvent & );
public:
inline CScopedGLMPIXEvent( const char *pName ) { GLMBeginPIXEvent( pName ); }
inline ~CScopedGLMPIXEvent() { GLMEndPIXEvent( ); }
};
#if GLMDEBUG
//===============================================================================
// classes
// helper class making function tracking easier to wire up
class GLMFuncLogger
{
public:
// simple function log
GLMFuncLogger( const char *funcName )
{
m_funcName = funcName;
m_earlyOut = false;
GLMPrintf( ">%s", m_funcName );
};
// more advanced version lets you pass args (i.e. called parameters or anything else of interest)
// no macro for this one, since no easy way to pass through the args as well as the funcname
GLMFuncLogger( const char *funcName, char *fmt, ... )
{
m_funcName = funcName;
m_earlyOut = false;
// this acts like GLMPrintf here
// all the indent policy is down in GLMPrintfVA
// which means we need to inject a ">" at the front of the format string to make this work... sigh.
char modifiedFmt[2000];
modifiedFmt[0] = '>';
strcpy( modifiedFmt+1, fmt );
va_list vargs;
va_start(vargs, fmt);
GLMPrintfVA( modifiedFmt, vargs );
va_end( vargs );
}
~GLMFuncLogger( )
{
if (m_earlyOut)
{
GLMPrintf( "<%s (early out)", m_funcName );
}
else
{
GLMPrintf( "<%s", m_funcName );
}
};
void EarlyOut( void )
{
m_earlyOut = true;
};
const char *m_funcName; // set at construction time
bool m_earlyOut;
};
// handy macro to go with the function tracking class
#define GLM_FUNC GLMFuncLogger _logger_ ( __FUNCTION__ )
#else
#define GLM_FUNC tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ )
#endif
// class to keep an in-memory mirror of a file which may be getting edited during run
class CGLMFileMirror
{
public:
CGLMFileMirror( char *fullpath ); // just associates mirror with file. if file exists it will be read.
//if non existent it will be created with size zero
~CGLMFileMirror( );
bool HasData( void ); // see if data avail
void GetData( char **dataPtr, uint *dataSizePtr ); // read it out
void SetData( char *data, uint dataSize ); // put data in (and write it to disk)
bool PollForChanges( void ); // check disk copy. If different, read it back in and return true.
void UpdateStatInfo( void ); // make sure stat info is current for our file
void ReadFile( void );
void WriteFile( void );
void OpenInEditor( bool foreground=false ); // pass TRUE if you would like the editor to pop to foreground
/// how about a "wait for change" method..
char *m_path; // fullpath to file
bool m_exists;
struct stat m_stat; // stat results for the file (last time checked)
char *m_data; // content of file
uint m_size; // length of content
};
// class based on the file mirror, that makes it easy to edit them outside the app.
// it receives an initial block of text from the engine, and hashes it. ("orig")
// it munges it by duplicating all the text after the "!!" line, and appending it in commented form. ("munged")
// a mirror file is activated, using a filename based on the hash from the orig text.
// if there is already content on disk matching that filename, use that content *unless* the 'blitz' parameter is set.
// (i.e. engine is instructing this subsystem to wipe out any old/modified variants of the text)
class CGLMEditableTextItem
{
public:
CGLMEditableTextItem( char *text, uint size, bool forceOverwrite, char *prefix, char *suffix = NULL ); // create a text blob from text source, optional filename suffix
~CGLMEditableTextItem( );
bool HasData( void );
bool PollForChanges( void ); // return true if stale i.e. you need to get a new edition
void GetCurrentText( char **textOut, uint *sizeOut ); // query for read access to the active blob (could be the original, could be external edited copy)
void OpenInEditor( bool foreground=false ); // call user attention to this text
// internal methods
void GenHashOfOrigText( void );
void GenBaseNameAndFullPath( char *prefix, char *suffix );
void GenMungedText( bool fromMirror );
// members
// orig
uint m_origSize;
char *m_origText; // what was submitted
unsigned char m_origDigest[MD5_DIGEST_LENGTH]; // digest of what was submitted
// munged
uint m_mungedSize;
char *m_mungedText; // re-processed edition, initial content submission to the file mirror
// mirror
char *m_mirrorBaseName; // generated from the hash of the orig text, plus the label / prefix
char *m_mirrorFullPath; // base name
CGLMFileMirror *m_mirror; // file mirror itself. holds "official" copy for GetCurrentText to return.
};
// debug font
extern unsigned char g_glmDebugFontMap[16384];
// class for cracking multi-part text blobs
// sections are demarcated by beginning-of-line markers submitted in a table by the caller
struct GLMTextSection
{
int m_markerIndex; // based on table of markers passed in to constructor
uint m_textOffset; // where is the text - offset
int m_textLength; // how big is the section
};
class CGLMTextSectioner
{
public:
CGLMTextSectioner( char *text, int textSize, const char **markers ); // constructor finds all the sections
~CGLMTextSectioner( );
int Count( void ); // how many sections found
void GetSection( int index, uint *offsetOut, uint *lengthOut, int *markerIndexOut );
// find section, size, what marker
// note that more than one section can be marked similarly.
// so policy isn't made here, you walk the sections and decide what to do if there are dupes.
//members
//section table
CUtlVector< GLMTextSection > m_sectionTable;
};
#ifndef OSX
void GLMGPUTimestampManagerInit();
void GLMGPUTimestampManagerDeinit();
void GLMGPUTimestampManagerTick();
#endif
#endif // GLMBASICS_H

View file

@ -0,0 +1,123 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glmgrext.h
// helper file for extension testing and runtime importing of entry points
//
//===============================================================================
#pragma once
#ifdef OSX
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#elif defined(DX_TO_GL_ABSTRACTION)
#include <GL/gl.h>
#include <GL/glext.h>
#else
#error
#endif
#ifndef GL_EXT_framebuffer_sRGB
#define GL_FRAMEBUFFER_SRGB_EXT 0x8DB9
#define GL_FRAMEBUFFER_SRGB_CAPABLE_EXT 0x8DBA
#endif
#ifndef ARB_texture_rg
#define GL_COMPRESSED_RED 0x8225
#define GL_COMPRESSED_RG 0x8226
#define GL_RG 0x8227
#define GL_RG_INTEGER 0x8228
#define GL_R8 0x8229
#define GL_R16 0x822A
#define GL_RG8 0x822B
#define GL_RG16 0x822C
#define GL_R16F 0x822D
#define GL_R32F 0x822E
#define GL_RG16F 0x822F
#define GL_RG32F 0x8230
#define GL_R8I 0x8231
#define GL_R8UI 0x8232
#define GL_R16I 0x8233
#define GL_R16UI 0x8234
#define GL_R32I 0x8235
#define GL_R32UI 0x8236
#define GL_RG8I 0x8237
#define GL_RG8UI 0x8238
#define GL_RG16I 0x8239
#define GL_RG16UI 0x823A
#define GL_RG32I 0x823B
#define GL_RG32UI 0x823C
#endif
#ifndef GL_EXT_bindable_uniform
#define GL_UNIFORM_BUFFER_EXT 0x8DEE
#endif
// unpublished extension enums (thus the "X")
// from EXT_framebuffer_multisample_blit_scaled..
#define XGL_SCALED_RESOLVE_FASTEST_EXT 0x90BA
#define XGL_SCALED_RESOLVE_NICEST_EXT 0x90BB
#ifndef GL_TEXTURE_MINIMIZE_STORAGE_APPLE
#define GL_TEXTURE_MINIMIZE_STORAGE_APPLE 0x85B6
#endif
#ifndef GL_ALL_COMPLETED_NV
#define GL_ALL_COMPLETED_NV 0x84F2
#endif
#ifndef GL_MAP_READ_BIT
#define GL_MAP_READ_BIT 0x0001
#endif
#ifndef GL_MAP_WRITE_BIT
#define GL_MAP_WRITE_BIT 0x0002
#endif
#ifndef GL_MAP_INVALIDATE_RANGE_BIT
#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
#endif
#ifndef GL_MAP_INVALIDATE_BUFFER_BIT
#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
#endif
#ifndef GL_MAP_FLUSH_EXPLICIT_BIT
#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
#endif
#ifndef GL_MAP_UNSYNCHRONIZED_BIT
#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
#endif
#ifndef GL_MAP_PERSISTENT_BIT
#define GL_MAP_PERSISTENT_BIT 0x0040
#endif
#ifndef GL_MAP_COHERENT_BIT
#define GL_MAP_COHERENT_BIT 0x0080
#endif

View file

@ -0,0 +1,73 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#ifndef RENDERMECHANISM_H
#define RENDERMECHANISM_H
#if defined(DX_TO_GL_ABSTRACTION)
#undef PROTECTED_THINGS_ENABLE
#include <GL/gl.h>
#include <GL/glext.h>
#include "tier0/basetypes.h"
#include "tier0/platform.h"
#include "togl/linuxwin/glmdebug.h"
#include "togl/linuxwin/glbase.h"
#include "togl/linuxwin/glentrypoints.h"
#include "togl/linuxwin/glmdisplay.h"
#include "togl/linuxwin/glmdisplaydb.h"
#include "togl/linuxwin/glmgrbasics.h"
#include "togl/linuxwin/glmgrext.h"
#include "togl/linuxwin/cglmbuffer.h"
#include "togl/linuxwin/cglmtex.h"
#include "togl/linuxwin/cglmfbo.h"
#include "togl/linuxwin/cglmprogram.h"
#include "togl/linuxwin/cglmquery.h"
#include "togl/linuxwin/glmgr.h"
#include "togl/linuxwin/dxabstract_types.h"
#include "togl/linuxwin/dxabstract.h"
#else
//USE_ACTUAL_DX
#ifdef WIN32
#ifdef _X360
#include "d3d9.h"
#include "d3dx9.h"
#else
#include <windows.h>
#include "../../dx9sdk/include/d3d9.h"
#include "../../dx9sdk/include/d3dx9.h"
#endif
typedef HWND VD3DHWND;
#endif
#define GLMPRINTF(args)
#define GLMPRINTSTR(args)
#define GLMPRINTTEXT(args)
#endif // defined(DX_TO_GL_ABSTRACTION)
#endif // RENDERMECHANISM_H

View file

@ -0,0 +1,17 @@
typedef unsigned int uint;
#include "../public/togl/linuxwin/glmdisplay.h"
#include "../public/togl/linuxwin/glmdisplaydb.h"
void GLMDisplayDB::PopulateRenderers( void ) { }
void GLMDisplayDB::PopulateFakeAdapters( uint realRendererIndex ) { } // fake adapters = one real adapter times however many displays are on
void GLMDisplayDB::Populate( void ) { }
int GLMDisplayDB::GetFakeAdapterCount( void ) { return 1; }
bool GLMDisplayDB::GetFakeAdapterInfo( int fakeAdapterIndex, int *rendererOut, int *displayOut, GLMRendererInfoFields *rendererInfoOut, GLMDisplayInfoFields *displayInfoOut ) { return true; }
int GLMDisplayDB::GetRendererCount( void ) { return 1; }
bool GLMDisplayDB::GetRendererInfo( int rendererIndex, GLMRendererInfoFields *infoOut ) { return true; }
int GLMDisplayDB::GetDisplayCount( int rendererIndex ) { return 1; }
bool GLMDisplayDB::GetDisplayInfo( int rendererIndex, int displayIndex, GLMDisplayInfoFields *infoOut ) { return true; }
int GLMDisplayDB::GetModeCount( int rendererIndex, int displayIndex ) { }
bool GLMDisplayDB::GetModeInfo( int rendererIndex, int displayIndex, int modeIndex, GLMDisplayModeInfoFields *infoOut ) { return false; }
void GLMDisplayDB::Dump( void ) { }

File diff suppressed because it is too large Load diff

355
togles/linuxwin/cglmfbo.cpp Normal file
View file

@ -0,0 +1,355 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmfbo.cpp
//
//===============================================================================
#include "togl/rendermechanism.h"
// memdbgon -must- be the last include file in a .cpp file.
#include "tier0/memdbgon.h"
CGLMFBO::CGLMFBO( GLMContext *ctx )
{
m_ctx = ctx;
m_ctx->CheckCurrent();
gGL->glGenFramebuffersEXT( 1, &m_name );
memset( m_attach, 0, sizeof( m_attach ) );
}
CGLMFBO::~CGLMFBO( )
{
m_ctx->CheckCurrent();
// detach all known attached textures first... necessary ?
for( int index = 0; index < kAttCount; index++)
{
if (m_attach[ index ].m_tex)
{
TexDetach( (EGLMFBOAttachment)index );
}
}
gGL->glDeleteFramebuffersEXT( 1, &m_name );
m_name = 0;
m_ctx = NULL;
}
// the tex attach path should also select a specific slice of the texture...
// and we need a way to make renderbuffers..
static GLenum EncodeAttachmentFBO( EGLMFBOAttachment index )
{
if (index < kAttDepth)
{
return GL_COLOR_ATTACHMENT0_EXT + (int) index;
}
else
{
switch( index )
{
case kAttDepth:
return GL_DEPTH_ATTACHMENT_EXT;
break;
case kAttStencil:
return GL_STENCIL_ATTACHMENT_EXT;
break;
case kAttDepthStencil:
return GL_DEPTH_STENCIL_ATTACHMENT_EXT;
break;
default:
GLMStop(); // bad news
break;
}
}
GLMStop(); // bad news
// shouldn't get here
return GL_COLOR_ATTACHMENT0_EXT;
}
void CGLMFBO::TexAttach( GLMFBOTexAttachParams *params, EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
{
// force our parent context to be current
m_ctx->MakeCurrent();
// bind to context (will cause FBO object creation on first use)
m_ctx->BindFBOToCtx( this, fboBindPoint );
// it's either a plain 2D, a 2D face of a cube map, or a slice of a 3D.
CGLMTex *tex = params->m_tex;
// always detach what is currently there, if anything
this->TexDetach( attachIndex, fboBindPoint );
if (!tex)
{
// andif they pass NULL to us, then we are done.
return;
}
GLMTexLayout *layout = tex->m_layout;
GLenum target = tex->m_layout->m_key.m_texGLTarget;
GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
switch( target )
{
case GL_TEXTURE_2D:
{
// we will attach the underlying RBO on a multisampled tex, iff the tex has one, **and** we're not being asked to attach it to the read buffer.
// if we get a req to attach an MSAA tex to the read buffer, chances are it's BlitTex calling, andit has already resolved the tex, so in those
// cases you really do want to attach the texture and not the RBO to the FBO in question.
bool useRBO = false; // initial state
if (layout->m_key.m_texFlags & kGLMTexMultisampled)
{
// it is an MSAA tex
if (fboBindPoint == GL_READ_FRAMEBUFFER_EXT)
{
// I think you just want to read a resolved tex.
// But I will check that it is resolved first..
Assert( tex->IsRBODirty() == false );
}
else
{
// you want to draw into it. You get the RBO bound instead of the tex.
useRBO = true;
}
}
if (useRBO)
{
// MSAA path - attach the RBO, not the texture, and mark the RBO dirty
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
{
// you have to attach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
// bind the RBO to the GL_RENDERBUFFER_EXT target
gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
// attach the GL_RENDERBUFFER_EXT target to the depth and stencil attach points
gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
gGL->glFramebufferRenderbufferEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, tex->m_rboName);
// no need to leave the RBO hanging on
gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
}
else
{
// color attachment (likely 0)
gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, tex->m_rboName );
gGL->glFramebufferRenderbufferEXT( fboBindPoint, attachIndexGL, GL_RENDERBUFFER_EXT, tex->m_rboName);
gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
}
tex->ForceRBODirty();
}
else
{
// regular path - attaching a texture2d
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
{
// you have to attach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, tex->m_texName, params->m_mip );
}
else
{
gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
}
}
}
break;
case GL_TEXTURE_3D:
{
gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip, params->m_zslice );
}
break;
case GL_TEXTURE_CUBE_MAP:
{
// adjust target to steer to the proper face of the cube map
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + params->m_face;
gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, tex->m_texName, params->m_mip );
}
break;
}
// log the attached tex
m_attach[ attachIndex ] = *params;
// indicate that the tex has been bound to an RT
tex->m_rtAttachCount++;
}
void CGLMFBO::TexDetach( EGLMFBOAttachment attachIndex, GLenum fboBindPoint )
{
// force our parent context to be current
m_ctx->MakeCurrent();
// bind to context (will cause FBO object creation on first use)
m_ctx->BindFBOToCtx( this, fboBindPoint );
if (m_attach[ attachIndex ].m_tex)
{
CGLMTex *tex = m_attach[ attachIndex ].m_tex;
GLMTexLayout *layout = tex->m_layout;
GLenum target = tex->m_layout->m_key.m_texGLTarget;
GLenum attachIndexGL = EncodeAttachmentFBO( attachIndex );
switch( target )
{
case GL_TEXTURE_2D:
{
if (layout->m_key.m_texFlags & kGLMTexMultisampled)
{
// MSAA path - detach the RBO, not the texture
// (is this the right time to resolve? probably better to wait until someone tries to sample the texture)
gGL->glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
{
// detach the GL_RENDERBUFFER_EXT target at depth and stencil attach points
gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0);
}
else
{
// color attachment (likely 0)
gGL->glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, attachIndexGL, GL_RENDERBUFFER_EXT, 0);
}
}
else
{
// plain tex detach
if (attachIndexGL==GL_DEPTH_STENCIL_ATTACHMENT_EXT)
{
// you have to detach it both places...
// http://www.opengl.org/wiki/GL_EXT_framebuffer_object
gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_DEPTH_ATTACHMENT_EXT, target, 0, 0 );
gGL->glFramebufferTexture2DEXT( fboBindPoint, GL_STENCIL_ATTACHMENT_EXT, target, 0, 0 );
}
else
{
gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
}
}
}
break;
case GL_TEXTURE_3D:
{
gGL->glFramebufferTexture3DEXT( fboBindPoint, attachIndexGL, target, 0, 0, 0 );
}
break;
case GL_TEXTURE_CUBE_MAP:
{
gGL->glFramebufferTexture2DEXT( fboBindPoint, attachIndexGL, target, 0, 0 );
}
break;
}
// un-log the attached tex
memset( &m_attach[ attachIndex ], 0, sizeof( m_attach[0] ) );
// drop the RT attach count
tex->m_rtAttachCount--;
}
else
{
//Debugger(); // odd, but not harmful - typ comes from D3D code passing NULL into SetRenderTarget
}
}
void CGLMFBO::TexScrub( CGLMTex *tex )
{
// see if it's attached anywhere
for( int attachIndex = 0; attachIndex < kAttCount; attachIndex++ )
{
if (m_attach[ attachIndex ].m_tex == tex)
{
// blammo
TexDetach( (EGLMFBOAttachment)attachIndex, GL_DRAW_FRAMEBUFFER_EXT );
}
}
}
bool CGLMFBO::IsReady( void )
{
bool result = false;
// ensure our parent context is current
m_ctx->CheckCurrent();
// bind to context (will cause FBO object creation on first use)
m_ctx->BindFBOToCtx( this );
GLenum status;
status = gGL->glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch(status)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
result = true;
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
result = false;
DebuggerBreak();
/* choose different formats */
break;
default:
result = false;
DebuggerBreak();
/* programming error; will fail on all hardware */
break;
}
return result;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,363 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// cglmquery.cpp
//
//===============================================================================
#include "togl/rendermechanism.h"
#ifndef _WIN32
#include <unistd.h>
#endif
// memdbgon -must- be the last include file in a .cpp file.
#include "tier0/memdbgon.h"
//===============================================================================
// http://www.opengl.org/registry/specs/ARB/occlusion_query.txt
// Workaround for "Calling either GenQueriesARB or DeleteQueriesARB while any query of any target is active causes an INVALID_OPERATION error to be generated."
uint CGLMQuery::s_nTotalOcclusionQueryCreatesOrDeletes;
extern ConVar gl_errorcheckall;
extern ConVar gl_errorcheckqueries;
extern ConVar gl_errorchecknone;
// how many microseconds to wait after a failed query-available test
// presently on MTGL this doesn't happen, but it could change, keep this handy
ConVar gl_nullqueries( "gl_nullqueries", "0" );
//===============================================================================
CGLMQuery::CGLMQuery( GLMContext *ctx, GLMQueryParams *params )
{
// get the type of query requested
// generate name(s) needed
// set initial state appropriately
m_ctx = ctx;
m_params = *params;
m_name = 0;
m_syncobj = 0;
m_started = m_stopped = m_done = false;
m_nullQuery = false;
// assume value of convar at start time
// does not change during individual query lifetime
// started null = stays null
// started live = stays live
switch(m_params.m_type)
{
case EOcclusion:
{
//make an occlusion query (and a fence to go with it)
gGL->glGenQueriesARB( 1, &m_name );
s_nTotalOcclusionQueryCreatesOrDeletes++;
GLMPRINTF(("-A- CGLMQuery(OQ) created name %d", m_name));
}
break;
case EFence:
//make a fence - no aux fence needed
m_syncobj = 0;
if (gGL->m_bHave_GL_ARB_sync)
{ /* GL_ARB_sync doesn't separate gen and set, so we do glFenceSync() later. */ }
else if (gGL->m_bHave_GL_NV_fence)
gGL->glGenFencesNV(1, &m_name );
else if (gGL->m_bHave_GL_APPLE_fence)
gGL->glGenFencesAPPLE(1, &m_name );
GLMPRINTF(("-A- CGLMQuery(fence) created name %d", m_name));
break;
}
}
CGLMQuery::~CGLMQuery()
{
GLMPRINTF(("-A-> ~CGLMQuery"));
// make sure query has completed (might not be necessary)
// delete the name(s)
switch(m_params.m_type)
{
case EOcclusion:
{
// do a finish occlusion query ?
GLMPRINTF(("-A- ~CGLMQuery(OQ) deleting name %d", m_name));
gGL->glDeleteQueriesARB(1, &m_name );
s_nTotalOcclusionQueryCreatesOrDeletes++;
}
break;
case EFence:
{
// do a finish fence ?
GLMPRINTF(("-A- ~CGLMQuery(fence) deleting name %llu", gGL->m_bHave_GL_ARB_sync ? (unsigned long long) m_syncobj : (unsigned long long) m_name));
#ifdef HAVE_GL_ARB_SYNC
if (gGL->m_bHave_GL_ARB_sync)
gGL->glDeleteSync( m_syncobj );
else
#endif
if (gGL->m_bHave_GL_NV_fence)
gGL->glDeleteFencesNV(1, &m_name );
else if (gGL->m_bHave_GL_APPLE_fence)
gGL->glDeleteFencesAPPLE(1, &m_name );
}
break;
}
m_name = 0;
m_syncobj = 0;
GLMPRINTF(("-A-< ~CGLMQuery"));
}
void CGLMQuery::Start( void ) // "start counting"
{
m_nullQuery = (gl_nullqueries.GetInt() != 0); // latch value for remainder of query life
m_started = true;
m_stopped = false;
m_done = false;
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
// do nothing..
}
else
{
gGL->glBeginQueryARB( GL_SAMPLES_PASSED_ARB, m_name );
}
}
break;
case EFence:
#ifdef HAVE_GL_ARB_SYNC
if (gGL->m_bHave_GL_ARB_sync)
{
if (m_syncobj != 0) gGL->glDeleteSync(m_syncobj);
m_syncobj = gGL->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
}
else
#endif
if (gGL->m_bHave_GL_NV_fence)
gGL->glSetFenceNV( m_name, GL_ALL_COMPLETED_NV );
else if (gGL->m_bHave_GL_APPLE_fence)
gGL->glSetFenceAPPLE( m_name );
m_stopped = true; // caller should not call Stop on a fence, it self-stops
break;
}
}
void CGLMQuery::Stop( void ) // "stop counting"
{
Assert(m_started);
if ( m_stopped )
return;
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
// do nothing..
}
else
{
gGL->glEndQueryARB( GL_SAMPLES_PASSED_ARB ); // we are only putting the request-to-stop-counting into the cmd stream.
}
}
break;
case EFence:
// nop - you don't "end" a fence, you just test it and/or finish it out in Complete
break;
}
m_stopped = true;
}
bool CGLMQuery::IsDone( void )
{
Assert(m_started);
Assert(m_stopped);
if(!m_done) // you can ask more than once, but we only check until it comes back as done.
{
// on occlusion: glGetQueryObjectivARB - large cost on pre SLGU, cheap after
// on fence: glTestFence* on the fence
switch(m_params.m_type)
{
case EOcclusion: // just test the fence that was set after the query begin
{
if (m_nullQuery)
{
// do almost nothing.. but claim work is complete
m_done = true;
}
else
{
// prepare to pay a big price on drivers prior to 10.6.4+SLGU
GLint available = 0;
gGL->glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
m_done = (available != 0);
}
}
break;
case EFence:
{
#ifdef HAVE_GL_ARB_SYNC
if (gGL->m_bHave_GL_ARB_sync)
m_done = (gGL->glClientWaitSync( m_syncobj, 0, 0 ) == GL_ALREADY_SIGNALED);
else
#endif
if ( m_name == 0 )
m_done = true;
else if (gGL->m_bHave_GL_NV_fence)
m_done = gGL->glTestFenceNV( m_name ) != 0;
else if (gGL->m_bHave_GL_APPLE_fence)
m_done = gGL->glTestFenceAPPLE( m_name ) != 0;
if (m_done)
{
if (gGL->m_bHave_GL_ARB_sync)
{ /* no-op; we already know it's set to GL_ALREADY_SIGNALED. */ }
else
{
if (gGL->m_bHave_GL_NV_fence)
gGL->glFinishFenceNV( m_name ); // no set fence goes un-finished
else if (gGL->m_bHave_GL_APPLE_fence)
gGL->glFinishFenceAPPLE( m_name ); // no set fence goes un-finished
}
}
}
break;
}
}
return m_done;
}
void CGLMQuery::Complete( uint *result )
{
uint resultval = 0;
//bool bogus_available = false;
// blocking call if not done
Assert(m_started);
Assert(m_stopped);
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
m_done = true;
resultval = 0; // we did say "null queries..."
}
else
{
gGL->glGetQueryObjectuivARB( m_name, GL_QUERY_RESULT_ARB, &resultval);
m_done = true;
}
}
break;
case EFence:
{
if(!m_done)
{
#ifdef HAVE_GL_ARB_SYNC
if (gGL->m_bHave_GL_ARB_sync)
{
if (gGL->glClientWaitSync( m_syncobj, 0, 0 ) != GL_ALREADY_SIGNALED)
{
GLenum syncstate;
do {
const GLuint64 timeout = 10 * ((GLuint64)1000 * 1000 * 1000); // 10 seconds in nanoseconds.
(void)timeout;
syncstate = gGL->glClientWaitSync( m_syncobj, GL_SYNC_FLUSH_COMMANDS_BIT, 0 );
} while (syncstate == GL_TIMEOUT_EXPIRED); // any errors or success break out of this loop.
}
}
else
#endif
if (gGL->m_bHave_GL_NV_fence)
gGL->glFinishFenceNV( m_name );
else if (gGL->m_bHave_GL_APPLE_fence)
gGL->glFinishFenceAPPLE( m_name );
m_done = true; // for clarity or if they try to Complete twice
}
}
break;
}
Assert( m_done );
// reset state for re-use - i.e. you have to call Complete if you want to re-use the object
m_started = m_stopped = m_done = false;
if (result) // caller may pass NULL if not interested in result, for example to clear a fence
{
*result = resultval;
}
}
// accessors for the started/stopped state
bool CGLMQuery::IsStarted ( void )
{
return m_started;
}
bool CGLMQuery::IsStopped ( void )
{
return m_stopped;
}

1990
togles/linuxwin/cglmtex.cpp Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,261 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//------------------------------------------------------------------------------
// DX9AsmToGL2.h
//------------------------------------------------------------------------------
#ifndef DX9_ASM_TO_GL_2_H
#define DX9_ASM_TO_GL_2_H
#include "tier1/utlstring.h"
#define DISASM_OK 0
#define DISASM_ERROR 1
#define MAX_SHADER_CONSTANTS 512
#define MAX_DECLARED_OUTPUTS 32
#define MAX_DECLARED_INPUTS 32
#define HEXCODE_HEADER "// Hex: "
// Option bits
#define D3DToGL_OptionUseEnvParams 0x0001
#define D3DToGL_OptionDoFixupZ 0x0002 // Add instructions to put Z in the right interval for GL
#define D3DToGL_OptionDoFixupY 0x0004 // Add instructions to flip the Y over for GL
#define D3DToGL_OptionDoUserClipPlanes 0x0008 // ARB mode: Include OPTION vertex_program_2 and append DP4's to write into oCLP[0] and oCLP[1]
// GLSL mode: generate code to write gl_ClipVertex
#define D3DToGL_AddHexComments 0x0020 // Include hex comments in the code for debugging
#define D3DToGL_PutHexCommentsAfterLines 0x0040 // If D3DToGL_AddHexComments is set, this puts the codes to the right, rather than on separate lines
#define D3DToGL_GeneratingDebugText 0x0080 // This tells it that we're just getting info for debugging so go easy on asserts and errors
#define D3DToGL_OptionSRGBWriteSuffix 0x0400 // Tack sRGB conversion suffix on to pixel shaders
#define D3DToGL_OptionGenerateBoneUniformBuffer 0x0800 // if enabled, the vertex shader "bone" registers (all regs DXABSTRACT_VS_FIRST_BONE_SLOT and higher) will be separated out into another uniform buffer (vcbone)
#define D3DToGL_OptionUseBindlessTexturing 0x1000
#define D3DToGL_OptionSpew 0x80000000
// Code for which component of the "dummy" address register is needed by an instruction
#define ARL_DEST_NONE -1
#define ARL_DEST_X 0
#define ARL_DEST_Y 1
#define ARL_DEST_Z 2
#define ARL_DEST_W 3
class D3DToGL
{
private:
// Pointers for dwToken stream management
uint32* m_pdwBaseToken;
uint32* m_pdwNextToken;
// Vertex shader or pixel shader, and version (necessary because some opcodes alias)
bool m_bVertexShader;
uint32 m_dwMinorVersion;
uint32 m_dwMajorVersion;
// Option flags
bool m_bUseEnvParams; // set D3DToGL_OptionUseEnvParams in 'options' to use
bool m_bDoFixupZ; // set D3DToGL_OptionDoFixupZ
bool m_bDoFixupY; // set D3DToGL_OptionDoFixupZ
bool m_bDoUserClipPlanes; // set D3DToGL_OptionDoUserClipPlanes
bool m_bSpew; // set D3DToGL_OptionSpew
bool m_bGenerateSRGBWriteSuffix; // set D3DToGL_OptionSRGBWriteSuffix
bool m_bGenerateBoneUniformBuffer;
bool m_bUseBindlessTexturing;
// Counter for dealing with nested loops
int m_nLoopDepth;
// Add "// Hex: 0xFFEEF00"-type statements after each instruction is parsed.
bool m_bAddHexCodeComments; // set D3DToGL_AddHexComments
// Only applicable if m_bAddHexCodeComments is true.
// If this is true, then it puts the hex code comments to the right of the instructions in a comment
// rather than preceding the instructions.
// Defaults to FALSE.
bool m_bPutHexCodesAfterLines; // set D3DToGL_PutHexCommentsAtEnd
// This tells it that we're just getting info for debugging so go easy on asserts and errors.
// Defaults to FALSE.
bool m_bGeneratingDebugText;
// Various scratch temps needed to handle mis-matches in instruction sets between D3D and OpenGL
bool m_bNeedsD2AddTemp;
bool m_bNeedsNRMTemp;
bool m_bDeclareAddressReg;
bool m_bNeedsLerpTemp;
bool m_bNeedsSinCosDeclarations;
// Keep track of which vs outputs are used so we can declare them
bool m_bDeclareVSOPos;
bool m_bDeclareVSOFog;
uint32 m_dwTexCoordOutMask;
int32 m_nVSPositionOutput;
// Mask of varyings which need centroid decoration
uint32 m_nCentroidMask;
// Keep track of which temps are used so they can be declared
uint32 m_dwTempUsageMask;
uint32 m_dwTempBoolUsageMask;
bool m_bOutputColorRegister[4];
bool m_bOutputDepthRegister;
// Declaration of integer and bool constants
uint32 m_dwConstIntUsageMask;
uint32 m_dwConstBoolUsageMask;
uint32 m_dwDefConstIntUsageMask;
uint32 m_dwDefConstIntIterCount[32];
// Did we use atomic_temp_var?
bool m_bUsedAtomicTempVar;
// Track constants so we know how to declare them
bool m_bConstantRegisterDefined[MAX_SHADER_CONSTANTS];
// Track sampler types when declared so we can properly decorate TEX instructions
uint32 m_dwSamplerTypes[32];
// Track sampler usage
uint32 m_dwSamplerUsageMask;
// Track shadow sampler usage
int m_nShadowDepthSamplerMask;
bool m_bDeclareShadowOption;
// Track attribute references
// init to 0xFFFFFFFF (unhit)
// index by (dwRegToken & D3DSP_REGNUM_MASK) in VS DCL insns
// fill with (usage<<4) | (usage index).
uint32 m_dwAttribMap[16];
// Register high water mark
uint32 m_nHighestRegister;
int32 m_nHighestBoneRegister;
// GLSL does indentation for readability
int m_NumIndentTabs;
// Output buffers.
CUtlBuffer *m_pBufHeaderCode;
CUtlBuffer *m_pBufAttribCode;
CUtlBuffer *m_pBufParamCode;
CUtlBuffer *m_pBufALUCode;
char *m_pFinalAssignmentsCode;
int m_nFinalAssignmentsBufSize;
// Recorded positions for debugging.
uint32* m_pRecordedInputTokenStart;
int m_nRecordedParamCodeStrlen;
int m_nRecordedALUCodeStrlen;
int m_nRecordedAttribCodeStrlen;
// In GLSL mode, these store the semantic attached to each oN register.
// They are the values that you pass to GetUsageIndexAndString.
uint32 m_DeclaredOutputs[MAX_DECLARED_OUTPUTS];
uint32 m_DeclaredInputs[MAX_DECLARED_INPUTS];
// Have they used the tangent input semantic (i.e. is g_pTangentAttributeName declared)?
bool m_bTangentInputUsed;
bool m_bUsesDSTInstruction;
private:
// Utilities to aid in decoding token stream
uint32 GetNextToken( void );
void SkipTokens( uint32 numToSkip );
uint32 Opcode( uint32 dwToken );
uint32 OpcodeSpecificData( uint32 dwToken );
uint32 TextureType ( uint32 dwToken );
uint32 GetRegType( uint32 dwRegToken );
// Write to the different buffers.
void StrcatToHeaderCode( const char *pBuf );
void StrcatToALUCode( const char *pBuf );
void StrcatToParamCode( const char *pBuf );
void StrcatToAttribCode( const char *pBuf );
void PrintToBufWithIndents( CUtlBuffer &buf, const char *pFormat, ... );
// This helps write the token hex codes into the output stream for debugging.
void AddTokenHexCodeToBuffer( char *pBuffer, int nSize, int nLastStrlen );
void RecordInputAndOutputPositions();
void AddTokenHexCode();
// Utilities for decoding tokens in to strings according to ASM syntax
void PrintOpcode( uint32 inst, char* buff, int nBufLen );
// fSemanticFlags is SEMANTIC_INPUT or SEMANTIC_OUTPUT.
void PrintUsageAndIndexToString( uint32 dwToken, char* strUsageUsageIndexName, int nBufLen, int fSemanticFlags );
CUtlString GetUsageAndIndexString( uint32 dwToken, int fSemanticFlags );
CUtlString GetParameterString( uint32 dwToken, uint32 dwSourceOrDest, bool bForceScalarSource, int *pARLDestReg );
const char* GetGLSLOperatorString( uint32 inst );
void PrintParameterToString ( uint32 dwToken, uint32 dwSourceOrDest, char *pRegisterName, int nBufLen, bool bForceScalarSource, int *pARLDestReg );
void InsertMoveFromAddressRegister( CUtlBuffer *pCode, int nARLComp0, int nARLComp1, int nARLComp2 = ARL_DEST_NONE );
void InsertMoveInstruction( CUtlBuffer *pCode, int nARLComponent );
void FlagIndirectRegister( uint32 dwToken, int *pARLDestReg );
// Utilities for decoding tokens in to strings according to GLSL syntax
bool OpenIntrinsic( uint32 inst, char* buff, int nBufLen, uint32 destDimension, uint32 nArgumentDimension );
void PrintIndentation( char *pBuf, int nBufLen );
uint32 MaintainAttributeMap( uint32 dwToken, uint32 dwRegToken );
CUtlString FixGLSLSwizzle( const char *pDestRegisterName, const char *pSrcRegisterName );
void WriteGLSLCmp( const char *pDestReg, const char *pSrc0Reg, const char *pSrc1Reg, const char *pSrc2Reg );
void WriteGLSLSamplerDefinitions();
void WriteGLSLOutputVariableAssignments();
void WriteGLSLInputVariableAssignments();
void NoteTangentInputUsed();
void Handle_DCL();
void Handle_DEF();
void Handle_DEFIB( uint32 nInstruction );
void Handle_MAD( uint32 nInstruction );
void Handle_DP2ADD();
void Handle_SINCOS();
void Handle_LRP( uint32 nInstruction );
void Handle_TEX( uint32 dwToken, bool bIsTexLDL );
void Handle_TexLDD( uint32 nInstruction );
void Handle_TexCoord();
void Handle_UnaryOp( uint32 nInstruction );
void Handle_BREAKC( uint32 dwToken );
void HandleBinaryOp_GLSL( uint32 nInstruction );
void HandleBinaryOp_ASM( uint32 nInstruction );
void Handle_CMP();
void Handle_NRM();
void Handle_DeclarativeNonDclOp( uint32 nInstruction );
public:
D3DToGL();
int TranslateShader( uint32* code, CUtlBuffer *pBufDisassembledCode, bool *bVertexShader, uint32 options, int32 nShadowDepthSamplerMask, uint32 nCentroidMask, char *debugLabel );
};
#endif // DX9_ASM_TO_GL_2_H

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,512 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// glentrypoints.cpp
//
//=============================================================================//
// Immediately include gl.h, etc. here to avoid compilation warnings.
#include "togl/rendermechanism.h"
#include "appframework/AppFramework.h"
#include "appframework/IAppSystemGroup.h"
#include "tier0/dbg.h"
#include "tier0/icommandline.h"
#include "tier0/platform.h"
#include "interface.h"
#include "filesystem.h"
#include "filesystem_init.h"
#include "tier1/convar.h"
#include "vstdlib/cvar.h"
#include "inputsystem/ButtonCode.h"
#include "tier1.h"
#include "tier2/tier2.h"
#if defined(_LINUX) && !defined(__ANDROID__)
#include <GL/glx.h>
#endif
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
#if !defined(DX_TO_GL_ABSTRACTION)
#error
#endif
#if defined(OSX) || defined(LINUX) || (defined (WIN32) && defined( DX_TO_GL_ABSTRACTION ))
#include "appframework/ilaunchermgr.h"
ILauncherMgr *g_pLauncherMgr = NULL;
#endif
#define DEBUG_ALL_GLCALLS 0
#if DEBUG_ALL_GLCALLS
bool g_bDebugOpenGLCalls = true;
bool g_bPrintOpenGLCalls = false;
#define GL_EXT(x,glmajor,glminor)
#define GL_FUNC(ext,req,ret,fn,arg,call) \
static ret (*fn##_gldebugptr) arg = NULL; \
static ret fn##_gldebug arg { \
if (!g_bDebugOpenGLCalls) { return fn##_gldebugptr call; } \
if (g_bPrintOpenGLCalls) { \
printf("Calling %s ... ", #fn); \
fflush(stdout); \
} \
ret retval = fn##_gldebugptr call; \
if (g_bPrintOpenGLCalls) { \
printf("%s returned!\n", #fn); \
fflush(stdout); \
} \
const GLenum err = glGetError_gldebugptr(); \
if ( err == GL_INVALID_FRAMEBUFFER_OPERATION_EXT ) { \
const GLenum fberr = gGL->glCheckFramebufferStatus( GL_FRAMEBUFFER_EXT ); \
printf("%s triggered error GL_INVALID_FRAMEBUFFER_OPERATION_EXT! (0x%X)\n\n\n", #fn, (int) fberr); \
fflush(stdout); \
__asm__ __volatile__ ( "int $3\n\t" ); \
} else if (err != GL_NO_ERROR) { \
printf("%s triggered error 0x%X!\n\n\n", #fn, (int) err); \
fflush(stdout); \
__asm__ __volatile__ ( "int $3\n\t" ); \
} \
return retval; \
}
#define GL_FUNC_VOID(ext,req,fn,arg,call) \
static void (*fn##_gldebugptr) arg = NULL; \
static void fn##_gldebug arg { \
if (!g_bDebugOpenGLCalls) { fn##_gldebugptr call; return; } \
if (g_bPrintOpenGLCalls) { \
printf("Calling %s ... ", #fn); \
fflush(stdout); \
} \
fn##_gldebugptr call; \
if (g_bPrintOpenGLCalls) { \
printf("%s returned!\n", #fn); \
fflush(stdout); \
} \
const GLenum err = glGetError_gldebugptr(); \
if ( err == GL_INVALID_FRAMEBUFFER_OPERATION_EXT ) { \
const GLenum fberr = gGL->glCheckFramebufferStatus( GL_FRAMEBUFFER_EXT ); \
printf("%s triggered error GL_INVALID_FRAMEBUFFER_OPERATION_EXT! (0x%X)\n\n\n", #fn, (int) fberr); \
fflush(stdout); \
__asm__ __volatile__ ( "int $3\n\t" ); \
} else if (err != GL_NO_ERROR) { \
printf("%s triggered error 0x%X!\n\n\n", #fn, (int) err); \
fflush(stdout); \
__asm__ __volatile__ ( "int $3\n\t" ); \
} \
}
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
#endif
COpenGLEntryPoints *gGL = NULL;
GL_GetProcAddressCallbackFunc_t gGL_GetProcAddressCallback = NULL;
void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired, void *fallback)
{
void *retval = NULL;
if ((!okay) && (!bRequired)) // always look up if required (so we get a complete list of crucial missing symbols).
return NULL;
// SDL does the right thing, so we never need to use tier0 in this case.
retval = (*gGL_GetProcAddressCallback)(fn, okay, bRequired, fallback);
//printf("CDynamicFunctionOpenGL: SDL_GL_GetProcAddress(\"%s\") returned %p\n", fn, retval);
if ((retval == NULL) && (fallback != NULL))
{
//printf("CDynamicFunctionOpenGL: Using fallback %p for \"%s\"\n", fallback, fn);
retval = fallback;
}
// Note that a non-NULL response doesn't mean it's safe to call the function!
// You always have to check that the extension is supported;
// an implementation MAY return NULL in this case, but it doesn't have to (and doesn't, with the DRI drivers).
okay = (okay && (retval != NULL));
if (bRequired && !okay)
fprintf(stderr, "Could not find required OpenGL entry point '%s'!\n", fn);
return retval;
}
COpenGLEntryPoints *GetOpenGLEntryPoints(GL_GetProcAddressCallbackFunc_t callback)
{
if (gGL == NULL)
{
gGL_GetProcAddressCallback = callback;
gGL = new COpenGLEntryPoints();
if (!gGL->m_bHave_OpenGL)
Error( "Missing basic required OpenGL functionality." );
}
return gGL;
}
void ClearOpenGLEntryPoints()
{
if ( gGL )
{
gGL->ClearEntryPoints();
}
}
COpenGLEntryPoints *ToGLConnectLibraries( CreateInterfaceFn factory )
{
ConnectTier1Libraries( &factory, 1 );
ConVar_Register();
ConnectTier2Libraries( &factory, 1 );
if ( !g_pFullFileSystem )
{
Warning( "ToGL was unable to access the required interfaces!\n" );
}
// NOTE! : Overbright is 1.0 so that Hammer will work properly with the white bumped and unbumped lightmaps.
MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f );
#if defined( USE_SDL )
g_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL );
#endif
return gGL;
}
void ToGLDisconnectLibraries()
{
DisconnectTier2Libraries();
ConVar_Unregister();
DisconnectTier1Libraries();
}
#define GLVERNUM(Major, Minor, Patch) (((Major) * 100000) + ((Minor) * 1000) + (Patch))
static void GetOpenGLVersion(int *major, int *minor, int *patch)
{
*major = *minor = *patch = 0;
static CDynamicFunctionOpenGL< true, const GLubyte *( APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString");
if (glGetString)
{
const char *version = (const char *) glGetString(GL_VERSION);
if (version)
{
sscanf( version, "%d.%d.%d", major, minor, patch );
}
}
}
static int GetOpenGLVersionMajor()
{
int major, minor, patch;
GetOpenGLVersion(&major, &minor, &patch);
return major;
}
static int GetOpenGLVersionMinor()
{
int major, minor, patch;
GetOpenGLVersion(&major, &minor, &patch);
return minor;
}
static int GetOpenGLVersionPatch()
{
int major, minor, patch;
GetOpenGLVersion(&major, &minor, &patch);
return patch;
}
static bool CheckBaseOpenGLVersion()
{
const int NEED_MAJOR = 2;
const int NEED_MINOR = 0;
const int NEED_PATCH = 0;
int major, minor, patch;
GetOpenGLVersion(&major, &minor, &patch);
const int need = GLVERNUM(NEED_MAJOR, NEED_MINOR, NEED_PATCH);
const int have = GLVERNUM(major, minor, patch);
if (have < need)
{
fprintf(stderr, "PROBLEM: You appear to have OpenGL %d.%d.%d, but we need at least %d.%d.%d!\n",
major, minor, patch, NEED_MAJOR, NEED_MINOR, NEED_PATCH);
return false;
}
return true;
}
static bool CheckOpenGLExtension_internal(const char *ext, const int coremajor, const int coreminor)
{
if ((coremajor >= 0) && (coreminor >= 0)) // we know that this extension is part of the base spec as of GL_VERSION coremajor.coreminor.
{
int major, minor, patch;
GetOpenGLVersion(&major, &minor, &patch);
const int need = GLVERNUM(coremajor, coreminor, 0);
const int have = GLVERNUM(major, minor, patch);
if (have >= need)
return true; // we definitely have access to this "extension," as it is part of this version of the GL's core functionality.
}
// okay, see if the GL_EXTENSIONS string reports it.
static CDynamicFunctionOpenGL< true, const GLubyte *( APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString");
if (!glGetString)
return false;
// hacky scanning of this string, because I don't want to spend time breaking it into a vector like I should have.
const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
const size_t extlen = strlen(ext);
while ((extensions) && (*extensions))
{
const char *ptr = strstr(extensions, ext);
#if _WIN32
if (!ptr)
{
static CDynamicFunctionOpenGL< true, const char *( APIENTRY *)( ), const char * > wglGetExtensionsStringEXT("wglGetExtensionsStringEXT");
if (wglGetExtensionsStringEXT)
{
extensions = wglGetExtensionsStringEXT();
ptr = strstr(extensions, ext);
}
if (!ptr)
{
return false;
}
}
#elif !defined ( OSX ) && !defined( __ANDROID__ )
if (!ptr)
{
static CDynamicFunctionOpenGL< true, Display *( APIENTRY *)( ), Display* > glXGetCurrentDisplay("glXGetCurrentDisplay");
static CDynamicFunctionOpenGL< true, const char *( APIENTRY *)( Display*, int ), const char * > glXQueryExtensionsString("glXQueryExtensionsString");
if (glXQueryExtensionsString && glXGetCurrentDisplay)
{
extensions = glXQueryExtensionsString(glXGetCurrentDisplay(), 0);
ptr = strstr(extensions, ext);
}
}
#endif
if (!ptr)
return false;
// make sure this matches the entire string, and isn't a substring match of some other extension.
// if ( ( (string is at start of extension list) or (the char before the string is a space) ) and
// (the next char after the string is a space or a null terminator) )
if ( ((ptr == extensions) || (ptr[-1] == ' ')) &&
((ptr[extlen] == ' ') || (ptr[extlen] == '\0')) )
return true; // found it!
extensions = ptr + extlen; // skip ahead, search again.
}
return false;
}
static bool CheckOpenGLExtension(const char *ext, const int coremajor, const int coreminor)
{
const bool retval = CheckOpenGLExtension_internal(ext, coremajor, coreminor);
printf("This system %s the OpenGL extension %s.\n", retval ? "supports" : "DOES NOT support", ext);
return retval;
}
// The GL context you want entry points for must be current when you hit this constructor!
COpenGLEntryPoints::COpenGLEntryPoints()
: m_nTotalGLCycles(0)
, m_nTotalGLCalls(0)
, m_nOpenGLVersionMajor(GetOpenGLVersionMajor())
, m_nOpenGLVersionMinor(GetOpenGLVersionMinor())
, m_nOpenGLVersionPatch(GetOpenGLVersionPatch())
, m_bHave_OpenGL(CheckBaseOpenGLVersion()) // may reset to false as these lookups happen.
#define GL_EXT(x,glmajor,glminor) , m_bHave_##x(CheckOpenGLExtension(#x, glmajor, glminor))
#define GL_FUNC(ext,req,ret,fn,arg,call) , fn(#fn, m_bHave_##ext)
#define GL_FUNC_VOID(ext,req,fn,arg,call) , fn(#fn, m_bHave_##ext)
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
{
// Locally cache the copy of the GL device strings, to avoid needing to call these glGet's (which can be extremely slow) more than once.
const char *pszString = ( const char * )glGetString(GL_VENDOR);
m_pGLDriverStrings[cGLVendorString] = strdup( pszString ? pszString : "" );
m_nDriverProvider = cGLDriverProviderUnknown;
if ( V_stristr( m_pGLDriverStrings[cGLVendorString], "nvidia" ) )
m_nDriverProvider = cGLDriverProviderNVIDIA;
else if ( V_stristr( m_pGLDriverStrings[cGLVendorString], "amd" ) || V_stristr( m_pGLDriverStrings[cGLVendorString], "ati" ) )
m_nDriverProvider = cGLDriverProviderAMD;
else if ( V_stristr( m_pGLDriverStrings[cGLVendorString], "intel" ) )
m_nDriverProvider = cGLDriverProviderIntelOpenSource;
else if ( V_stristr( m_pGLDriverStrings[cGLVendorString], "apple" ) )
m_nDriverProvider = cGLDriverProviderApple;
pszString = ( const char * )glGetString(GL_RENDERER);
m_pGLDriverStrings[cGLRendererString] = strdup( pszString ? pszString : "" );
pszString = ( const char * )glGetString(GL_VERSION);
m_pGLDriverStrings[cGLVersionString] = strdup( pszString ? pszString : "" );
pszString = ( const char * )glGetString(GL_EXTENSIONS);
m_pGLDriverStrings[cGLExtensionsString] = strdup( pszString ? pszString : "" );
printf( "OpenGL: %s %s (%d.%d.%d)\n", m_pGLDriverStrings[ cGLRendererString ], m_pGLDriverStrings[ cGLVersionString ],
m_nOpenGLVersionMajor, m_nOpenGLVersionMinor, m_nOpenGLVersionPatch );
// !!! FIXME: Alfred says the original GL_APPLE_fence code only exists to
// !!! FIXME: hint Apple's drivers and not because we rely on the
// !!! FIXME: functionality. If so, just remove this check (and the
// !!! FIXME: GL_NV_fence code entirely).
#ifndef ANDROID // HACK
if ((m_bHave_OpenGL) && ((!m_bHave_GL_NV_fence) && (!m_bHave_GL_ARB_sync) && (!m_bHave_GL_APPLE_fence)))
{
Error( "Required OpenGL extension \"GL_NV_fence\", \"GL_ARB_sync\", or \"GL_APPLE_fence\" is not supported. Please upgrade your OpenGL driver." );
}
#endif
// same extension, different name.
if (m_bHave_GL_EXT_vertex_array_bgra || m_bHave_GL_ARB_vertex_array_bgra)
{
m_bHave_GL_EXT_vertex_array_bgra = m_bHave_GL_ARB_vertex_array_bgra = true;
}
// GL_ARB_framebuffer_object is a superset of GL_EXT_framebuffer_object,
// (etc) but if you don't call in through the ARB entry points, you won't
// get the relaxed restrictions on mismatched attachment dimensions.
if (m_bHave_GL_ARB_framebuffer_object)
{
m_bHave_GL_EXT_framebuffer_object = true;
m_bHave_GL_EXT_framebuffer_blit = true;
m_bHave_GL_EXT_framebuffer_multisample = true;
glBindFramebufferEXT.Force(glBindFramebuffer.Pointer());
glBindRenderbufferEXT.Force(glBindRenderbuffer.Pointer());
glCheckFramebufferStatusEXT.Force(glCheckFramebufferStatus.Pointer());
glDeleteRenderbuffersEXT.Force(glDeleteRenderbuffers.Pointer());
glFramebufferRenderbufferEXT.Force(glFramebufferRenderbuffer.Pointer());
glFramebufferTexture2DEXT.Force(glFramebufferTexture2D.Pointer());
glFramebufferTexture3DEXT.Force(glFramebufferTexture3D.Pointer());
glGenFramebuffersEXT.Force(glGenFramebuffers.Pointer());
glGenRenderbuffersEXT.Force(glGenRenderbuffers.Pointer());
glDeleteFramebuffersEXT.Force(glDeleteFramebuffers.Pointer());
glBlitFramebufferEXT.Force(glBlitFramebuffer.Pointer());
glRenderbufferStorageMultisampleEXT.Force(glRenderbufferStorageMultisample.Pointer());
}
#if DEBUG_ALL_GLCALLS
// push all GL calls through the debug wrappers.
#define GL_EXT(x,glmajor,glminor)
#define GL_FUNC(ext,req,ret,fn,arg,call) \
fn##_gldebugptr = this->fn; \
this->fn.Force(fn##_gldebug);
#define GL_FUNC_VOID(ext,req,fn,arg,call) \
fn##_gldebugptr = this->fn; \
this->fn.Force(fn##_gldebug);
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
#endif
#ifdef OSX
m_bHave_GL_NV_bindless_texture = false;
m_bHave_GL_AMD_pinned_memory = false;
#else
if ( ( m_bHave_GL_NV_bindless_texture ) && ( !CommandLine()->CheckParm( "-gl_nv_bindless_texturing" ) ) )
{
m_bHave_GL_NV_bindless_texture = false;
glGetTextureHandleNV.Force( NULL );
glGetTextureSamplerHandleNV.Force( NULL );
glMakeTextureHandleResidentNV.Force( NULL );
glMakeTextureHandleNonResidentNV.Force( NULL );
glUniformHandleui64NV.Force( NULL );
glUniformHandleui64vNV.Force( NULL );
glProgramUniformHandleui64NV.Force( NULL );
glProgramUniformHandleui64vNV.Force( NULL );
glIsTextureHandleResidentNV.Force( NULL );
}
if ( !CommandLine()->CheckParm( "-gl_amd_pinned_memory" ) )
{
m_bHave_GL_AMD_pinned_memory = false;
}
#endif // !OSX
// Getting reports of black screens, etc. with ARB_buffer_storage and AMD drivers. This type of thing:
// http://forums.steampowered.com/forums/showthread.php?t=3266806
// So disable it for now.
if ( ( m_nDriverProvider == cGLDriverProviderAMD ) || CommandLine()->CheckParm( "-gl_disable_arb_buffer_storage" ) )
{
m_bHave_GL_ARB_buffer_storage = false;
}
printf( "GL_NV_bindless_texture: %s\n", m_bHave_GL_NV_bindless_texture ? "ENABLED" : "DISABLED" );
printf( "GL_AMD_pinned_memory: %s\n", m_bHave_GL_AMD_pinned_memory ? "ENABLED" : "DISABLED" );
printf( "GL_ARB_buffer_storage: %s\n", m_bHave_GL_ARB_buffer_storage ? "AVAILABLE" : "NOT AVAILABLE" );
printf( "GL_EXT_texture_sRGB_decode: %s\n", m_bHave_GL_EXT_texture_sRGB_decode ? "AVAILABLE" : "NOT AVAILABLE" );
bool bGLCanDecodeS3TCTextures = m_bHave_GL_EXT_texture_compression_s3tc || ( m_bHave_GL_EXT_texture_compression_dxt1 && m_bHave_GL_ANGLE_texture_compression_dxt3 && m_bHave_GL_ANGLE_texture_compression_dxt5 );
if ( !bGLCanDecodeS3TCTextures )
{
Error( "This application requires either the GL_EXT_texture_compression_s3tc, or the GL_EXT_texture_compression_dxt1 + GL_ANGLE_texture_compression_dxt3 + GL_ANGLE_texture_compression_dxt5 OpenGL extensions. Please install S3TC texture support.\n" );
}
#ifdef OSX
if ( CommandLine()->FindParm( "-glmnosrgbdecode" ) )
{
Msg( "Forcing m_bHave_GL_EXT_texture_sRGB_decode off.\n" );
m_bHave_GL_EXT_texture_sRGB_decode = false;
}
#endif
#ifndef OSX
if ( !m_bHave_GL_EXT_texture_sRGB_decode )
{
Error( "Required OpenGL extension \"GL_EXT_texture_sRGB_decode\" is not supported. Please update your OpenGL driver.\n" );
}
#endif
}
COpenGLEntryPoints::~COpenGLEntryPoints()
{
for ( uint i = 0; i < cGLTotalDriverProviders; ++i )
{
free( m_pGLDriverStrings[i] );
m_pGLDriverStrings[i] = NULL;
}
}
void COpenGLEntryPoints::ClearEntryPoints()
{
#define GL_EXT(x,glmajor,glminor)
#define GL_FUNC(ext,req,ret,fn,arg,call) fn.Force( NULL );
#define GL_FUNC_VOID(ext,req,fn,arg,call) fn.Force( NULL );
#include "togl/glfuncs.inl"
#undef GL_FUNC_VOID
#undef GL_FUNC
#undef GL_EXT
}
// Turn off memdbg macros (turned on up top) since this is included like a header
#include "tier0/memdbgoff.h"

6092
togles/linuxwin/glmgr.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,622 @@
// BE VERY VERY CAREFUL what you do in these function. They are extremely hot, and calling the wrong GL API's in here will crush perf. (especially on NVidia threaded drivers).
FORCEINLINE uint32 bitmix32(uint32 a)
{
a -= (a<<6);
//a ^= (a>>17);
//a -= (a<<9);
a ^= (a<<4);
//a -= (a<<3);
//a ^= (a<<10);
a ^= (a>>15);
return a;
}
#ifndef OSX
FORCEINLINE GLuint GLMContext::FindSamplerObject( const GLMTexSamplingParams &desiredParams )
{
int h = bitmix32( desiredParams.m_bits + desiredParams.m_borderColor ) & ( cSamplerObjectHashSize - 1 );
while ( ( m_samplerObjectHash[h].m_params.m_bits != desiredParams.m_bits ) || ( m_samplerObjectHash[h].m_params.m_borderColor != desiredParams.m_borderColor ) )
{
if ( !m_samplerObjectHash[h].m_params.m_packed.m_isValid )
break;
if ( ++h >= cSamplerObjectHashSize )
h = 0;
}
if ( !m_samplerObjectHash[h].m_params.m_packed.m_isValid )
{
GLMTexSamplingParams &hashParams = m_samplerObjectHash[h].m_params;
hashParams = desiredParams;
hashParams.SetToSamplerObject( m_samplerObjectHash[h].m_samplerObject );
if ( ++m_nSamplerObjectHashNumEntries == cSamplerObjectHashSize )
{
// TODO: Support resizing
Error( "Sampler object hash is full, increase cSamplerObjectHashSize" );
}
}
return m_samplerObjectHash[h].m_samplerObject;
}
#endif // !OSX
// BE VERY CAREFUL WHAT YOU DO IN HERE. This is called on every batch, even seemingly simple changes can kill perf.
FORCEINLINE void GLMContext::FlushDrawStates( uint nStartIndex, uint nEndIndex, uint nBaseVertex ) // shadersOn = true for draw calls, false for clear calls
{
Assert( m_drawingLang == kGLMGLSL ); // no support for ARB shaders right now (and NVidia reports that they aren't worth targeting under Windows/Linux for various reasons anyway)
Assert( ( m_drawingFBO == m_boundDrawFBO ) && ( m_drawingFBO == m_boundReadFBO ) ); // this check MUST succeed
Assert( m_pDevice->m_pVertDecl );
#if GLMDEBUG
GLM_FUNC;
#endif
GL_BATCH_PERF( m_FlushStats.m_nTotalBatchFlushes++; )
#if GLMDEBUG
bool tex0_srgb = (m_boundDrawFBO[0].m_attach[0].m_tex->m_layout->m_key.m_texFlags & kGLMTexSRGB) != 0;
// you can only actually use the sRGB FB state on some systems.. check caps
if (m_caps.m_hasGammaWrites)
{
GLBlendEnableSRGB_t writeSRGBState;
m_BlendEnableSRGB.Read( &writeSRGBState, 0 ); // the client set value, not the API-written value yet..
bool draw_srgb = writeSRGBState.enable != 0;
if (draw_srgb)
{
if (tex0_srgb)
{
// good - draw mode and color tex agree
}
else
{
// bad
// Client has asked to write sRGB into a texture that can't do it.
// there is no way to satisfy this unless we change the RT tex and we avoid doing that.
// (although we might consider a ** ONE TIME ** promotion.
// this shouldn't be a big deal if the tex format is one where it doesn't matter like 32F.
GLMPRINTF(("-Z- srgb-enabled FBO conflict: attached tex %08x [%s] is not SRGB", m_boundDrawFBO[0].m_attach[0].m_tex, m_boundDrawFBO[0].m_attach[0].m_tex->m_layout->m_layoutSummary ));
// do we shoot down the srgb-write state for this batch?
// I think the runtime will just ignore it.
}
}
else
{
if (tex0_srgb)
{
// odd - client is not writing sRGB into a texture which *can* do it.
//GLMPRINTF(( "-Z- srgb-disabled FBO conflict: attached tex %08x [%s] is SRGB", m_boundFBO[0].m_attach[0].m_tex, m_boundFBO[0].m_attach[0].m_tex->m_layout->m_layoutSummary ));
//writeSRGBState.enable = true;
//m_BlendEnableSRGB.Write( &writeSRGBState );
}
else
{
// good - draw mode and color tex agree
}
}
}
#endif
Assert( m_drawingProgram[ kGLMVertexProgram ] );
Assert( m_drawingProgram[ kGLMFragmentProgram ] );
Assert( ( m_drawingProgram[kGLMVertexProgram]->m_type == kGLMVertexProgram ) && ( m_drawingProgram[kGLMFragmentProgram]->m_type == kGLMFragmentProgram ) );
Assert( m_drawingProgram[ kGLMVertexProgram ]->m_bTranslatedProgram && m_drawingProgram[ kGLMFragmentProgram ]->m_bTranslatedProgram );
#if GLMDEBUG
// Depth compare mode check
uint nCurMask = 1, nShaderSamplerMask = m_drawingProgram[kGLMFragmentProgram]->m_samplerMask;
for ( int nSamplerIndex = 0; nSamplerIndex < GLM_SAMPLER_COUNT; ++nSamplerIndex, nCurMask <<= 1 )
{
if ( !m_samplers[nSamplerIndex].m_pBoundTex )
continue;
if ( m_samplers[nSamplerIndex].m_pBoundTex->m_layout->m_mipCount == 1 )
{
if ( m_samplers[nSamplerIndex].m_samp.m_packed.m_mipFilter == D3DTEXF_LINEAR )
{
GLMDebugPrintf( "Sampler %u has mipmap filtering enabled on a texture without mipmaps! (texture name: %s, pixel shader: %s)!\n",
nSamplerIndex,
m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel ? m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel : "?",
m_drawingProgram[kGLMFragmentProgram]->m_shaderName );
}
}
if ( ( nShaderSamplerMask & nCurMask ) == 0 )
continue;
if ( m_samplers[nSamplerIndex].m_pBoundTex->m_layout->m_mipCount == 1 )
{
if ( m_samplers[nSamplerIndex].m_samp.m_packed.m_mipFilter == D3DTEXF_LINEAR )
{
// Note this is not always an error - shadow buffer debug visualization shaders purposely want to read shadow depths (and not do the comparison)
GLMDebugPrintf( "Sampler %u has mipmap filtering enabled on a texture without mipmaps! (texture name: %s, pixel shader: %s)!\n",
nSamplerIndex,
m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel ? m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel : "?",
m_drawingProgram[kGLMFragmentProgram]->m_shaderName );
}
}
bool bSamplerIsDepth = ( m_samplers[nSamplerIndex].m_pBoundTex->m_layout->m_key.m_texFlags & kGLMTexIsDepth ) != 0;
bool bSamplerShadow = m_samplers[nSamplerIndex].m_samp.m_packed.m_compareMode != 0;
bool bShaderShadow = ( m_drawingProgram[kGLMFragmentProgram]->m_nShadowDepthSamplerMask & nCurMask ) != 0;
if ( bShaderShadow )
{
// Shader expects shadow depth sampling at this sampler index
// Must have a depth texture and compare mode must be enabled
if ( !bSamplerIsDepth || !bSamplerShadow )
{
// FIXME: This occasionally occurs in L4D2 when CShaderAPIDx8::ExecuteCommandBuffer() sets the TEXTURE_WHITE texture in the flashlight depth texture slot.
GLMDebugPrintf( "Sampler %u's compare mode (%u) or format (depth=%u) is not consistent with pixel shader's compare mode (%u) (texture name: %s, pixel shader: %s)!\n",
nSamplerIndex, bSamplerShadow, bSamplerIsDepth, bShaderShadow,
m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel ? m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel : "?",
m_drawingProgram[kGLMFragmentProgram]->m_shaderName );
}
}
else
{
// Shader does not expect shadow depth sampling as this sampler index
// We don't care if comparemode is enabled, but we can't have a depth texture in this sampler
if ( bSamplerIsDepth )
{
GLMDebugPrintf( "Sampler %u is a depth texture but the pixel shader's shadow depth sampler mask does not expect depth here (texture name: %s, pixel shader: %s)!\n",
nSamplerIndex,
m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel ? m_samplers[nSamplerIndex].m_pBoundTex->m_debugLabel : "?",
m_drawingProgram[kGLMFragmentProgram]->m_shaderName );
}
}
}
#endif
if ( m_bDirtyPrograms )
{
m_bDirtyPrograms = false;
CGLMShaderPair *pNewPair = m_pairCache->SelectShaderPair( m_drawingProgram[ kGLMVertexProgram ], m_drawingProgram[ kGLMFragmentProgram ], 0 );
if ( pNewPair != m_pBoundPair )
{
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "NewProgram" );
#endif
if ( !pNewPair->m_valid )
{
if ( !pNewPair->ValidateProgramPair() )
{
goto flush_error_exit;
}
}
gGL->glUseProgram( (GLuint)pNewPair->m_program );
GL_BATCH_PERF( m_FlushStats.m_nTotalProgramPairChanges++; )
if ( !m_pBoundPair )
{
GL_BATCH_PERF( m_FlushStats.m_nNewPS++; )
GL_BATCH_PERF( m_FlushStats.m_nNewVS++; )
}
else
{
GL_BATCH_PERF( if ( pNewPair->m_fragmentProg != m_pBoundPair->m_fragmentProg ) m_FlushStats.m_nNewPS++; )
GL_BATCH_PERF( if ( pNewPair->m_vertexProg != m_pBoundPair->m_vertexProg ) m_FlushStats.m_nNewVS++; )
}
#if GL_BATCH_PERF_ANALYSIS
tmMessage( TELEMETRY_LEVEL2, TMMF_ICON_NOTE, "V:%s (V Regs:%u V Bone Regs:%u) F:%s (F Regs:%u)",
m_drawingProgram[ kGLMVertexProgram ]->m_shaderName,
m_drawingProgram[ kGLMVertexProgram ]->m_descs[kGLMGLSL].m_highWater,
m_drawingProgram[ kGLMVertexProgram ]->m_descs[kGLMGLSL].m_VSHighWaterBone,
m_drawingProgram[ kGLMFragmentProgram ]->m_shaderName,
m_drawingProgram[ kGLMFragmentProgram ]->m_descs[kGLMGLSL].m_highWater );
#endif
m_pBoundPair = pNewPair;
// set the dirty levels appropriately since the program changed and has never seen any of the current values.
m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = 0;
m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = m_drawingProgram[ kGLMVertexProgram ]->m_descs[kGLMGLSL].m_highWater;
m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = m_drawingProgram[ kGLMVertexProgram ]->m_descs[kGLMGLSL].m_VSHighWaterBone;
m_programParamsF[kGLMFragmentProgram].m_firstDirtySlotNonBone = 0;
m_programParamsF[kGLMFragmentProgram].m_dirtySlotHighWaterNonBone = m_drawingProgram[ kGLMFragmentProgram ]->m_descs[kGLMGLSL].m_highWater;
// bool and int dirty levels get set to max, we don't have actual high water marks for them
// code which sends the values must clamp on these types.
m_programParamsB[kGLMVertexProgram].m_dirtySlotCount = kGLMProgramParamBoolLimit;
m_programParamsB[kGLMFragmentProgram].m_dirtySlotCount = kGLMProgramParamBoolLimit;
m_programParamsI[kGLMVertexProgram].m_dirtySlotCount = kGLMProgramParamInt4Limit;
m_programParamsI[kGLMFragmentProgram].m_dirtySlotCount = 0;
// check fragment buffers used (MRT)
if( pNewPair->m_fragmentProg->m_fragDataMask != m_fragDataMask )
{
gGL->glDrawBuffers( pNewPair->m_fragmentProg->m_numDrawBuffers, pNewPair->m_fragmentProg->m_drawBuffers );
m_fragDataMask = pNewPair->m_fragmentProg->m_fragDataMask;
}
}
}
Assert( m_ViewportBox.GetData().width == (int)( m_ViewportBox.GetData().widthheight & 0xFFFF ) );
Assert( m_ViewportBox.GetData().height == (int)( m_ViewportBox.GetData().widthheight >> 16 ) );
m_pBoundPair->UpdateScreenUniform( m_ViewportBox.GetData().widthheight );
GL_BATCH_PERF( m_FlushStats.m_nNumChangedSamplers += m_nNumDirtySamplers );
#if !defined( OSX ) // no support for sampler objects in OSX 10.6 (GL 2.1 profile)
if ( m_bUseSamplerObjects)
{
while ( m_nNumDirtySamplers )
{
const uint nSamplerIndex = m_nDirtySamplers[--m_nNumDirtySamplers];
Assert( ( nSamplerIndex < GLM_SAMPLER_COUNT ) && ( !m_nDirtySamplerFlags[nSamplerIndex]) );
m_nDirtySamplerFlags[nSamplerIndex] = 1;
gGL->glBindSampler( nSamplerIndex, FindSamplerObject( m_samplers[nSamplerIndex].m_samp ) );
GL_BATCH_PERF( m_FlushStats.m_nNumSamplingParamsChanged++ );
#if defined( OSX ) // valid for OSX only if using GL 3.3 context
CGLMTex *pTex = m_samplers[nSamplerIndex].m_pBoundTex;
if( pTex && !( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) )
{
// see if requested SRGB state differs from the known one
bool texSRGB = ( pTex->m_layout->m_key.m_texFlags & kGLMTexSRGB ) != 0;
bool glSampSRGB = m_samplers[nSamplerIndex].m_samp.m_packed.m_srgb;
if ( texSRGB != glSampSRGB ) // mismatch
{
pTex->HandleSRGBMismatch( glSampSRGB, pTex->m_srgbFlipCount );
}
}
#endif
}
}
else
#endif // if !defined( OSX )
{
while ( m_nNumDirtySamplers )
{
const uint nSamplerIndex = m_nDirtySamplers[--m_nNumDirtySamplers];
Assert( ( nSamplerIndex < GLM_SAMPLER_COUNT ) && ( !m_nDirtySamplerFlags[nSamplerIndex]) );
m_nDirtySamplerFlags[nSamplerIndex] = 1;
CGLMTex *pTex = m_samplers[nSamplerIndex].m_pBoundTex;
if ( ( pTex ) && ( !( pTex->m_SamplingParams == m_samplers[nSamplerIndex].m_samp ) ) )
{
SelectTMU( nSamplerIndex );
m_samplers[nSamplerIndex].m_samp.DeltaSetToTarget( pTex->m_texGLTarget, pTex->m_SamplingParams );
pTex->m_SamplingParams = m_samplers[nSamplerIndex].m_samp;
#if defined( OSX )
if( pTex && !( gGL->m_bHave_GL_EXT_texture_sRGB_decode ) )
{
// see if requested SRGB state differs from the known one
bool texSRGB = ( pTex->m_layout->m_key.m_texFlags & kGLMTexSRGB ) != 0;
bool glSampSRGB = m_samplers[nSamplerIndex].m_samp.m_packed.m_srgb;
if ( texSRGB != glSampSRGB ) // mismatch
{
pTex->HandleSRGBMismatch( glSampSRGB, pTex->m_srgbFlipCount );
}
}
#endif
}
}
}
// vertex stage --------------------------------------------------------------------
if ( m_bUseBoneUniformBuffers )
{
// vertex stage --------------------------------------------------------------------
if ( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone )
{
int firstDirtySlot = m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone;
int dirtySlotHighWater = MIN( m_drawingProgram[kGLMVertexProgram]->m_descs[kGLMGLSL].m_highWater, m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone );
GLint vconstLoc = m_pBoundPair->m_locVertexParams;
if ( ( vconstLoc >= 0 ) && ( dirtySlotHighWater > firstDirtySlot ) )
{
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "VSNonBoneUniformUpdate %u %u", firstDirtySlot, dirtySlotHighWater );
#endif
int numSlots = dirtySlotHighWater - DXABSTRACT_VS_FIRST_BONE_SLOT;
// consts after the bones (c217 onwards), since we use the concatenated destination array vc[], upload these consts starting from vc[58]
if( numSlots > 0 )
{
gGL->glUniform4fv( m_pBoundPair->m_UniformBufferParams[kGLMVertexProgram][DXABSTRACT_VS_FIRST_BONE_SLOT], numSlots, &m_programParamsF[kGLMVertexProgram].m_values[(DXABSTRACT_VS_LAST_BONE_SLOT+1)][0] );
dirtySlotHighWater = DXABSTRACT_VS_FIRST_BONE_SLOT;
GL_BATCH_PERF( m_nTotalVSUniformCalls++; )
GL_BATCH_PERF( m_nTotalVSUniformsSet += numSlots; )
GL_BATCH_PERF( m_FlushStats.m_nFirstVSConstant = DXABSTRACT_VS_FIRST_BONE_SLOT; )
GL_BATCH_PERF( m_FlushStats.m_nNumVSConstants += numSlots; )
}
numSlots = dirtySlotHighWater - firstDirtySlot;
// consts before the bones (c0-c57)
if( numSlots > 0 )
{
gGL->glUniform4fv( m_pBoundPair->m_UniformBufferParams[kGLMVertexProgram][firstDirtySlot], dirtySlotHighWater - firstDirtySlot, &m_programParamsF[kGLMVertexProgram].m_values[firstDirtySlot][0] );
GL_BATCH_PERF( m_nTotalVSUniformCalls++; )
GL_BATCH_PERF( m_nTotalVSUniformsSet += dirtySlotHighWater - firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nFirstVSConstant = firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nNumVSConstants += (dirtySlotHighWater - firstDirtySlot); )
}
}
m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = 256;
m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = 0;
}
if ( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone )
{
const GLint vconstBoneLoc = m_pBoundPair->m_locVertexBoneParams;
if ( vconstBoneLoc >= 0 )
{
int shaderSlotsBone = 0;
if ( ( m_drawingProgram[kGLMVertexProgram]->m_descs[kGLMGLSL].m_VSHighWaterBone > 0 ) && ( m_nMaxUsedVertexProgramConstantsHint > DXABSTRACT_VS_FIRST_BONE_SLOT ) )
{
shaderSlotsBone = MIN( m_drawingProgram[kGLMVertexProgram]->m_descs[kGLMGLSL].m_VSHighWaterBone, m_nMaxUsedVertexProgramConstantsHint - DXABSTRACT_VS_FIRST_BONE_SLOT );
}
int dirtySlotHighWaterBone = MIN( shaderSlotsBone, m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone );
if ( dirtySlotHighWaterBone )
{
uint nNumBoneRegs = dirtySlotHighWaterBone;
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "VSBoneUniformUpdate %u", nNumBoneRegs );
#endif
gGL->glUniform4fv( vconstBoneLoc, nNumBoneRegs, &m_programParamsF[kGLMVertexProgram].m_values[DXABSTRACT_VS_FIRST_BONE_SLOT][0] );
GL_BATCH_PERF( m_nTotalVSUniformBoneCalls++; )
GL_BATCH_PERF( m_nTotalVSUniformsBoneSet += nNumBoneRegs; )
GL_BATCH_PERF( m_FlushStats.m_nNumVSBoneConstants += nNumBoneRegs; )
}
m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterBone = 0;
}
}
}
else
{
if ( m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone )
{
const int nMaxUsedShaderSlots = m_drawingProgram[kGLMVertexProgram]->m_descs[kGLMGLSL].m_highWater;
int firstDirtySlot = m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone;
int dirtySlotHighWater = MIN( nMaxUsedShaderSlots, m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone );
GLint vconstLoc = m_pBoundPair->m_locVertexParams;
if ( ( vconstLoc >= 0 ) && ( dirtySlotHighWater > firstDirtySlot ) )
{
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "VSNonBoneUniformUpdate %u %u", firstDirtySlot, dirtySlotHighWater );
#endif
gGL->glUniform4fv( m_pBoundPair->m_UniformBufferParams[kGLMVertexProgram][firstDirtySlot], dirtySlotHighWater - firstDirtySlot, &m_programParamsF[kGLMVertexProgram].m_values[firstDirtySlot][0] );
GL_BATCH_PERF( m_nTotalVSUniformCalls++; )
GL_BATCH_PERF( m_nTotalVSUniformsSet += dirtySlotHighWater - firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nFirstVSConstant = firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nNumVSConstants += (dirtySlotHighWater - firstDirtySlot); )
}
m_programParamsF[kGLMVertexProgram].m_firstDirtySlotNonBone = 256;
m_programParamsF[kGLMVertexProgram].m_dirtySlotHighWaterNonBone = 0;
}
}
// see if VS uses i0, b0, b1, b2, b3.
// use a glUniform1i to set any one of these if active. skip all of them if no dirties reported.
// my kingdom for the UBO extension!
// ------- bools ---------- //
if ( m_pBoundPair->m_bHasBoolOrIntUniforms )
{
if ( m_programParamsB[kGLMVertexProgram].m_dirtySlotCount ) // optimize this later after the float param pushes are proven out
{
const uint nLimit = MIN( CGLMShaderPair::cMaxVertexShaderBoolUniforms, m_programParamsB[kGLMVertexProgram].m_dirtySlotCount );
for ( uint i = 0; i < nLimit; ++i )
{
GLint constBoolLoc = m_pBoundPair->m_locVertexBool[i];
if ( constBoolLoc >= 0 )
gGL->glUniform1i( constBoolLoc, m_programParamsB[kGLMVertexProgram].m_values[i] );
}
m_programParamsB[kGLMVertexProgram].m_dirtySlotCount = 0;
}
if ( m_programParamsB[kGLMFragmentProgram].m_dirtySlotCount ) // optimize this later after the float param pushes are proven out
{
const uint nLimit = MIN( CGLMShaderPair::cMaxFragmentShaderBoolUniforms, m_programParamsB[kGLMFragmentProgram].m_dirtySlotCount );
for ( uint i = 0; i < nLimit; ++i )
{
GLint constBoolLoc = m_pBoundPair->m_locFragmentBool[i];
if ( constBoolLoc >= 0 )
gGL->glUniform1i( constBoolLoc, m_programParamsB[kGLMFragmentProgram].m_values[i] );
}
m_programParamsB[kGLMFragmentProgram].m_dirtySlotCount = 0;
}
if ( m_programParamsI[kGLMVertexProgram].m_dirtySlotCount )
{
GLint vconstInt0Loc = m_pBoundPair->m_locVertexInteger0; //glGetUniformLocationARB( prog, "i0");
if ( vconstInt0Loc >= 0 )
{
gGL->glUniform1i( vconstInt0Loc, m_programParamsI[kGLMVertexProgram].m_values[0][0] ); //FIXME magic number
}
m_programParamsI[kGLMVertexProgram].m_dirtySlotCount = 0;
}
}
Assert( ( m_pDevice->m_streams[0].m_vtxBuffer && ( m_pDevice->m_streams[0].m_vtxBuffer->m_vtxBuffer == m_pDevice->m_vtx_buffers[0] ) ) || ( ( !m_pDevice->m_streams[0].m_vtxBuffer ) && ( m_pDevice->m_vtx_buffers[0] == m_pDevice->m_pDummy_vtx_buffer ) ) );
Assert( ( m_pDevice->m_streams[1].m_vtxBuffer && ( m_pDevice->m_streams[1].m_vtxBuffer->m_vtxBuffer == m_pDevice->m_vtx_buffers[1] ) ) || ( ( !m_pDevice->m_streams[1].m_vtxBuffer ) && ( m_pDevice->m_vtx_buffers[1] == m_pDevice->m_pDummy_vtx_buffer ) ) );
Assert( ( m_pDevice->m_streams[2].m_vtxBuffer && ( m_pDevice->m_streams[2].m_vtxBuffer->m_vtxBuffer == m_pDevice->m_vtx_buffers[2] ) ) || ( ( !m_pDevice->m_streams[2].m_vtxBuffer ) && ( m_pDevice->m_vtx_buffers[2] == m_pDevice->m_pDummy_vtx_buffer ) ) );
Assert( ( m_pDevice->m_streams[3].m_vtxBuffer && ( m_pDevice->m_streams[3].m_vtxBuffer->m_vtxBuffer == m_pDevice->m_vtx_buffers[3] ) ) || ( ( !m_pDevice->m_streams[3].m_vtxBuffer ) && ( m_pDevice->m_vtx_buffers[3] == m_pDevice->m_pDummy_vtx_buffer ) ) );
uint nCurTotalBufferRevision;
nCurTotalBufferRevision = m_pDevice->m_vtx_buffers[0]->m_nRevision + m_pDevice->m_vtx_buffers[1]->m_nRevision + m_pDevice->m_vtx_buffers[2]->m_nRevision + m_pDevice->m_vtx_buffers[3]->m_nRevision;
// If any of these inputs have changed, we need to enumerate through all of the expected GL vertex attribs and modify anything in the GL layer that have changed.
// This is not always a win, but it is a net win on NVidia (by 1-4.8% depending on whether driver threading is enabled).
if ( ( nCurTotalBufferRevision != m_CurAttribs.m_nTotalBufferRevision ) ||
( m_CurAttribs.m_pVertDecl != m_pDevice->m_pVertDecl ) ||
( m_CurAttribs.m_vtxAttribMap[0] != reinterpret_cast<const uint64 *>(m_pDevice->m_vertexShader->m_vtxAttribMap)[0] ) ||
( m_CurAttribs.m_vtxAttribMap[1] != reinterpret_cast<const uint64 *>(m_pDevice->m_vertexShader->m_vtxAttribMap)[1] ) ||
( memcmp( m_CurAttribs.m_streams, m_pDevice->m_streams, sizeof( m_pDevice->m_streams ) ) != 0 ) )
{
// This branch is taken 52.2% of the time in the L4D2 test1 (long) timedemo.
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "SetVertexAttribs" );
#endif
m_CurAttribs.m_nTotalBufferRevision = nCurTotalBufferRevision;
m_CurAttribs.m_pVertDecl = m_pDevice->m_pVertDecl;
m_CurAttribs.m_vtxAttribMap[0] = reinterpret_cast<const uint64 *>(m_pDevice->m_vertexShader->m_vtxAttribMap)[0];
m_CurAttribs.m_vtxAttribMap[1] = reinterpret_cast<const uint64 *>(m_pDevice->m_vertexShader->m_vtxAttribMap)[1];
memcpy( m_CurAttribs.m_streams, m_pDevice->m_streams, sizeof( m_pDevice->m_streams ) );
unsigned char *pVertexShaderAttribMap = m_pDevice->m_vertexShader->m_vtxAttribMap;
const int nMaxVertexAttributesToCheck = m_drawingProgram[ kGLMVertexProgram ]->m_maxVertexAttrs;
IDirect3DVertexDeclaration9 *pVertDecl = m_pDevice->m_pVertDecl;
const uint8 *pVertexAttribDescToStreamIndex = pVertDecl->m_VertexAttribDescToStreamIndex;
for( int nMask = 1, nIndex = 0; nIndex < nMaxVertexAttributesToCheck; ++nIndex, nMask <<= 1 )
{
uint8 vertexShaderAttrib = pVertexShaderAttribMap[ nIndex ];
uint nDeclIndex = pVertexAttribDescToStreamIndex[vertexShaderAttrib];
if ( nDeclIndex == 0xFF )
{
// Not good - the vertex shader has an attribute which can't be located in the decl!
// The D3D9 debug runtime is also going to complain.
Assert( 0 );
if ( m_lastKnownVertexAttribMask & nMask )
{
m_lastKnownVertexAttribMask &= ~nMask;
gGL->glDisableVertexAttribArray( nIndex );
}
continue;
}
D3DVERTEXELEMENT9_GL *pDeclElem = &pVertDecl->m_elements[nDeclIndex];
Assert( ( ( vertexShaderAttrib >> 4 ) == pDeclElem->m_dxdecl.Usage ) && ( ( vertexShaderAttrib & 0x0F ) == pDeclElem->m_dxdecl.UsageIndex) );
const uint nStreamIndex = pDeclElem->m_dxdecl.Stream;
const D3DStreamDesc *pStream = &m_pDevice->m_streams[ nStreamIndex ];
CGLMBuffer *pBuf = m_pDevice->m_vtx_buffers[ nStreamIndex ];
if ( pBuf == m_pDevice->m_pDummy_vtx_buffer )
{
Assert( pStream->m_vtxBuffer == NULL );
// this shader doesn't use that pair.
if ( m_lastKnownVertexAttribMask & nMask )
{
m_lastKnownVertexAttribMask &= ~nMask;
gGL->glDisableVertexAttribArray( nIndex );
}
continue;
}
Assert( pStream->m_vtxBuffer->m_vtxBuffer == pBuf );
int nBufOffset = pDeclElem->m_gldecl.m_offset + pStream->m_offset;
Assert( nBufOffset >= 0 );
Assert( nBufOffset < (int)pBuf->m_nSize );
if ( pBuf->m_bUsingPersistentBuffer )
{
nBufOffset += pBuf->m_nPersistentBufferStartOffset;
}
SetBufAndVertexAttribPointer( nIndex, pBuf->GetHandle(),
pStream->m_stride, pDeclElem->m_gldecl.m_datatype, pDeclElem->m_gldecl.m_normalized, pDeclElem->m_gldecl.m_nCompCount,
reinterpret_cast< const GLvoid * >( reinterpret_cast< int >( pBuf->m_pPseudoBuf ) + nBufOffset ),
pBuf->m_nRevision );
if ( !( m_lastKnownVertexAttribMask & nMask ) )
{
m_lastKnownVertexAttribMask |= nMask;
gGL->glEnableVertexAttribArray( nIndex );
}
}
for( int nIndex = nMaxVertexAttributesToCheck; nIndex < m_nNumSetVertexAttributes; nIndex++ )
{
gGL->glDisableVertexAttribArray( nIndex );
m_lastKnownVertexAttribMask &= ~(1 << nIndex);
}
m_nNumSetVertexAttributes = nMaxVertexAttributesToCheck;
}
// fragment stage --------------------------------------------------------------------
if ( m_programParamsF[kGLMFragmentProgram].m_dirtySlotHighWaterNonBone )
{
GLint fconstLoc;
fconstLoc = m_pBoundPair->m_locFragmentParams;
if ( fconstLoc >= 0 )
{
const int nMaxUsedShaderSlots = m_drawingProgram[kGLMFragmentProgram]->m_descs[kGLMGLSL].m_highWater;
int firstDirtySlot = m_programParamsF[kGLMFragmentProgram].m_firstDirtySlotNonBone;
int dirtySlotHighWater = MIN( nMaxUsedShaderSlots, m_programParamsF[kGLMFragmentProgram].m_dirtySlotHighWaterNonBone );
if ( dirtySlotHighWater > firstDirtySlot )
{
#if GL_BATCH_TELEMETRY_ZONES
tmZone( TELEMETRY_LEVEL2, TMZF_NONE, "PSUniformUpdate %u %u", firstDirtySlot, dirtySlotHighWater );
#endif
gGL->glUniform4fv( m_pBoundPair->m_UniformBufferParams[kGLMFragmentProgram][firstDirtySlot], dirtySlotHighWater - firstDirtySlot, &m_programParamsF[kGLMFragmentProgram].m_values[firstDirtySlot][0] );
GL_BATCH_PERF( m_nTotalPSUniformCalls++; )
GL_BATCH_PERF( m_nTotalPSUniformsSet += dirtySlotHighWater - firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nFirstPSConstant = firstDirtySlot; )
GL_BATCH_PERF( m_FlushStats.m_nNumPSConstants += (dirtySlotHighWater - firstDirtySlot); )
}
m_programParamsF[kGLMFragmentProgram].m_firstDirtySlotNonBone = 256;
m_programParamsF[kGLMFragmentProgram].m_dirtySlotHighWaterNonBone = 0;
}
}
return;
flush_error_exit:
m_pBoundPair = NULL;
m_bDirtyPrograms = true;
return;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
//========= Copyright 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: provide some call-out glue to ObjC from the C++ GLMgr code
//
// $Revision: $
// $NoKeywords: $
//=============================================================================//
#include <Cocoa/Cocoa.h>
#include <OpenGL/OpenGL.h>
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#undef MIN
#undef MAX
#define DONT_DEFINE_BOOL // Don't define BOOL!
#include "tier0/threadtools.h"
#include "tier1/interface.h"
#include "tier1/strtools.h"
#include "tier1/utllinkedlist.h"
#include "togl/rendermechanism.h"
// ------------------------------------------------------------------------------------ //
// some glue to let GLMgr call into NS/ObjC classes.
// ------------------------------------------------------------------------------------ //
CGLContextObj GetCGLContextFromNSGL( PseudoNSGLContextPtr nsglCtx )
{
return (CGLContextObj)[ (NSOpenGLContext*)nsglCtx CGLContextObj];
}

View file

@ -0,0 +1,29 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef CGLMTEXINLINES_H
#define CGLMTEXINLINES_H
#pragma once
#endif // CGLMTEXINLINES_H

View file

@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "intelglmallocworkaround.h"
#include "mach_override.h"
// memdbgon -must- be the last include file in a .cpp file.
#include "tier0/memdbgon.h"
IntelGLMallocWorkaround* IntelGLMallocWorkaround::s_pWorkaround = NULL;
void *IntelGLMallocWorkaround::ZeroingAlloc(size_t size)
{
// We call into this pointer that resumes the original malloc.
void *memory = s_pWorkaround->m_pfnMallocReentry(size);
if (size < 96)
{
// Since the Intel driver has an issue with a small allocation
// that's left uninitialized, we use memset to ensure it's zero-initialized.
memset(memory, 0, size);
}
return memory;
}
IntelGLMallocWorkaround* IntelGLMallocWorkaround::Get()
{
if (!s_pWorkaround)
{
s_pWorkaround = new IntelGLMallocWorkaround();
}
return s_pWorkaround;
}
bool IntelGLMallocWorkaround::Enable()
{
if ( m_pfnMallocReentry != NULL )
{
return true;
}
mach_error_t error = mach_override_ptr( (void*)&malloc, (const void*)&ZeroingAlloc, (void**)&m_pfnMallocReentry );
if ( error == err_cannot_override )
{
m_pfnMallocReentry = NULL;
return false;
}
return true;
}

View file

@ -0,0 +1,61 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
// TOGL CODE LICENSE
//
// Copyright 2011-2014 Valve Corporation
// All Rights Reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// intelglmallocworkaround.h
// class responsible for setting up a malloc override that zeroes allocated
// memory of less than 96 bytes. this is to work around a bug
// in the Intel GLSL compiler on Mac OS X 10.8 due to uninitialized memory.
//
// 96 was chosen due to this quote from Apple:
// "I verified that the size of the structure is exactly 64 bytes on 10.8.3, 10.8.4 and will be on 10.8.5."
//
// certain GLSL shaders would (intermittently) cause a crash the first time they
// were drawn, and the bug has supposedly been fixed in 10.9, but is unlikely to
// ever make it to 10.8.
//
//===============================================================================
#ifndef INTELGLMALLOCWORKAROUND_H
#define INTELGLMALLOCWORKAROUND_H
#include <stdlib.h>
class IntelGLMallocWorkaround
{
public:
static IntelGLMallocWorkaround *Get();
bool Enable();
protected:
IntelGLMallocWorkaround() :m_pfnMallocReentry(NULL) {}
~IntelGLMallocWorkaround() {}
static IntelGLMallocWorkaround *s_pWorkaround;
static void* ZeroingAlloc(size_t);
typedef void* (*pfnMalloc_t)(size_t);
pfnMalloc_t m_pfnMallocReentry;
};
#endif // INTELGLMALLOCWORKAROUND_H

View file

@ -0,0 +1,765 @@
// mach_override.c semver:1.2.0
// Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
// Some rights reserved: http://opensource.org/licenses/mit
// https://github.com/rentzsch/mach_override
#include "mach_override.h"
#include <mach-o/dyld.h>
#include <mach/mach_host.h>
#include <mach/mach_init.h>
#include <mach/vm_map.h>
#include <sys/mman.h>
#include <libkern/OSAtomic.h>
#include <CoreServices/CoreServices.h>
/**************************
*
* Constants
*
**************************/
#pragma mark -
#pragma mark (Constants)
#define kPageSize 4096
#if defined(__ppc__) || defined(__POWERPC__)
long kIslandTemplate[] = {
0x9001FFFC, // stw r0,-4(SP)
0x3C00DEAD, // lis r0,0xDEAD
0x6000BEEF, // ori r0,r0,0xBEEF
0x7C0903A6, // mtctr r0
0x8001FFFC, // lwz r0,-4(SP)
0x60000000, // nop ; optionally replaced
0x4E800420 // bctr
};
#define kAddressHi 3
#define kAddressLo 5
#define kInstructionHi 10
#define kInstructionLo 11
#elif defined(__i386__)
#define kOriginalInstructionsSize 16
// On X86 we migh need to instert an add with a 32 bit immediate after the
// original instructions.
#define kMaxFixupSizeIncrease 5
unsigned char kIslandTemplate[] = {
// kOriginalInstructionsSize nop instructions so that we
// should have enough space to host original instructions
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
// Now the real jump instruction
0xE9, 0xEF, 0xBE, 0xAD, 0xDE
};
#define kInstructions 0
#define kJumpAddress kInstructions + kOriginalInstructionsSize + 1
#elif defined(__x86_64__)
#define kOriginalInstructionsSize 32
// On X86-64 we never need to instert a new instruction.
#define kMaxFixupSizeIncrease 0
#define kJumpAddress kOriginalInstructionsSize + 6
unsigned char kIslandTemplate[] = {
// kOriginalInstructionsSize nop instructions so that we
// should have enough space to host original instructions
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
// Now the real jump instruction
0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
#endif
/**************************
*
* Data Types
*
**************************/
#pragma mark -
#pragma mark (Data Types)
typedef struct {
char instructions[sizeof(kIslandTemplate)];
} BranchIsland;
/**************************
*
* Funky Protos
*
**************************/
#pragma mark -
#pragma mark (Funky Protos)
static mach_error_t
allocateBranchIsland(
BranchIsland **island,
void *originalFunctionAddress);
mach_error_t
freeBranchIsland(
BranchIsland *island );
#if defined(__ppc__) || defined(__POWERPC__)
mach_error_t
setBranchIslandTarget(
BranchIsland *island,
const void *branchTo,
long instruction );
#endif
#if defined(__i386__) || defined(__x86_64__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions );
void
atomic_mov64(
uint64_t *targetAddress,
uint64_t value );
static Boolean
eatKnownInstructions(
unsigned char *code,
uint64_t *newInstruction,
int *howManyEaten,
char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes );
static void
fixupInstructions(
uint32_t offset,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes );
#endif
/*******************************************************************************
*
* Interface
*
*******************************************************************************/
#pragma mark -
#pragma mark (Interface)
#if defined(__i386__) || defined(__x86_64__)
mach_error_t makeIslandExecutable(void *address) {
mach_error_t err = err_none;
uintptr_t page = (uintptr_t)address & ~(uintptr_t)(kPageSize-1);
int e = err_none;
e |= mprotect((void *)page, kPageSize, PROT_EXEC | PROT_READ | PROT_WRITE);
e |= msync((void *)page, kPageSize, MS_INVALIDATE );
if (e) {
err = err_cannot_override;
}
return err;
}
#endif
mach_error_t
mach_override_ptr(
void *originalFunctionAddress,
const void *overrideFunctionAddress,
void **originalFunctionReentryIsland )
{
assert( originalFunctionAddress );
assert( overrideFunctionAddress );
// this addresses overriding such functions as AudioOutputUnitStart()
// test with modified DefaultOutputUnit project
#if defined(__x86_64__)
for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp qword near [rip+0x????????]
originalFunctionAddress=*(void**)((char*)originalFunctionAddress+6+*(int32_t *)((uint16_t*)originalFunctionAddress+1));
else break;
}
#elif defined(__i386__)
for(;;){
if(*(uint16_t*)originalFunctionAddress==0x25FF) // jmp *0x????????
originalFunctionAddress=**(void***)((uint16_t*)originalFunctionAddress+1);
else break;
}
#endif
long *originalFunctionPtr = (long*) originalFunctionAddress;
mach_error_t err = err_none;
#if defined(__ppc__) || defined(__POWERPC__)
// Ensure first instruction isn't 'mfctr'.
#define kMFCTRMask 0xfc1fffff
#define kMFCTRInstruction 0x7c0903a6
long originalInstruction = *originalFunctionPtr;
if( !err && ((originalInstruction & kMFCTRMask) == kMFCTRInstruction) )
err = err_cannot_override;
#elif defined(__i386__) || defined(__x86_64__)
int eatenCount = 0;
int originalInstructionCount = 0;
char originalInstructions[kOriginalInstructionsSize];
uint8_t originalInstructionSizes[kOriginalInstructionsSize];
uint64_t jumpRelativeInstruction = 0; // JMP
Boolean overridePossible = eatKnownInstructions ((unsigned char *)originalFunctionPtr,
&jumpRelativeInstruction, &eatenCount,
originalInstructions, &originalInstructionCount,
originalInstructionSizes );
if (eatenCount + kMaxFixupSizeIncrease > kOriginalInstructionsSize) {
//printf ("Too many instructions eaten\n");
overridePossible = false;
}
if (!overridePossible) err = err_cannot_override;
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
#endif
// Make the original function implementation writable.
if( !err ) {
err = vm_protect( mach_task_self(),
(vm_address_t) originalFunctionPtr, 8, false,
(VM_PROT_ALL | VM_PROT_COPY) );
if( err )
err = vm_protect( mach_task_self(),
(vm_address_t) originalFunctionPtr, 8, false,
(VM_PROT_DEFAULT | VM_PROT_COPY) );
}
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
// Allocate and target the escape island to the overriding function.
BranchIsland *escapeIsland = NULL;
if( !err )
err = allocateBranchIsland( &escapeIsland, originalFunctionAddress );
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
#if defined(__ppc__) || defined(__POWERPC__)
if( !err )
err = setBranchIslandTarget( escapeIsland, overrideFunctionAddress, 0 );
// Build the branch absolute instruction to the escape island.
long branchAbsoluteInstruction = 0; // Set to 0 just to silence warning.
if( !err ) {
long escapeIslandAddress = ((long) escapeIsland) & 0x3FFFFFF;
branchAbsoluteInstruction = 0x48000002 | escapeIslandAddress;
}
#elif defined(__i386__) || defined(__x86_64__)
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
if( !err )
err = setBranchIslandTarget_i386( escapeIsland, overrideFunctionAddress, 0 );
if (err) fprintf(stderr, "err = %x %s:%d\n", err, __FILE__, __LINE__);
// Build the jump relative instruction to the escape island
#endif
#if defined(__i386__) || defined(__x86_64__)
if (!err) {
uint32_t addressOffset = ((char*)escapeIsland - (char*)originalFunctionPtr - 5);
addressOffset = OSSwapInt32(addressOffset);
jumpRelativeInstruction |= 0xE900000000000000LL;
jumpRelativeInstruction |= ((uint64_t)addressOffset & 0xffffffff) << 24;
jumpRelativeInstruction = OSSwapInt64(jumpRelativeInstruction);
}
#endif
// Optionally allocate & return the reentry island. This may contain relocated
// jmp instructions and so has all the same addressing reachability requirements
// the escape island has to the original function, except the escape island is
// technically our original function.
BranchIsland *reentryIsland = NULL;
if( !err && originalFunctionReentryIsland ) {
err = allocateBranchIsland( &reentryIsland, escapeIsland);
if( !err )
*originalFunctionReentryIsland = reentryIsland;
}
#if defined(__ppc__) || defined(__POWERPC__)
// Atomically:
// o If the reentry island was allocated:
// o Insert the original instruction into the reentry island.
// o Target the reentry island at the 2nd instruction of the
// original function.
// o Replace the original instruction with the branch absolute.
if( !err ) {
int escapeIslandEngaged = false;
do {
if( reentryIsland )
err = setBranchIslandTarget( reentryIsland,
(void*) (originalFunctionPtr+1), originalInstruction );
if( !err ) {
escapeIslandEngaged = CompareAndSwap( originalInstruction,
branchAbsoluteInstruction,
(UInt32*)originalFunctionPtr );
if( !escapeIslandEngaged ) {
// Someone replaced the instruction out from under us,
// re-read the instruction, make sure it's still not
// 'mfctr' and try again.
originalInstruction = *originalFunctionPtr;
if( (originalInstruction & kMFCTRMask) == kMFCTRInstruction)
err = err_cannot_override;
}
}
} while( !err && !escapeIslandEngaged );
}
#elif defined(__i386__) || defined(__x86_64__)
// Atomically:
// o If the reentry island was allocated:
// o Insert the original instructions into the reentry island.
// o Target the reentry island at the first non-replaced
// instruction of the original function.
// o Replace the original first instructions with the jump relative.
//
// Note that on i386, we do not support someone else changing the code under our feet
if ( !err ) {
uint32_t offset = (uintptr_t)originalFunctionPtr - (uintptr_t)reentryIsland;
fixupInstructions(offset, originalInstructions,
originalInstructionCount, originalInstructionSizes );
if( reentryIsland )
err = setBranchIslandTarget_i386( reentryIsland,
(void*) ((char *)originalFunctionPtr+eatenCount), originalInstructions );
// try making islands executable before planting the jmp
#if defined(__x86_64__) || defined(__i386__)
if( !err )
err = makeIslandExecutable(escapeIsland);
if( !err && reentryIsland )
err = makeIslandExecutable(reentryIsland);
#endif
if ( !err )
atomic_mov64((uint64_t *)originalFunctionPtr, jumpRelativeInstruction);
}
#endif
// Clean up on error.
if( err ) {
if( reentryIsland )
freeBranchIsland( reentryIsland );
if( escapeIsland )
freeBranchIsland( escapeIsland );
}
return err;
}
/*******************************************************************************
*
* Implementation
*
*******************************************************************************/
#pragma mark -
#pragma mark (Implementation)
static bool jump_in_range(intptr_t from, intptr_t to) {
intptr_t field_value = to - from - 5;
int32_t field_value_32 = field_value;
return field_value == field_value_32;
}
/*******************************************************************************
Implementation: Allocates memory for a branch island.
@param island <- The allocated island.
@result <- mach_error_t
***************************************************************************/
static mach_error_t
allocateBranchIslandAux(
BranchIsland **island,
void *originalFunctionAddress,
bool forward)
{
assert( island );
assert( sizeof( BranchIsland ) <= kPageSize );
vm_map_t task_self = mach_task_self();
vm_address_t original_address = (vm_address_t) originalFunctionAddress;
vm_address_t address = original_address;
for (;;) {
vm_size_t vmsize = 0;
memory_object_name_t object = 0;
kern_return_t kr = 0;
vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
// Find the region the address is in.
#if __WORDSIZE == 32
vm_region_basic_info_data_t info;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
kr = vm_region(task_self, &address, &vmsize, flavor,
(vm_region_info_t)&info, &info_count, &object);
#else
vm_region_basic_info_data_64_t info;
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
kr = vm_region_64(task_self, &address, &vmsize, flavor,
(vm_region_info_t)&info, &info_count, &object);
#endif
if (kr != KERN_SUCCESS)
return kr;
assert((address & (kPageSize - 1)) == 0);
// Go to the first page before or after this region
vm_address_t new_address = forward ? address + vmsize : address - kPageSize;
#if __WORDSIZE == 64
if(!jump_in_range(original_address, new_address))
break;
#endif
address = new_address;
// Try to allocate this page.
kr = vm_allocate(task_self, &address, kPageSize, 0);
if (kr == KERN_SUCCESS) {
*island = (BranchIsland*) address;
return err_none;
}
if (kr != KERN_NO_SPACE)
return kr;
}
return KERN_NO_SPACE;
}
static mach_error_t
allocateBranchIsland(
BranchIsland **island,
void *originalFunctionAddress)
{
mach_error_t err =
allocateBranchIslandAux(island, originalFunctionAddress, true);
if (!err)
return err;
return allocateBranchIslandAux(island, originalFunctionAddress, false);
}
/*******************************************************************************
Implementation: Deallocates memory for a branch island.
@param island -> The island to deallocate.
@result <- mach_error_t
***************************************************************************/
mach_error_t
freeBranchIsland(
BranchIsland *island )
{
assert( island );
assert( (*(long*)&island->instructions[0]) == kIslandTemplate[0] );
assert( sizeof( BranchIsland ) <= kPageSize );
return vm_deallocate( mach_task_self(), (vm_address_t) island,
kPageSize );
}
/*******************************************************************************
Implementation: Sets the branch island's target, with an optional
instruction.
@param island -> The branch island to insert target into.
@param branchTo -> The address of the target.
@param instruction -> Optional instruction to execute prior to branch. Set
to zero for nop.
@result <- mach_error_t
***************************************************************************/
#if defined(__ppc__) || defined(__POWERPC__)
mach_error_t
setBranchIslandTarget(
BranchIsland *island,
const void *branchTo,
long instruction )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// Fill in the address.
((short*)island->instructions)[kAddressLo] = ((long) branchTo) & 0x0000FFFF;
((short*)island->instructions)[kAddressHi]
= (((long) branchTo) >> 16) & 0x0000FFFF;
// Fill in the (optional) instuction.
if( instruction != 0 ) {
((short*)island->instructions)[kInstructionLo]
= instruction & 0x0000FFFF;
((short*)island->instructions)[kInstructionHi]
= (instruction >> 16) & 0x0000FFFF;
}
//MakeDataExecutable( island->instructions, sizeof( kIslandTemplate ) );
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#endif
#if defined(__i386__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// copy original instructions
if (instructions) {
bcopy (instructions, island->instructions + kInstructions, kOriginalInstructionsSize);
}
// Fill in the address.
int32_t addressOffset = (char *)branchTo - (island->instructions + kJumpAddress + 4);
*((int32_t *)(island->instructions + kJumpAddress)) = addressOffset;
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#elif defined(__x86_64__)
mach_error_t
setBranchIslandTarget_i386(
BranchIsland *island,
const void *branchTo,
char* instructions )
{
// Copy over the template code.
bcopy( kIslandTemplate, island->instructions, sizeof( kIslandTemplate ) );
// Copy original instructions.
if (instructions) {
bcopy (instructions, island->instructions, kOriginalInstructionsSize);
}
// Fill in the address.
*((uint64_t *)(island->instructions + kJumpAddress)) = (uint64_t)branchTo;
msync( island->instructions, sizeof( kIslandTemplate ), MS_INVALIDATE );
return err_none;
}
#endif
#if defined(__i386__) || defined(__x86_64__)
// simplistic instruction matching
typedef struct {
unsigned int length; // max 15
unsigned char mask[15]; // sequence of bytes in memory order
unsigned char constraint[15]; // sequence of bytes in memory order
} AsmInstructionMatch;
#if defined(__i386__)
static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x5, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x55, 0x89, 0xe5, 0xc9, 0xc3} }, // push %ebp; mov %esp,%ebp; leave; ret
{ 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xFF}, {0x55} }, // push %esp
{ 0x2, {0xFF, 0xFF}, {0x89, 0xE5} }, // mov %esp,%ebp
{ 0x1, {0xFF}, {0x53} }, // push %ebx
{ 0x3, {0xFF, 0xFF, 0x00}, {0x83, 0xEC, 0x00} }, // sub 0x??, %esp
{ 0x6, {0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x81, 0xEC, 0x00, 0x00, 0x00, 0x00} }, // sub 0x??, %esp with 32bit immediate
{ 0x1, {0xFF}, {0x57} }, // push %edi
{ 0x1, {0xFF}, {0x56} }, // push %esi
{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
{ 0x3, {0xFF, 0x4F, 0x00}, {0x8B, 0x45, 0x00} }, // mov $imm(%ebp), %reg
{ 0x3, {0xFF, 0x4C, 0x00}, {0x8B, 0x40, 0x00} }, // mov $imm(%eax-%edx), %reg
{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x8B, 0x4C, 0x24, 0x00} }, // mov $imm(%esp), %ecx
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %eax
{ 0x6, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0xE8, 0x00, 0x00, 0x00, 0x00, 0x58} }, // call $imm; pop %eax
{ 0x0 }
};
#elif defined(__x86_64__)
static AsmInstructionMatch possibleInstructions[] = {
{ 0x5, {0xFF, 0x00, 0x00, 0x00, 0x00}, {0xE9, 0x00, 0x00, 0x00, 0x00} }, // jmp 0x????????
{ 0x1, {0xFF}, {0x90} }, // nop
{ 0x1, {0xF8}, {0x50} }, // push %rX
{ 0x3, {0xFF, 0xFF, 0xFF}, {0x48, 0x89, 0xE5} }, // mov %rsp,%rbp
{ 0x4, {0xFF, 0xFF, 0xFF, 0x00}, {0x48, 0x83, 0xEC, 0x00} }, // sub 0x??, %rsp
{ 0x4, {0xFB, 0xFF, 0x00, 0x00}, {0x48, 0x89, 0x00, 0x00} }, // move onto rbp
{ 0x4, {0xFF, 0xFF, 0xFF, 0xFF}, {0x40, 0x0f, 0xbe, 0xce} }, // movsbl %sil, %ecx
{ 0x2, {0xFF, 0x00}, {0x41, 0x00} }, // push %rXX
{ 0x2, {0xFF, 0x00}, {0x85, 0x00} }, // test %rX,%rX
{ 0x5, {0xF8, 0x00, 0x00, 0x00, 0x00}, {0xB8, 0x00, 0x00, 0x00, 0x00} }, // mov $imm, %reg
{ 0x3, {0xFF, 0xFF, 0x00}, {0xFF, 0x77, 0x00} }, // pushq $imm(%rdi)
{ 0x2, {0xFF, 0xFF}, {0x31, 0xC0} }, // xor %eax, %eax
{ 0x2, {0xFF, 0xFF}, {0x89, 0xF8} }, // mov %edi, %eax
//leaq offset(%rip),%rax
{ 0x7, {0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}, {0x48, 0x8d, 0x05, 0x00, 0x00, 0x00, 0x00} },
{ 0x0 }
};
#endif
static Boolean codeMatchesInstruction(unsigned char *code, AsmInstructionMatch* instruction)
{
Boolean match = true;
size_t i;
for (i=0; i<instruction->length; i++) {
unsigned char mask = instruction->mask[i];
unsigned char constraint = instruction->constraint[i];
unsigned char codeValue = code[i];
match = ((codeValue & mask) == constraint);
if (!match) break;
}
return match;
}
#if defined(__i386__) || defined(__x86_64__)
static Boolean
eatKnownInstructions(
unsigned char *code,
uint64_t *newInstruction,
int *howManyEaten,
char *originalInstructions,
int *originalInstructionCount,
uint8_t *originalInstructionSizes )
{
Boolean allInstructionsKnown = true;
int totalEaten = 0;
unsigned char* ptr = code;
int remainsToEat = 5; // a JMP instruction takes 5 bytes
int instructionIndex = 0;
if (howManyEaten) *howManyEaten = 0;
if (originalInstructionCount) *originalInstructionCount = 0;
while (remainsToEat > 0) {
Boolean curInstructionKnown = false;
// See if instruction matches one we know
AsmInstructionMatch* curInstr = possibleInstructions;
do {
if ((curInstructionKnown = codeMatchesInstruction(ptr, curInstr))) break;
curInstr++;
} while (curInstr->length > 0);
// if all instruction matches failed, we don't know current instruction then, stop here
if (!curInstructionKnown) {
allInstructionsKnown = false;
fprintf(stderr, "mach_override: some instructions unknown! Need to update mach_override.c\n");
break;
}
// At this point, we've matched curInstr
int eaten = curInstr->length;
ptr += eaten;
remainsToEat -= eaten;
totalEaten += eaten;
if (originalInstructionSizes) originalInstructionSizes[instructionIndex] = eaten;
instructionIndex += 1;
if (originalInstructionCount) *originalInstructionCount = instructionIndex;
}
if (howManyEaten) *howManyEaten = totalEaten;
if (originalInstructions) {
Boolean enoughSpaceForOriginalInstructions = (totalEaten < kOriginalInstructionsSize);
if (enoughSpaceForOriginalInstructions) {
memset(originalInstructions, 0x90 /* NOP */, kOriginalInstructionsSize); // fill instructions with NOP
bcopy(code, originalInstructions, totalEaten);
} else {
// printf ("Not enough space in island to store original instructions. Adapt the island definition and kOriginalInstructionsSize\n");
return false;
}
}
if (allInstructionsKnown) {
// save last 3 bytes of first 64bits of codre we'll replace
uint64_t currentFirst64BitsOfCode = *((uint64_t *)code);
currentFirst64BitsOfCode = OSSwapInt64(currentFirst64BitsOfCode); // back to memory representation
currentFirst64BitsOfCode &= 0x0000000000FFFFFFLL;
// keep only last 3 instructions bytes, first 5 will be replaced by JMP instr
*newInstruction &= 0xFFFFFFFFFF000000LL; // clear last 3 bytes
*newInstruction |= (currentFirst64BitsOfCode & 0x0000000000FFFFFFLL); // set last 3 bytes
}
return allInstructionsKnown;
}
static void
fixupInstructions(
uint32_t offset,
void *instructionsToFix,
int instructionCount,
uint8_t *instructionSizes )
{
// The start of "leaq offset(%rip),%rax"
static const uint8_t LeaqHeader[] = {0x48, 0x8d, 0x05};
int index;
for (index = 0;index < instructionCount;index += 1)
{
if (*(uint8_t*)instructionsToFix == 0xE9) // 32-bit jump relative
{
uint32_t *jumpOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 1);
*jumpOffsetPtr += offset;
}
// leaq offset(%rip),%rax
if (memcmp(instructionsToFix, LeaqHeader, 3) == 0) {
uint32_t *LeaqOffsetPtr = (uint32_t*)((uintptr_t)instructionsToFix + 3);
*LeaqOffsetPtr += offset;
}
// 32-bit call relative to the next addr; pop %eax
if (*(uint8_t*)instructionsToFix == 0xE8)
{
// Just this call is larger than the jump we use, so we
// know this is the last instruction.
assert(index == (instructionCount - 1));
assert(instructionSizes[index] == 6);
// Insert "addl $offset, %eax" in the end so that when
// we jump to the rest of the function %eax has the
// value it would have if eip had been pushed by the
// call in its original position.
uint8_t *op = (uint8_t*)instructionsToFix;
op += 6;
*op = 0x05; // addl
uint32_t *addImmPtr = (uint32_t*)(op + 1);
*addImmPtr = offset;
}
instructionsToFix = (void*)((uintptr_t)instructionsToFix + instructionSizes[index]);
}
}
#endif
#if defined(__i386__)
void atomic_mov64(
uint64_t *targetAddress,
uint64_t value)
{
while (true)
{
uint64_t old_value = *targetAddress;
if (OSAtomicCompareAndSwap64(old_value, value, (int64_t*)targetAddress)) return;
}
}
#elif defined(__x86_64__)
void atomic_mov64(
uint64_t *targetAddress,
uint64_t value )
{
*targetAddress = value;
}
#endif
#endif

View file

@ -0,0 +1,76 @@
// mach_override.h semver:1.2.0
// Copyright (c) 2003-2012 Jonathan 'Wolf' Rentzsch: http://rentzsch.com
// Some rights reserved: http://opensource.org/licenses/mit
// https://github.com/rentzsch/mach_override
#ifndef _mach_override_
#define _mach_override_
#include <sys/types.h>
#include <mach/error.h>
#define err_cannot_override (err_local|1)
__BEGIN_DECLS
/****************************************************************************************
Dynamically overrides the function implementation referenced by
originalFunctionAddress with the implentation pointed to by overrideFunctionAddress.
Optionally returns a pointer to a "reentry island" which, if jumped to, will resume
the original implementation.
@param originalFunctionAddress -> Required address of the function to
override (with overrideFunctionAddress).
@param overrideFunctionAddress -> Required address to the overriding
function.
@param originalFunctionReentryIsland <- Optional pointer to pointer to the
reentry island. Can be NULL.
@result <- err_cannot_override if the original
function's implementation begins with
the 'mfctr' instruction.
************************************************************************************/
mach_error_t
mach_override_ptr(
void *originalFunctionAddress,
const void *overrideFunctionAddress,
void **originalFunctionReentryIsland );
__END_DECLS
/****************************************************************************************
If you're using C++ this macro will ease the tedium of typedef'ing, naming, keeping
track of reentry islands and defining your override code. See test_mach_override.cp
for example usage.
************************************************************************************/
#ifdef __cplusplus
#define MACH_OVERRIDE( ORIGINAL_FUNCTION_RETURN_TYPE, ORIGINAL_FUNCTION_NAME, ORIGINAL_FUNCTION_ARGS, ERR ) \
{ \
static ORIGINAL_FUNCTION_RETURN_TYPE (*ORIGINAL_FUNCTION_NAME##_reenter)ORIGINAL_FUNCTION_ARGS; \
static bool ORIGINAL_FUNCTION_NAME##_overriden = false; \
class mach_override_class__##ORIGINAL_FUNCTION_NAME { \
public: \
static kern_return_t override(void *originalFunctionPtr) { \
kern_return_t result = err_none; \
if (!ORIGINAL_FUNCTION_NAME##_overriden) { \
ORIGINAL_FUNCTION_NAME##_overriden = true; \
result = mach_override_ptr( (void*)originalFunctionPtr, \
(void*)mach_override_class__##ORIGINAL_FUNCTION_NAME::replacement, \
(void**)&ORIGINAL_FUNCTION_NAME##_reenter ); \
} \
return result; \
} \
static ORIGINAL_FUNCTION_RETURN_TYPE replacement ORIGINAL_FUNCTION_ARGS {
#define END_MACH_OVERRIDE( ORIGINAL_FUNCTION_NAME ) \
} \
}; \
\
err = mach_override_class__##ORIGINAL_FUNCTION_NAME::override((void*)ORIGINAL_FUNCTION_NAME); \
}
#endif
#endif // _mach_override_

116
togles/togl.vpc Normal file
View file

@ -0,0 +1,116 @@
//-----------------------------------------------------------------------------
// TOGL.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR ".." [$WIN32]
$Macro SRCDIR ".." [!$WIN32]
$Macro OUTBINDIR $LIBPUBLIC
$Macro OUTBINNAME "togl"
$Macro TOGL_SRCDIR "$SRCDIR/togl/linuxwin"
$Macro TOGL_INCDIR "$SRCDIR/public/togl/linuxwin"
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
// Common Configuration
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE;..\"
$PreprocessorDefinitions "$BASE;TOGL_DLL_EXPORT;PROTECTED_THINGS_ENABLE;strncpy=use_Q_strncpy_instead;_snprintf=use_Q_snprintf_instead" [!$OSXALL]
$PreprocessorDefinitions "$BASE;TOGL_DLL_EXPORT" [$OSXALL]
}
$Linker
{
$ImportLibrary "$LIBPUBLIC\$_IMPLIB_PREFIX$OUTBINNAME$_IMPLIB_EXT" [!$X360 && !$OSXALL]
$ImportLibrary "$SRCDIR\lib\$PLATFORM\$_IMPLIB_PREFIX$OUTBINNAME$_IMPLIB_EXT" [$OSXALL]
}
$Linker [$OSXALL]
{
$SystemFrameworks "Carbon;OpenGL;Quartz;Cocoa;IOKit"
}
// togl/tier0/vstdlib traditionally used "lib" prefix though nobody else seems to.
$Linker [$POSIX]
{
$OutputFile "$(OBJ_DIR)/$_IMPLIB_PREFIX$OUTBINNAME$_DLL_EXT"
}
$General [$POSIX]
{
$GameOutputFile "$OUTBINDIR/$_IMPLIB_PREFIX$OUTBINNAME$_DLL_EXT"
}
$PreLinkEvent [$WINDOWS]
{
$CommandLine "call $SRCDIR\vpc_scripts\valve_p4_edit.cmd $LIBPUBLIC\$(TargetName).lib $SRCDIR" "\n" \
"$BASE"
}
}
$Project "togl"
{
$Folder "Source Files" [$GL]
{
$File "$TOGL_SRCDIR/dx9asmtogl2.cpp"
$File "$TOGL_SRCDIR/dxabstract.cpp"
$File "$TOGL_SRCDIR/glentrypoints.cpp"
$File "$TOGL_SRCDIR/glmgr.cpp"
$File "$TOGL_SRCDIR/glmgrbasics.cpp"
$File "$TOGL_SRCDIR/glmgrcocoa.mm" [$OSXALL]
$File "$TOGL_SRCDIR/intelglmallocworkaround.cpp" [$OSXALL]
$File "$TOGL_SRCDIR/mach_override.c" [$OSXALL]
$File "$TOGL_SRCDIR/cglmtex.cpp"
$File "$TOGL_SRCDIR/cglmfbo.cpp"
$File "$TOGL_SRCDIR/cglmprogram.cpp"
$File "$TOGL_SRCDIR/cglmbuffer.cpp"
$File "$TOGL_SRCDIR/cglmquery.cpp"
$File "$TOGL_SRCDIR/asanstubs.cpp"
}
$Folder "DirectX Header Files" [$WIN32 && !$GL]
{
}
$Folder "Header Files" [$GL]
{
$File "$TOGL_SRCDIR/dx9asmtogl2.h"
$File "$TOGL_SRCDIR/glmgr_flush.inl"
$File "$TOGL_SRCDIR/intelglmallocworkaround.h" [$OSXALL]
$File "$TOGL_SRCDIR/mach_override.h" [$OSXALL]
}
$Folder "Public Header Files" [$GL]
{
$File "$SRCDIR/public/togl/rendermechanism.h"
$File "$TOGL_INCDIR/dxabstract.h"
$File "$TOGL_INCDIR/dxabstract_types.h"
$File "$TOGL_INCDIR/glbase.h"
$File "$TOGL_INCDIR/glentrypoints.h"
$File "$TOGL_INCDIR/glmgr.h"
$File "$TOGL_INCDIR/glmdebug.h"
$File "$TOGL_INCDIR/glmgrbasics.h"
$File "$TOGL_INCDIR/glmgrext.h"
$File "$TOGL_INCDIR/glmdisplay.h"
$File "$TOGL_INCDIR/glmdisplaydb.h"
$File "$TOGL_INCDIR/glfuncs.h"
$File "$TOGL_INCDIR/cglmtex.h"
$File "$TOGL_INCDIR/cglmfbo.h"
$File "$TOGL_INCDIR/cglmprogram.h"
$File "$TOGL_INCDIR/cglmbuffer.h"
$File "$TOGL_INCDIR/cglmquery.h"
}
$Folder "Link Libraries"
{
$Lib tier2
$Lib mathlib
}
}

62
togles/wscript Executable file
View file

@ -0,0 +1,62 @@
#! /usr/bin/env python
# encoding: utf-8
from waflib import Utils
import os
top = '.'
PROJECT_NAME = 'togl'
def options(opt):
# stub
return
def configure(conf):
conf.define('TOGL_DLL_EXPORT',1)
conf.env.append_unique('DEFINES',['strncpy=use_Q_strncpy_instead',
'_snprintf=use_Q_snprintf_instead'])
def build(bld):
source = [
'linuxwin/dx9asmtogl2.cpp',
'linuxwin/dxabstract.cpp',
'linuxwin/glentrypoints.cpp',
'linuxwin/glmgr.cpp',
'linuxwin/glmgrbasics.cpp',
#'linuxwin/glmgrcocoa.mm', [$OSXALL]
#'linuxwin/intelglmallocworkaround.cpp', [$OSXALL]
#'linuxwin/mach_override.c', [$OSXALL]
'linuxwin/cglmtex.cpp',
'linuxwin/cglmfbo.cpp',
'linuxwin/cglmprogram.cpp',
'linuxwin/cglmbuffer.cpp',
'linuxwin/cglmquery.cpp',
'linuxwin/asanstubs.cpp'
]
includes = [
'.',
'../public',
'../public/tier0',
'../public/tier1'
] + bld.env.INCLUDES_SDL2
defines = []
libs = ['tier0','tier1','tier2','vstdlib','mathlib']
install_path = bld.env.LIBDIR
bld.shlib(
source = source,
target = PROJECT_NAME,
name = PROJECT_NAME,
features = 'c cxx',
includes = includes,
defines = defines,
use = libs,
install_path = install_path,
subsystem = bld.env.MSVC_SUBSYSTEM,
idx = bld.get_taskgen_count()
)