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.

261 lines
9.1 KiB

  1. //========== Copyright © 2005, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "pch_materialsystem.h"
  7. #ifndef _PS3
  8. #define MATSYS_INTERNAL
  9. #endif
  10. #include "occlusionquerymgr.h"
  11. #include "imaterialsysteminternal.h"
  12. #include "imatrendercontextinternal.h"
  13. // NOTE: This must be the last file included!!!
  14. #include "tier0/memdbgon.h"
  15. //-----------------------------------------------------------------------------
  16. // Singleton
  17. //-----------------------------------------------------------------------------
  18. static COcclusionQueryMgr s_OcclusionQueryMgr;
  19. COcclusionQueryMgr *g_pOcclusionQueryMgr = &s_OcclusionQueryMgr;
  20. //-----------------------------------------------------------------------------
  21. // Constructor
  22. //-----------------------------------------------------------------------------
  23. COcclusionQueryMgr::COcclusionQueryMgr()
  24. {
  25. m_nFrameCount = 0;
  26. }
  27. //-----------------------------------------------------------------------------
  28. // Allocate and delete query objects.
  29. //-----------------------------------------------------------------------------
  30. OcclusionQueryObjectHandle_t COcclusionQueryMgr::CreateOcclusionQueryObject( )
  31. {
  32. m_Mutex.Lock();
  33. OcclusionQueryObjectHandle_t h = (OcclusionQueryObjectHandle_t)m_OcclusionQueryObjects.AddToTail();
  34. m_Mutex.Unlock();
  35. return h;
  36. }
  37. void COcclusionQueryMgr::OnCreateOcclusionQueryObject( OcclusionQueryObjectHandle_t h )
  38. {
  39. for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++)
  40. {
  41. m_OcclusionQueryObjects[(intp)h].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject( );
  42. }
  43. }
  44. // Flushes an outstanding query
  45. // HEY - Be very careful using this method - it causes a full pipeline flush/stall!
  46. void COcclusionQueryMgr::FlushQuery( OcclusionQueryObjectHandle_t hOcclusionQuery, int nIndex )
  47. {
  48. // Flush out any previous queries
  49. intp h = (intp)hOcclusionQuery;
  50. if ( m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] )
  51. {
  52. ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nIndex];
  53. while ( OCCLUSION_QUERY_RESULT_PENDING == g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, true ) )
  54. continue;
  55. }
  56. }
  57. void COcclusionQueryMgr::DestroyOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery )
  58. {
  59. intp h = (intp)hOcclusionQuery;
  60. Assert( m_OcclusionQueryObjects.IsValidIndex( h ) );
  61. if ( m_OcclusionQueryObjects.IsValidIndex( h ) )
  62. {
  63. for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++)
  64. {
  65. if ( m_OcclusionQueryObjects[h].m_QueryHandle[i] != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE )
  66. {
  67. g_pShaderAPI->DestroyOcclusionQueryObject( m_OcclusionQueryObjects[h].m_QueryHandle[i] );
  68. }
  69. }
  70. m_Mutex.Lock();
  71. m_OcclusionQueryObjects.Remove( h );
  72. m_Mutex.Unlock();
  73. }
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Advance frame
  77. //-----------------------------------------------------------------------------
  78. void COcclusionQueryMgr::AdvanceFrame()
  79. {
  80. ++m_nFrameCount;
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Alt-tab support
  84. // NOTE: This doesn't queue anything up
  85. //-----------------------------------------------------------------------------
  86. void COcclusionQueryMgr::AllocOcclusionQueryObjects( void )
  87. {
  88. FOR_EACH_LL( m_OcclusionQueryObjects, iterator )
  89. {
  90. for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++)
  91. {
  92. m_OcclusionQueryObjects[iterator].m_QueryHandle[i] = g_pShaderAPI->CreateOcclusionQueryObject();
  93. m_OcclusionQueryObjects[iterator].m_bHasBeenIssued[i] = false; // any in-flight queries are never returning
  94. }
  95. }
  96. }
  97. void COcclusionQueryMgr::FreeOcclusionQueryObjects( void )
  98. {
  99. FOR_EACH_LL( m_OcclusionQueryObjects, iterator )
  100. {
  101. for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++)
  102. {
  103. if ( m_OcclusionQueryObjects[iterator].m_QueryHandle[i] != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE )
  104. {
  105. g_pShaderAPI->DestroyOcclusionQueryObject( m_OcclusionQueryObjects[iterator].m_QueryHandle[i] );
  106. m_OcclusionQueryObjects[iterator].m_QueryHandle[i] = INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE;
  107. m_OcclusionQueryObjects[iterator].m_bHasBeenIssued[i] = false;
  108. }
  109. }
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Used to make the handle think it's never had a successful query before
  114. //-----------------------------------------------------------------------------
  115. void COcclusionQueryMgr::ResetOcclusionQueryObject( OcclusionQueryObjectHandle_t hOcclusionQuery )
  116. {
  117. intp h = (intp)hOcclusionQuery;
  118. Assert( m_OcclusionQueryObjects.IsValidIndex( h ) );
  119. if ( m_OcclusionQueryObjects.IsValidIndex( h ) )
  120. {
  121. // Forget we've issued any previous queries - there's no need to flush them.
  122. for ( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++)
  123. {
  124. m_OcclusionQueryObjects[h].m_bHasBeenIssued[i] = false;
  125. }
  126. m_OcclusionQueryObjects[h].m_LastResult = -1;
  127. m_OcclusionQueryObjects[h].m_nFrameIssued = -1;
  128. }
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Bracket drawing with begin and end so that we can get counts next frame.
  132. //-----------------------------------------------------------------------------
  133. void COcclusionQueryMgr::BeginOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery )
  134. {
  135. intp h = (intp)hOcclusionQuery;
  136. Assert( m_OcclusionQueryObjects.IsValidIndex( h ) );
  137. if ( m_OcclusionQueryObjects.IsValidIndex( h ) )
  138. {
  139. int nCurrent = m_OcclusionQueryObjects[h].m_nCurrentIssue;
  140. ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nCurrent];
  141. if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE )
  142. {
  143. // If it's been issued, but we haven't gotten a result when we polled last time,
  144. // try polling one last time, since we can't poll again after we issue again.
  145. if ( m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] )
  146. {
  147. int nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, false );
  148. if ( ( nPixels == OCCLUSION_QUERY_RESULT_PENDING ) && ( m_OcclusionQueryObjects[h].m_nFrameIssued == m_nFrameCount ) )
  149. {
  150. static int s_nWarnCount = 0;
  151. if ( s_nWarnCount++ < 5 )
  152. {
  153. DevWarning( "blocking issue in occlusion queries! Grab brian!\n" );
  154. }
  155. }
  156. while( !OCCLUSION_QUERY_FINISHED( nPixels ) )
  157. {
  158. // We're going to reuse this query, so issue a flush to force the query results to come back.
  159. nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery, true );
  160. }
  161. if ( nPixels >= 0 )
  162. {
  163. m_OcclusionQueryObjects[h].m_LastResult = nPixels;
  164. }
  165. m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] = false;
  166. }
  167. g_pShaderAPI->BeginOcclusionQueryDrawing( hQuery );
  168. }
  169. }
  170. }
  171. void COcclusionQueryMgr::EndOcclusionQueryDrawing( OcclusionQueryObjectHandle_t hOcclusionQuery )
  172. {
  173. intp h = (intp)hOcclusionQuery;
  174. Assert( m_OcclusionQueryObjects.IsValidIndex( h ) );
  175. if ( m_OcclusionQueryObjects.IsValidIndex( h ) )
  176. {
  177. int nCurrent = m_OcclusionQueryObjects[h].m_nCurrentIssue;
  178. ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nCurrent];
  179. if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE )
  180. {
  181. g_pShaderAPI->EndOcclusionQueryDrawing( hQuery );
  182. m_OcclusionQueryObjects[h].m_bHasBeenIssued[nCurrent] = true;
  183. m_OcclusionQueryObjects[h].m_nFrameIssued = m_nFrameCount;
  184. nCurrent = (nCurrent+1) % COUNT_OCCLUSION_QUERY_STACK;
  185. m_OcclusionQueryObjects[h].m_nCurrentIssue = nCurrent;
  186. }
  187. }
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Get the number of pixels rendered between begin and end on an earlier frame.
  191. // Calling this in the same frame is a huge perf hit!
  192. //-----------------------------------------------------------------------------
  193. void COcclusionQueryMgr::OcclusionQuery_IssueNumPixelsRenderedQuery( OcclusionQueryObjectHandle_t hOcclusionQuery )
  194. {
  195. intp h = (intp)hOcclusionQuery;
  196. Assert( m_OcclusionQueryObjects.IsValidIndex( h ) );
  197. if ( m_OcclusionQueryObjects.IsValidIndex( h ) )
  198. {
  199. for( int i = 0; i < COUNT_OCCLUSION_QUERY_STACK; i++ )
  200. {
  201. int nIndex = ( m_OcclusionQueryObjects[h].m_nCurrentIssue + i ) % COUNT_OCCLUSION_QUERY_STACK;
  202. ShaderAPIOcclusionQuery_t hQuery = m_OcclusionQueryObjects[h].m_QueryHandle[nIndex];
  203. if ( hQuery != INVALID_SHADERAPI_OCCLUSION_QUERY_HANDLE && m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] )
  204. {
  205. int nPixels = g_pShaderAPI->OcclusionQuery_GetNumPixelsRendered( hQuery );
  206. if ( nPixels == OCCLUSION_QUERY_RESULT_ERROR )
  207. {
  208. // 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.
  209. m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] = false;
  210. }
  211. else if ( nPixels >= 0 )
  212. {
  213. m_OcclusionQueryObjects[h].m_LastResult = nPixels;
  214. m_OcclusionQueryObjects[h].m_bHasBeenIssued[nIndex] = false;
  215. }
  216. }
  217. }
  218. }
  219. }
  220. int COcclusionQueryMgr::OcclusionQuery_GetNumPixelsRendered( OcclusionQueryObjectHandle_t h, bool bDoQuery )
  221. {
  222. if ( bDoQuery )
  223. {
  224. OcclusionQuery_IssueNumPixelsRenderedQuery( h );
  225. }
  226. int nPixels = m_OcclusionQueryObjects[(intp)h].m_LastResult;
  227. return nPixels;
  228. }