Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

413 lines
10 KiB

//============ Copyright (c) Valve Corporation, All rights reserved. ============
//
// cglmquery.cpp
//
//===============================================================================
#include "glmgr/glmgr.h"
#include "glmgr/cglmquery.h"
#include "../shaderapidx9/dxabstract.h"
#include <unistd.h>
// memdbgon -must- be the last include file in a .cpp file.
#include "tier0/memdbgon.h"
//===============================================================================
extern ConVar gl_errorcheckall;
extern ConVar gl_errorcheckqueries;
extern ConVar gl_errorchecknone;
// how many microseconds to wait after a failed query-available test
// presently on MTGL this doesn't happen, but it could change, keep this handy
ConVar gl_nullqueries( "gl_nullqueries", "0" );
GLenum GetQueryError( void )
{
if ( ( GLMDEBUG || (gl_errorcheckall.GetInt() != 0) || (gl_errorcheckqueries.GetInt() != 0) ) && (gl_errorchecknone.GetInt() == 0) )
{
return glGetError();
}
else
{
return (GLenum) 0; // whistle past graveyard
}
}
//===============================================================================
CGLMQuery::CGLMQuery( GLMContext *ctx, GLMQueryParams *params )
{
// make sure context is current
// get the type of query requested
// generate name(s) needed
// set initial state appropriately
ctx->MakeCurrent();
m_ctx = ctx;
m_params = *params;
m_name = 0;
m_started = m_stopped = m_done = false;
m_nullQuery = false;
// assume value of convar at start time
// does not change during individual query lifetime
// started null = stays null
// started live = stays live
switch(m_params.m_type)
{
case EOcclusion:
{
//make an occlusion query (and a fence to go with it)
glGenQueriesARB( 1, &m_name );
GLMPRINTF(("-A- CGLMQuery(OQ) created name %d", m_name));
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::CGLMQuery (OQ) saw %s error (%d) from glGenQueriesARB", decodedStr, errorcode );
m_name = 0;
}
}
break;
case EFence:
//make a fence - no aux fence needed
glGenFencesAPPLE(1, &m_name );
GLMPRINTF(("-A- CGLMQuery(fence) created name %d", m_name));
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::CGLMQuery (fence) saw %s error (%d) from glGenFencesAPPLE", decodedStr, errorcode );
m_name = 0;
}
break;
}
}
CGLMQuery::~CGLMQuery()
{
GLMPRINTF(("-A-> ~CGLMQuery"));
// make sure query has completed (might not be necessary)
// delete the name(s)
m_ctx->MakeCurrent();
switch(m_params.m_type)
{
case EOcclusion:
{
// do a finish occlusion query ?
GLMPRINTF(("-A- ~CGLMQuery(OQ) deleting name %d", m_name));
glDeleteQueries(1, &m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::~CGLMQuery (OQ) saw %s error (%d) from glDeleteQueries", decodedStr, errorcode );
}
}
break;
case EFence:
{
// do a finish fence ?
GLMPRINTF(("-A- ~CGLMQuery(fence) deleting name %d", m_name));
glDeleteFencesAPPLE(1, &m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::~CGLMQuery (fence) saw %s error (%d) from glDeleteFencesAPPLE", decodedStr, errorcode );
}
}
break;
}
m_name = 0;
GLMPRINTF(("-A-< ~CGLMQuery"));
}
void CGLMQuery::Start( void ) // "start counting"
{
m_ctx->MakeCurrent();
// on occlusion query:
// glBeginQueryARB on the OQ name. counting starts.
// on fence: glSetFence on m_name.
// note, fences finish themselves via command progress - OQ's do not.
Assert(!m_started);
Assert(!m_stopped);
Assert(!m_done);
m_nullQuery = (gl_nullqueries.GetInt() != 0); // latch value for remainder of query life
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
// do nothing..
}
else
{
glBeginQueryARB( GL_SAMPLES_PASSED_ARB, m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Start(OQ) saw %s error (%d) from glBeginQueryARB (GL_SAMPLES_PASSED_ARB) name=%d", decodedStr, errorcode, m_name );
}
}
}
break;
case EFence:
glSetFenceAPPLE( m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Start(fence) saw %s error (%d) from glSetFenceAPPLE name=%d", decodedStr, errorcode, m_name );
}
m_stopped = true; // caller should not call Stop on a fence, it self-stops
break;
}
m_started = true;
}
void CGLMQuery::Stop( void ) // "stop counting"
{
m_ctx->MakeCurrent();
Assert(m_started);
Assert(!m_stopped); // this will assert if you try to call Stop on a fence that is started
Assert(!m_done);
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
// do nothing..
}
else
{
glEndQueryARB( GL_SAMPLES_PASSED_ARB ); // we are only putting the request-to-stop-counting into the cmd stream.
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Stop(OQ) saw %s error (%d) from glEndQueryARB( GL_SAMPLES_PASSED_ARB ) name=%d", decodedStr, errorcode, m_name );
}
}
}
break;
case EFence:
// nop - you don't "end" a fence, you just test it and/or finish it out in Complete
break;
}
m_stopped = true;
}
bool CGLMQuery::IsDone( void )
{
m_ctx->MakeCurrent();
Assert(m_started);
Assert(m_stopped);
if(!m_done) // you can ask more than once, but we only check until it comes back as done.
{
// on occlusion: glGetQueryObjectivARB - large cost on pre SLGU, cheap after
// on fence: glTestFenceAPPLE on the fence
switch(m_params.m_type)
{
case EOcclusion: // just test the fence that was set after the query begin
{
if (m_nullQuery)
{
// do almost nothing.. but claim work is complete
m_done = true;
}
else
{
// prepare to pay a big price on drivers prior to 10.6.4+SLGU
GLint available = 0;
glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glGetQueryObjectivARB(a2) name=%d", decodedStr, errorcode, m_name );
}
m_done = (available != 0);
}
}
break;
case EFence:
{
m_done = glTestFenceAPPLE( m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glTestFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
}
if (m_done)
{
glFinishFenceAPPLE( m_name ); // no set fence goes un-finished
errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::IsDone saw %s error (%d) from glFinishFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
}
}
}
break;
}
}
return m_done;
}
void CGLMQuery::Complete( uint *result )
{
m_ctx->MakeCurrent();
uint resultval = 0;
GLint available = 0;
bool bogus_available = false;
// blocking call if not done
Assert(m_started);
Assert(m_stopped);
switch(m_params.m_type)
{
case EOcclusion:
{
if (m_nullQuery)
{
m_done = true;
resultval = 0; // we did say "null queries..."
}
else
{
// accept that the query is going to drain pipe in 10.6.4 and prior.
// check the error on the spot.
glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_AVAILABLE_ARB name=%d", decodedStr, errorcode, m_name );
resultval=0;
}
else
{
if (!available)
{
// this does happen with some very modest frequency.
if (!m_ctx->Caps().m_hasPerfPackage1)
{
glFlush(); // ISTR some deadlock cases on pre-SLGU drivers if you didn't do this to kick the queue along..
}
}
glGetQueryObjectuivARB( m_name, GL_QUERY_RESULT_ARB, &resultval);
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_ARB name=%d", decodedStr, errorcode, m_name );
resultval=0;
}
else
{
// resultval is legit
}
}
m_done = true;
}
}
break;
case EFence:
{
if(!m_done)
{
glFinishFenceAPPLE( m_name );
GLenum errorcode = GetQueryError();
if (errorcode)
{
const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
printf( "\nCGLMQuery::Complete saw %s error (%d) from glFinishFenceAPPLE (EFence) name=%d", decodedStr, errorcode, m_name );
}
m_done = true; // for clarity or if they try to Complete twice
}
}
break;
}
Assert( m_done );
// reset state for re-use - i.e. you have to call Complete if you want to re-use the object
m_started = m_stopped = m_done = false;
if (result) // caller may pass NULL if not interested in result, for example to clear a fence
{
*result = resultval;
}
}
// accessors for the started/stopped state
bool CGLMQuery::IsStarted ( void )
{
return m_started;
}
bool CGLMQuery::IsStopped ( void )
{
return m_stopped;
}