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

  1. //============ Copyright (c) Valve Corporation, All rights reserved. ============
  2. //
  3. // cglmquery.cpp
  4. //
  5. //===============================================================================
  6. #include "glmgr/glmgr.h"
  7. #include "glmgr/cglmquery.h"
  8. #include "../shaderapidx9/dxabstract.h"
  9. #include <unistd.h>
  10. // memdbgon -must- be the last include file in a .cpp file.
  11. #include "tier0/memdbgon.h"
  12. //===============================================================================
  13. extern ConVar gl_errorcheckall;
  14. extern ConVar gl_errorcheckqueries;
  15. extern ConVar gl_errorchecknone;
  16. // how many microseconds to wait after a failed query-available test
  17. // presently on MTGL this doesn't happen, but it could change, keep this handy
  18. ConVar gl_nullqueries( "gl_nullqueries", "0" );
  19. GLenum GetQueryError( void )
  20. {
  21. if ( ( GLMDEBUG || (gl_errorcheckall.GetInt() != 0) || (gl_errorcheckqueries.GetInt() != 0) ) && (gl_errorchecknone.GetInt() == 0) )
  22. {
  23. return glGetError();
  24. }
  25. else
  26. {
  27. return (GLenum) 0; // whistle past graveyard
  28. }
  29. }
  30. //===============================================================================
  31. CGLMQuery::CGLMQuery( GLMContext *ctx, GLMQueryParams *params )
  32. {
  33. // make sure context is current
  34. // get the type of query requested
  35. // generate name(s) needed
  36. // set initial state appropriately
  37. ctx->MakeCurrent();
  38. m_ctx = ctx;
  39. m_params = *params;
  40. m_name = 0;
  41. m_started = m_stopped = m_done = false;
  42. m_nullQuery = false;
  43. // assume value of convar at start time
  44. // does not change during individual query lifetime
  45. // started null = stays null
  46. // started live = stays live
  47. switch(m_params.m_type)
  48. {
  49. case EOcclusion:
  50. {
  51. //make an occlusion query (and a fence to go with it)
  52. glGenQueriesARB( 1, &m_name );
  53. GLMPRINTF(("-A- CGLMQuery(OQ) created name %d", m_name));
  54. GLenum errorcode = GetQueryError();
  55. if (errorcode)
  56. {
  57. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  58. printf( "\nCGLMQuery::CGLMQuery (OQ) saw %s error (%d) from glGenQueriesARB", decodedStr, errorcode );
  59. m_name = 0;
  60. }
  61. }
  62. break;
  63. case EFence:
  64. //make a fence - no aux fence needed
  65. glGenFencesAPPLE(1, &m_name );
  66. GLMPRINTF(("-A- CGLMQuery(fence) created name %d", m_name));
  67. GLenum errorcode = GetQueryError();
  68. if (errorcode)
  69. {
  70. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  71. printf( "\nCGLMQuery::CGLMQuery (fence) saw %s error (%d) from glGenFencesAPPLE", decodedStr, errorcode );
  72. m_name = 0;
  73. }
  74. break;
  75. }
  76. }
  77. CGLMQuery::~CGLMQuery()
  78. {
  79. GLMPRINTF(("-A-> ~CGLMQuery"));
  80. // make sure query has completed (might not be necessary)
  81. // delete the name(s)
  82. m_ctx->MakeCurrent();
  83. switch(m_params.m_type)
  84. {
  85. case EOcclusion:
  86. {
  87. // do a finish occlusion query ?
  88. GLMPRINTF(("-A- ~CGLMQuery(OQ) deleting name %d", m_name));
  89. glDeleteQueries(1, &m_name );
  90. GLenum errorcode = GetQueryError();
  91. if (errorcode)
  92. {
  93. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  94. printf( "\nCGLMQuery::~CGLMQuery (OQ) saw %s error (%d) from glDeleteQueries", decodedStr, errorcode );
  95. }
  96. }
  97. break;
  98. case EFence:
  99. {
  100. // do a finish fence ?
  101. GLMPRINTF(("-A- ~CGLMQuery(fence) deleting name %d", m_name));
  102. glDeleteFencesAPPLE(1, &m_name );
  103. GLenum errorcode = GetQueryError();
  104. if (errorcode)
  105. {
  106. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  107. printf( "\nCGLMQuery::~CGLMQuery (fence) saw %s error (%d) from glDeleteFencesAPPLE", decodedStr, errorcode );
  108. }
  109. }
  110. break;
  111. }
  112. m_name = 0;
  113. GLMPRINTF(("-A-< ~CGLMQuery"));
  114. }
  115. void CGLMQuery::Start( void ) // "start counting"
  116. {
  117. m_ctx->MakeCurrent();
  118. // on occlusion query:
  119. // glBeginQueryARB on the OQ name. counting starts.
  120. // on fence: glSetFence on m_name.
  121. // note, fences finish themselves via command progress - OQ's do not.
  122. Assert(!m_started);
  123. Assert(!m_stopped);
  124. Assert(!m_done);
  125. m_nullQuery = (gl_nullqueries.GetInt() != 0); // latch value for remainder of query life
  126. switch(m_params.m_type)
  127. {
  128. case EOcclusion:
  129. {
  130. if (m_nullQuery)
  131. {
  132. // do nothing..
  133. }
  134. else
  135. {
  136. glBeginQueryARB( GL_SAMPLES_PASSED_ARB, m_name );
  137. GLenum errorcode = GetQueryError();
  138. if (errorcode)
  139. {
  140. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  141. printf( "\nCGLMQuery::Start(OQ) saw %s error (%d) from glBeginQueryARB (GL_SAMPLES_PASSED_ARB) name=%d", decodedStr, errorcode, m_name );
  142. }
  143. }
  144. }
  145. break;
  146. case EFence:
  147. glSetFenceAPPLE( m_name );
  148. GLenum errorcode = GetQueryError();
  149. if (errorcode)
  150. {
  151. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  152. printf( "\nCGLMQuery::Start(fence) saw %s error (%d) from glSetFenceAPPLE name=%d", decodedStr, errorcode, m_name );
  153. }
  154. m_stopped = true; // caller should not call Stop on a fence, it self-stops
  155. break;
  156. }
  157. m_started = true;
  158. }
  159. void CGLMQuery::Stop( void ) // "stop counting"
  160. {
  161. m_ctx->MakeCurrent();
  162. Assert(m_started);
  163. Assert(!m_stopped); // this will assert if you try to call Stop on a fence that is started
  164. Assert(!m_done);
  165. switch(m_params.m_type)
  166. {
  167. case EOcclusion:
  168. {
  169. if (m_nullQuery)
  170. {
  171. // do nothing..
  172. }
  173. else
  174. {
  175. glEndQueryARB( GL_SAMPLES_PASSED_ARB ); // we are only putting the request-to-stop-counting into the cmd stream.
  176. GLenum errorcode = GetQueryError();
  177. if (errorcode)
  178. {
  179. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  180. printf( "\nCGLMQuery::Stop(OQ) saw %s error (%d) from glEndQueryARB( GL_SAMPLES_PASSED_ARB ) name=%d", decodedStr, errorcode, m_name );
  181. }
  182. }
  183. }
  184. break;
  185. case EFence:
  186. // nop - you don't "end" a fence, you just test it and/or finish it out in Complete
  187. break;
  188. }
  189. m_stopped = true;
  190. }
  191. bool CGLMQuery::IsDone( void )
  192. {
  193. m_ctx->MakeCurrent();
  194. Assert(m_started);
  195. Assert(m_stopped);
  196. if(!m_done) // you can ask more than once, but we only check until it comes back as done.
  197. {
  198. // on occlusion: glGetQueryObjectivARB - large cost on pre SLGU, cheap after
  199. // on fence: glTestFenceAPPLE on the fence
  200. switch(m_params.m_type)
  201. {
  202. case EOcclusion: // just test the fence that was set after the query begin
  203. {
  204. if (m_nullQuery)
  205. {
  206. // do almost nothing.. but claim work is complete
  207. m_done = true;
  208. }
  209. else
  210. {
  211. // prepare to pay a big price on drivers prior to 10.6.4+SLGU
  212. GLint available = 0;
  213. glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
  214. GLenum errorcode = GetQueryError();
  215. if (errorcode)
  216. {
  217. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  218. printf( "\nCGLMQuery::IsDone saw %s error (%d) from glGetQueryObjectivARB(a2) name=%d", decodedStr, errorcode, m_name );
  219. }
  220. m_done = (available != 0);
  221. }
  222. }
  223. break;
  224. case EFence:
  225. {
  226. m_done = glTestFenceAPPLE( m_name );
  227. GLenum errorcode = GetQueryError();
  228. if (errorcode)
  229. {
  230. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  231. printf( "\nCGLMQuery::IsDone saw %s error (%d) from glTestFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
  232. }
  233. if (m_done)
  234. {
  235. glFinishFenceAPPLE( m_name ); // no set fence goes un-finished
  236. errorcode = GetQueryError();
  237. if (errorcode)
  238. {
  239. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  240. printf( "\nCGLMQuery::IsDone saw %s error (%d) from glFinishFenceAPPLE(b) name=%d", decodedStr, errorcode, m_name );
  241. }
  242. }
  243. }
  244. break;
  245. }
  246. }
  247. return m_done;
  248. }
  249. void CGLMQuery::Complete( uint *result )
  250. {
  251. m_ctx->MakeCurrent();
  252. uint resultval = 0;
  253. GLint available = 0;
  254. bool bogus_available = false;
  255. // blocking call if not done
  256. Assert(m_started);
  257. Assert(m_stopped);
  258. switch(m_params.m_type)
  259. {
  260. case EOcclusion:
  261. {
  262. if (m_nullQuery)
  263. {
  264. m_done = true;
  265. resultval = 0; // we did say "null queries..."
  266. }
  267. else
  268. {
  269. // accept that the query is going to drain pipe in 10.6.4 and prior.
  270. // check the error on the spot.
  271. glGetQueryObjectivARB(m_name, GL_QUERY_RESULT_AVAILABLE_ARB, &available );
  272. GLenum errorcode = GetQueryError();
  273. if (errorcode)
  274. {
  275. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  276. printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_AVAILABLE_ARB name=%d", decodedStr, errorcode, m_name );
  277. resultval=0;
  278. }
  279. else
  280. {
  281. if (!available)
  282. {
  283. // this does happen with some very modest frequency.
  284. if (!m_ctx->Caps().m_hasPerfPackage1)
  285. {
  286. glFlush(); // ISTR some deadlock cases on pre-SLGU drivers if you didn't do this to kick the queue along..
  287. }
  288. }
  289. glGetQueryObjectuivARB( m_name, GL_QUERY_RESULT_ARB, &resultval);
  290. GLenum errorcode = GetQueryError();
  291. if (errorcode)
  292. {
  293. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  294. printf( "\nCGLMQuery::Complete saw %s error (%d) from glGetQueryObjectivARB GL_QUERY_RESULT_ARB name=%d", decodedStr, errorcode, m_name );
  295. resultval=0;
  296. }
  297. else
  298. {
  299. // resultval is legit
  300. }
  301. }
  302. m_done = true;
  303. }
  304. }
  305. break;
  306. case EFence:
  307. {
  308. if(!m_done)
  309. {
  310. glFinishFenceAPPLE( m_name );
  311. GLenum errorcode = GetQueryError();
  312. if (errorcode)
  313. {
  314. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  315. printf( "\nCGLMQuery::Complete saw %s error (%d) from glFinishFenceAPPLE (EFence) name=%d", decodedStr, errorcode, m_name );
  316. }
  317. m_done = true; // for clarity or if they try to Complete twice
  318. }
  319. }
  320. break;
  321. }
  322. Assert( m_done );
  323. // reset state for re-use - i.e. you have to call Complete if you want to re-use the object
  324. m_started = m_stopped = m_done = false;
  325. if (result) // caller may pass NULL if not interested in result, for example to clear a fence
  326. {
  327. *result = resultval;
  328. }
  329. }
  330. // accessors for the started/stopped state
  331. bool CGLMQuery::IsStarted ( void )
  332. {
  333. return m_started;
  334. }
  335. bool CGLMQuery::IsStopped ( void )
  336. {
  337. return m_stopped;
  338. }