D3DPerfQuery.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2012 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoBackends/D3D/D3DPerfQuery.h"
  4. #include "Common/CommonTypes.h"
  5. #include "Common/Logging/Log.h"
  6. #include "VideoBackends/D3D/D3DBase.h"
  7. #include "VideoCommon/FramebufferManager.h"
  8. #include "VideoCommon/VideoCommon.h"
  9. #include "VideoCommon/VideoConfig.h"
  10. namespace DX11
  11. {
  12. PerfQuery::PerfQuery() : m_query_read_pos()
  13. {
  14. for (ActiveQuery& entry : m_query_buffer)
  15. {
  16. D3D11_QUERY_DESC qdesc = CD3D11_QUERY_DESC(D3D11_QUERY_OCCLUSION, 0);
  17. D3D::device->CreateQuery(&qdesc, &entry.query);
  18. }
  19. ResetQuery();
  20. }
  21. PerfQuery::~PerfQuery() = default;
  22. void PerfQuery::EnableQuery(PerfQueryGroup group)
  23. {
  24. u32 query_count = m_query_count.load(std::memory_order_relaxed);
  25. // Is this sane?
  26. if (query_count > m_query_buffer.size() / 2)
  27. {
  28. WeakFlush();
  29. query_count = m_query_count.load(std::memory_order_relaxed);
  30. }
  31. if (m_query_buffer.size() == query_count)
  32. {
  33. // TODO
  34. FlushOne();
  35. query_count = m_query_count.load(std::memory_order_relaxed);
  36. ERROR_LOG_FMT(VIDEO, "Flushed query buffer early!");
  37. }
  38. // start query
  39. if (group == PQG_ZCOMP_ZCOMPLOC || group == PQG_ZCOMP)
  40. {
  41. auto& entry = m_query_buffer[(m_query_read_pos + query_count) % m_query_buffer.size()];
  42. D3D::context->Begin(entry.query.Get());
  43. entry.query_group = group;
  44. m_query_count.fetch_add(1, std::memory_order_relaxed);
  45. }
  46. }
  47. void PerfQuery::DisableQuery(PerfQueryGroup group)
  48. {
  49. // stop query
  50. if (group == PQG_ZCOMP_ZCOMPLOC || group == PQG_ZCOMP)
  51. {
  52. auto& entry = m_query_buffer[(m_query_read_pos + m_query_count.load(std::memory_order_relaxed) +
  53. m_query_buffer.size() - 1) %
  54. m_query_buffer.size()];
  55. D3D::context->End(entry.query.Get());
  56. }
  57. }
  58. void PerfQuery::ResetQuery()
  59. {
  60. m_query_count.store(0, std::memory_order_relaxed);
  61. for (size_t i = 0; i < m_results.size(); ++i)
  62. m_results[i].store(0, std::memory_order_relaxed);
  63. }
  64. u32 PerfQuery::GetQueryResult(PerfQueryType type)
  65. {
  66. u32 result = 0;
  67. if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
  68. {
  69. result = m_results[PQG_ZCOMP_ZCOMPLOC].load(std::memory_order_relaxed);
  70. }
  71. else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
  72. {
  73. result = m_results[PQG_ZCOMP].load(std::memory_order_relaxed);
  74. }
  75. else if (type == PQ_BLEND_INPUT)
  76. {
  77. result = m_results[PQG_ZCOMP].load(std::memory_order_relaxed) +
  78. m_results[PQG_ZCOMP_ZCOMPLOC].load(std::memory_order_relaxed);
  79. }
  80. else if (type == PQ_EFB_COPY_CLOCKS)
  81. {
  82. result = m_results[PQG_EFB_COPY_CLOCKS].load(std::memory_order_relaxed);
  83. }
  84. return result / 4;
  85. }
  86. void PerfQuery::FlushOne()
  87. {
  88. auto& entry = m_query_buffer[m_query_read_pos];
  89. UINT64 result = 0;
  90. HRESULT hr = S_FALSE;
  91. while (hr != S_OK)
  92. {
  93. // TODO: Might cause us to be stuck in an infinite loop!
  94. hr = D3D::context->GetData(entry.query.Get(), &result, sizeof(result), 0);
  95. }
  96. // NOTE: Reported pixel metrics should be referenced to native resolution
  97. // TODO: Dropping the lower 2 bits from this count should be closer to actual
  98. // hardware behavior when drawing triangles.
  99. u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
  100. g_framebuffer_manager->GetEFBHeight();
  101. if (g_ActiveConfig.iMultisamples > 1)
  102. native_res_result /= g_ActiveConfig.iMultisamples;
  103. m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
  104. std::memory_order_relaxed);
  105. m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
  106. m_query_count.fetch_sub(1, std::memory_order_relaxed);
  107. }
  108. // TODO: could selectively flush things, but I don't think that will do much
  109. void PerfQuery::FlushResults()
  110. {
  111. while (!IsFlushed())
  112. FlushOne();
  113. }
  114. void PerfQuery::WeakFlush()
  115. {
  116. while (!IsFlushed())
  117. {
  118. auto& entry = m_query_buffer[m_query_read_pos];
  119. UINT64 result = 0;
  120. HRESULT hr = D3D::context->GetData(entry.query.Get(), &result, sizeof(result),
  121. D3D11_ASYNC_GETDATA_DONOTFLUSH);
  122. if (hr == S_OK)
  123. {
  124. // NOTE: Reported pixel metrics should be referenced to native resolution
  125. const u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() *
  126. EFB_HEIGHT / g_framebuffer_manager->GetEFBHeight();
  127. m_results[entry.query_group].store(static_cast<u32>(native_res_result),
  128. std::memory_order_relaxed);
  129. m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
  130. m_query_count.fetch_sub(1, std::memory_order_relaxed);
  131. }
  132. else
  133. {
  134. break;
  135. }
  136. }
  137. }
  138. bool PerfQuery::IsFlushed() const
  139. {
  140. return m_query_count.load(std::memory_order_relaxed) == 0;
  141. }
  142. } // namespace DX11