diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /togl/linuxwin/cglmquery.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'togl/linuxwin/cglmquery.cpp')
| -rw-r--r-- | togl/linuxwin/cglmquery.cpp | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/togl/linuxwin/cglmquery.cpp b/togl/linuxwin/cglmquery.cpp new file mode 100644 index 0000000..199780a --- /dev/null +++ b/togl/linuxwin/cglmquery.cpp @@ -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; +} + |