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 /materialsystem/occlusionquerymgr.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'materialsystem/occlusionquerymgr.cpp')
| -rw-r--r-- | materialsystem/occlusionquerymgr.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/materialsystem/occlusionquerymgr.cpp b/materialsystem/occlusionquerymgr.cpp new file mode 100644 index 0000000..5ee497e --- /dev/null +++ b/materialsystem/occlusionquerymgr.cpp @@ -0,0 +1,258 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "pch_materialsystem.h" + +#define MATSYS_INTERNAL + +#include "occlusionquerymgr.h" +#include "imaterialsysteminternal.h" +#include "imatrendercontextinternal.h" + +// NOTE: This must be the last file included!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +static COcclusionQueryMgr s_OcclusionQueryMgr; +COcclusionQueryMgr *g_pOcclusionQueryMgr = &s_OcclusionQueryMgr; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +COcclusionQueryMgr::COcclusionQueryMgr() +{ + m_nFrameCount = 0; +} + + +//----------------------------------------------------------------------------- +// Allocate and delete query objects. +//----------------------------------------------------------------------------- +OcclusionQueryObjectHandle_t COcclusionQueryMgr::CreateOcclusionQueryObject( ) +{ + m_Mutex.Lock(); + int h = m_OcclusionQueryObjects.AddToTail(); + m_Mutex.Unlock(); + return (OcclusionQueryObjectHandle_t)h; +} + +void COcclusionQueryMgr::OnCreateOcclusionQueryObject( OcclusionQueryObjectHandle_t h ) +{ + for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) + { + m_OcclusionQueryObjects[(int)h].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject( ); + } +} + +// Flushes an outstanding query +// HEY - Be very careful using this method - it causes a full pipeline flush/stall! +void COcclusionQueryMgr::FlushQuery( OcclusionQueryObjectHandle_t hOcclusionQuery, int nIndex ) +{ + // Flush out any previous queries + int h = (int)hOcclusionQuery; + if ( m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] ) + { + ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nIndex]; + + while ( OCCLUSION_QUERY_RESULT_PENDING == g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, true ) ) + continue; + } +} + +void COcclusionQueryMgr::DestroyOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery ) +{ + int h = (int)hOcclusionQuery; + Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); + if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) + { + for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) + { + if ( m_OcclusionQueryObjects[h].m_QueryHandle[i] != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) + { + g_pShaderAPI->DestroyOcclusionQueryObject( m_OcclusionQueryObjects[h].m_QueryHandle[i] ); + } + } + m_Mutex.Lock(); + m_OcclusionQueryObjects.Remove( h ); + m_Mutex.Unlock(); + } +} + + +//----------------------------------------------------------------------------- +// Advance frame +//----------------------------------------------------------------------------- +void COcclusionQueryMgr::AdvanceFrame() +{ + ++m_nFrameCount; +} + + +//----------------------------------------------------------------------------- +// Alt-tab support +// NOTE: This doesn't queue anything up +//----------------------------------------------------------------------------- +void COcclusionQueryMgr::AllocOcclusionQueryObjects( void ) +{ + FOR_EACH_LL( m_OcclusionQueryObjects, iterator ) + { + for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) + { + m_OcclusionQueryObjects[iterator].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject(); + m_OcclusionQueryObjects[iterator].m_bHasBeenIssued[i] = false; // any in-flight queries are never returning + } + } +} + +void COcclusionQueryMgr::FreeOcclusionQueryObjects( void ) +{ + FOR_EACH_LL( m_OcclusionQueryObjects, iterator ) + { + for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) + { + if ( m_OcclusionQueryObjects[iterator].m_QueryHandle[i] != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) + { + g_pShaderAPI->DestroyOcclusionQueryObject( m_OcclusionQueryObjects[iterator].m_QueryHandle[i] ); + m_OcclusionQueryObjects[iterator].m_QueryHandle[i] = INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE; + m_OcclusionQueryObjects[iterator].m_bHasBeenIssued[i] = false; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Used to make the handle think it's never had a successful query before +//----------------------------------------------------------------------------- +void COcclusionQueryMgr::ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery ) +{ + int h = (int)hOcclusionQuery; + Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); + if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) + { + // Forget we've issued any previous queries - there's no need to flush them. + for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++) + { + m_OcclusionQueryObjects[h].m_bHasBeenIssued[i] = false; + } + + m_OcclusionQueryObjects[h].m_LastResult = -1; + m_OcclusionQueryObjects[h].m_nFrameIssued = -1; + } +} + + +//----------------------------------------------------------------------------- +// Bracket drawing with begin and end so that we can get counts next frame. +//----------------------------------------------------------------------------- +void COcclusionQueryMgr::BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery ) +{ + int h = (int)hOcclusionQuery; + Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); + if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) + { + int nCurrent = m_OcclusionQueryObjects[h].m_nCurrentIssue; + ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nCurrent]; + if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) + { + // If it's been issued, but we haven't gotten a result when we polled last time, + // try polling one last time, since we can't poll again after we issue again. + if ( m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] ) + { + int nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, false ); + if ( ( nPixels == OCCLUSION_QUERY_RESULT_PENDING ) && ( m_OcclusionQueryObjects[h].m_nFrameIssued == m_nFrameCount ) ) + { + static int s_nWarnCount = 0; + if ( s_nWarnCount++ < 5 ) + { + DevWarning( "blocking issue in occlusion queries! Grab brian!\n" ); + } + } + while( !OCCLUSION_QUERY_FINISHED( nPixels ) ) + { + // We're going to reuse this query, so issue a flush to force the query results to come back. + nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, true ); + } + if ( nPixels >= 0 ) + { + m_OcclusionQueryObjects[h].m_LastResult = nPixels; + } + m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] = false; + } + g_pShaderAPI->BeginOcclusionQueryDrawing( hQuery ); + } + } +} + + +void COcclusionQueryMgr::EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery ) +{ + int h = (int)hOcclusionQuery; + Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); + if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) + { + int nCurrent = m_OcclusionQueryObjects[h].m_nCurrentIssue; + ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nCurrent]; + if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE ) + { + g_pShaderAPI->EndOcclusionQueryDrawing( hQuery ); + + m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] = true; + m_OcclusionQueryObjects[h].m_nFrameIssued = m_nFrameCount; + + nCurrent = ( nCurrent + 1 ) % COUNT_OCCLUSION_QUERY_STACK; + m_OcclusionQueryObjects[h].m_nCurrentIssue = nCurrent; + } + } +} + + +//----------------------------------------------------------------------------- +// Get the number of pixels rendered between begin and end on an earlier frame. +// Calling this in the same frame is a huge perf hit! +//----------------------------------------------------------------------------- +void COcclusionQueryMgr::OcclusionQuery_IssueNumPixelsRenderedQuery( OcclusionQueryObjectHandle_t hOcclusionQuery ) +{ + int h = (int)hOcclusionQuery; + Assert( m_OcclusionQueryObjects.IsValidIndex( h ) ); + if ( m_OcclusionQueryObjects.IsValidIndex( h ) ) + { + for( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++ ) + { + int nIndex = ( m_OcclusionQueryObjects[h].m_nCurrentIssue + i ) % COUNT_OCCLUSION_QUERY_STACK; + ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nIndex]; + if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE && m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] ) + { + int nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery ); + if ( nPixels == OCCLUSION_QUERY_RESULT_ERROR ) + { + // In GL mode, it's possible for queries to fail (say when mat_queue_mode is toggled). In this case, just clear m_bHasBeenIssued and forget we ever issued this query. + m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] = false; + } + else if ( nPixels >= 0 ) + { + m_OcclusionQueryObjects[h].m_LastResult = nPixels; + m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] = false; + } + } + } + } +} + +int COcclusionQueryMgr::OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t h, bool bDoQuery ) +{ + if ( bDoQuery ) + { + OcclusionQuery_IssueNumPixelsRenderedQuery( h ); + } + + int nPixels = m_OcclusionQueryObjects[(int)h].m_LastResult; + return nPixels; +} |