PerfQuery.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2012 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include "VideoBackends/OGL/GLInterfaceBase.h"
  5. #include "VideoBackends/OGL/GLUtil.h"
  6. #include "VideoBackends/OGL/PerfQuery.h"
  7. #include "VideoCommon/RenderBase.h"
  8. namespace OGL
  9. {
  10. PerfQueryBase* GetPerfQuery()
  11. {
  12. if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 &&
  13. GLExtensions::Supports("GL_NV_occlusion_query_samples"))
  14. return new PerfQueryGLESNV();
  15. else if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
  16. return new PerfQueryGL(GL_ANY_SAMPLES_PASSED);
  17. else
  18. return new PerfQueryGL(GL_SAMPLES_PASSED);
  19. }
  20. PerfQuery::PerfQuery()
  21. : m_query_read_pos()
  22. {
  23. ResetQuery();
  24. }
  25. void PerfQuery::EnableQuery(PerfQueryGroup type)
  26. {
  27. m_query->EnableQuery(type);
  28. }
  29. void PerfQuery::DisableQuery(PerfQueryGroup type)
  30. {
  31. m_query->DisableQuery(type);
  32. }
  33. bool PerfQuery::IsFlushed() const
  34. {
  35. return 0 == m_query_count;
  36. }
  37. // TODO: could selectively flush things, but I don't think that will do much
  38. void PerfQuery::FlushResults()
  39. {
  40. m_query->FlushResults();
  41. }
  42. void PerfQuery::ResetQuery()
  43. {
  44. m_query_count = 0;
  45. std::fill_n(m_results, ArraySize(m_results), 0);
  46. }
  47. u32 PerfQuery::GetQueryResult(PerfQueryType type)
  48. {
  49. u32 result = 0;
  50. if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
  51. {
  52. result = m_results[PQG_ZCOMP_ZCOMPLOC];
  53. }
  54. else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
  55. {
  56. result = m_results[PQG_ZCOMP];
  57. }
  58. else if (type == PQ_BLEND_INPUT)
  59. {
  60. result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
  61. }
  62. else if (type == PQ_EFB_COPY_CLOCKS)
  63. {
  64. result = m_results[PQG_EFB_COPY_CLOCKS];
  65. }
  66. return result / 4;
  67. }
  68. // Implementations
  69. PerfQueryGL::PerfQueryGL(GLenum query_type)
  70. : m_query_type(query_type)
  71. {
  72. for (ActiveQuery& query : m_query_buffer)
  73. glGenQueries(1, &query.query_id);
  74. }
  75. PerfQueryGL::~PerfQueryGL()
  76. {
  77. for (ActiveQuery& query : m_query_buffer)
  78. glDeleteQueries(1, &query.query_id);
  79. }
  80. void PerfQueryGL::EnableQuery(PerfQueryGroup type)
  81. {
  82. // Is this sane?
  83. if (m_query_count > m_query_buffer.size() / 2)
  84. WeakFlush();
  85. if (m_query_buffer.size() == m_query_count)
  86. {
  87. FlushOne();
  88. //ERROR_LOG(VIDEO, "Flushed query buffer early!");
  89. }
  90. // start query
  91. if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
  92. {
  93. auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];
  94. glBeginQuery(m_query_type, entry.query_id);
  95. entry.query_type = type;
  96. ++m_query_count;
  97. }
  98. }
  99. void PerfQueryGL::DisableQuery(PerfQueryGroup type)
  100. {
  101. // stop query
  102. if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
  103. {
  104. glEndQuery(m_query_type);
  105. }
  106. }
  107. void PerfQueryGL::WeakFlush()
  108. {
  109. while (!IsFlushed())
  110. {
  111. auto& entry = m_query_buffer[m_query_read_pos];
  112. GLuint result = GL_FALSE;
  113. glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT_AVAILABLE, &result);
  114. if (GL_TRUE == result)
  115. {
  116. FlushOne();
  117. }
  118. else
  119. {
  120. break;
  121. }
  122. }
  123. }
  124. void PerfQueryGL::FlushOne()
  125. {
  126. auto& entry = m_query_buffer[m_query_read_pos];
  127. GLuint result = 0;
  128. glGetQueryObjectuiv(entry.query_id, GL_QUERY_RESULT, &result);
  129. // NOTE: Reported pixel metrics should be referenced to native resolution
  130. m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
  131. m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
  132. --m_query_count;
  133. }
  134. // TODO: could selectively flush things, but I don't think that will do much
  135. void PerfQueryGL::FlushResults()
  136. {
  137. while (!IsFlushed())
  138. FlushOne();
  139. }
  140. PerfQueryGLESNV::PerfQueryGLESNV()
  141. {
  142. for (ActiveQuery& query : m_query_buffer)
  143. glGenOcclusionQueriesNV(1, &query.query_id);
  144. }
  145. PerfQueryGLESNV::~PerfQueryGLESNV()
  146. {
  147. for (ActiveQuery& query : m_query_buffer)
  148. glDeleteOcclusionQueriesNV(1, &query.query_id);
  149. }
  150. void PerfQueryGLESNV::EnableQuery(PerfQueryGroup type)
  151. {
  152. // Is this sane?
  153. if (m_query_count > m_query_buffer.size() / 2)
  154. WeakFlush();
  155. if (m_query_buffer.size() == m_query_count)
  156. {
  157. FlushOne();
  158. //ERROR_LOG(VIDEO, "Flushed query buffer early!");
  159. }
  160. // start query
  161. if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
  162. {
  163. auto& entry = m_query_buffer[(m_query_read_pos + m_query_count) % m_query_buffer.size()];
  164. glBeginOcclusionQueryNV(entry.query_id);
  165. entry.query_type = type;
  166. ++m_query_count;
  167. }
  168. }
  169. void PerfQueryGLESNV::DisableQuery(PerfQueryGroup type)
  170. {
  171. // stop query
  172. if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
  173. {
  174. glEndOcclusionQueryNV();
  175. }
  176. }
  177. void PerfQueryGLESNV::WeakFlush()
  178. {
  179. while (!IsFlushed())
  180. {
  181. auto& entry = m_query_buffer[m_query_read_pos];
  182. GLuint result = GL_FALSE;
  183. glGetOcclusionQueryuivNV(entry.query_id, GL_PIXEL_COUNT_AVAILABLE_NV, &result);
  184. if (GL_TRUE == result)
  185. {
  186. FlushOne();
  187. }
  188. else
  189. {
  190. break;
  191. }
  192. }
  193. }
  194. void PerfQueryGLESNV::FlushOne()
  195. {
  196. auto& entry = m_query_buffer[m_query_read_pos];
  197. GLuint result = 0;
  198. glGetOcclusionQueryuivNV(entry.query_id, GL_OCCLUSION_TEST_RESULT_HP, &result);
  199. // NOTE: Reported pixel metrics should be referenced to native resolution
  200. m_results[entry.query_type] += (u64)result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight();
  201. m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
  202. --m_query_count;
  203. }
  204. // TODO: could selectively flush things, but I don't think that will do much
  205. void PerfQueryGLESNV::FlushResults()
  206. {
  207. while (!IsFlushed())
  208. FlushOne();
  209. }
  210. } // namespace