diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 41 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 4 | ||||
| -rw-r--r-- | src/video_core/rasterizer_interface.h | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_query_cache.cpp | 201 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_query_cache.h | 123 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 30 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 10 |
7 files changed, 328 insertions, 86 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index fe91ff6a0..9add2bc94 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -556,23 +556,13 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 556 | // matches the current payload. | 556 | // matches the current payload. |
| 557 | UNIMPLEMENTED_MSG("Unimplemented query operation ACQUIRE"); | 557 | UNIMPLEMENTED_MSG("Unimplemented query operation ACQUIRE"); |
| 558 | break; | 558 | break; |
| 559 | case Regs::QueryOperation::Counter: { | 559 | case Regs::QueryOperation::Counter: |
| 560 | u64 result; | 560 | if (const std::optional<u64> result = GetQueryResult()) { |
| 561 | switch (regs.query.query_get.select) { | 561 | // If the query returns an empty optional it means it's cached and deferred. |
| 562 | case Regs::QuerySelect::Zero: | 562 | // In this case we have a non-empty result, so we stamp it immediately. |
| 563 | result = 0; | 563 | StampQueryResult(*result, regs.query.query_get.short_query == 0); |
| 564 | break; | ||
| 565 | case Regs::QuerySelect::SamplesPassed: | ||
| 566 | result = rasterizer.Query(VideoCore::QueryType::SamplesPassed); | ||
| 567 | break; | ||
| 568 | default: | ||
| 569 | result = 1; | ||
| 570 | UNIMPLEMENTED_MSG("Unimplemented query select type {}", | ||
| 571 | static_cast<u32>(regs.query.query_get.select.Value())); | ||
| 572 | } | 564 | } |
| 573 | StampQueryResult(result, regs.query.query_get.short_query == 0); | ||
| 574 | break; | 565 | break; |
| 575 | } | ||
| 576 | case Regs::QueryOperation::Trap: | 566 | case Regs::QueryOperation::Trap: |
| 577 | UNIMPLEMENTED_MSG("Unimplemented query operation TRAP"); | 567 | UNIMPLEMENTED_MSG("Unimplemented query operation TRAP"); |
| 578 | break; | 568 | break; |
| @@ -595,20 +585,20 @@ void Maxwell3D::ProcessQueryCondition() { | |||
| 595 | } | 585 | } |
| 596 | case Regs::ConditionMode::ResNonZero: { | 586 | case Regs::ConditionMode::ResNonZero: { |
| 597 | Regs::QueryCompare cmp; | 587 | Regs::QueryCompare cmp; |
| 598 | memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); | 588 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); |
| 599 | execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; | 589 | execute_on = cmp.initial_sequence != 0U && cmp.initial_mode != 0U; |
| 600 | break; | 590 | break; |
| 601 | } | 591 | } |
| 602 | case Regs::ConditionMode::Equal: { | 592 | case Regs::ConditionMode::Equal: { |
| 603 | Regs::QueryCompare cmp; | 593 | Regs::QueryCompare cmp; |
| 604 | memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); | 594 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); |
| 605 | execute_on = | 595 | execute_on = |
| 606 | cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode; | 596 | cmp.initial_sequence == cmp.current_sequence && cmp.initial_mode == cmp.current_mode; |
| 607 | break; | 597 | break; |
| 608 | } | 598 | } |
| 609 | case Regs::ConditionMode::NotEqual: { | 599 | case Regs::ConditionMode::NotEqual: { |
| 610 | Regs::QueryCompare cmp; | 600 | Regs::QueryCompare cmp; |
| 611 | memory_manager.ReadBlockUnsafe(condition_address, &cmp, sizeof(cmp)); | 601 | memory_manager.ReadBlock(condition_address, &cmp, sizeof(cmp)); |
| 612 | execute_on = | 602 | execute_on = |
| 613 | cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode; | 603 | cmp.initial_sequence != cmp.current_sequence || cmp.initial_mode != cmp.current_mode; |
| 614 | break; | 604 | break; |
| @@ -674,6 +664,21 @@ void Maxwell3D::DrawArrays() { | |||
| 674 | } | 664 | } |
| 675 | } | 665 | } |
| 676 | 666 | ||
| 667 | std::optional<u64> Maxwell3D::GetQueryResult() { | ||
| 668 | switch (regs.query.query_get.select) { | ||
| 669 | case Regs::QuerySelect::Zero: | ||
| 670 | return 0; | ||
| 671 | case Regs::QuerySelect::SamplesPassed: | ||
| 672 | // Deferred. | ||
| 673 | rasterizer.Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed); | ||
| 674 | return {}; | ||
| 675 | default: | ||
| 676 | UNIMPLEMENTED_MSG("Unimplemented query select type {}", | ||
| 677 | static_cast<u32>(regs.query.query_get.select.Value())); | ||
| 678 | return 1; | ||
| 679 | } | ||
| 680 | } | ||
| 681 | |||
| 677 | void Maxwell3D::ProcessCBBind(std::size_t stage_index) { | 682 | void Maxwell3D::ProcessCBBind(std::size_t stage_index) { |
| 678 | // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. | 683 | // Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage. |
| 679 | auto& shader = state.shader_stages[stage_index]; | 684 | auto& shader = state.shader_stages[stage_index]; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index d21f678ed..26939be3f 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <bitset> | 8 | #include <bitset> |
| 9 | #include <optional> | ||
| 9 | #include <type_traits> | 10 | #include <type_traits> |
| 10 | #include <unordered_map> | 11 | #include <unordered_map> |
| 11 | #include <vector> | 12 | #include <vector> |
| @@ -1462,6 +1463,9 @@ private: | |||
| 1462 | 1463 | ||
| 1463 | // Handles a instance drawcall from MME | 1464 | // Handles a instance drawcall from MME |
| 1464 | void StepInstance(MMEDrawMode expected_mode, u32 count); | 1465 | void StepInstance(MMEDrawMode expected_mode, u32 count); |
| 1466 | |||
| 1467 | /// Returns a query's value or an empty object if the value will be deferred through a cache. | ||
| 1468 | std::optional<u64> GetQueryResult(); | ||
| 1465 | }; | 1469 | }; |
| 1466 | 1470 | ||
| 1467 | #define ASSERT_REG_POSITION(field_name, position) \ | 1471 | #define ASSERT_REG_POSITION(field_name, position) \ |
diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 2fc627539..a394f2d3e 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -20,6 +20,7 @@ namespace VideoCore { | |||
| 20 | enum class QueryType { | 20 | enum class QueryType { |
| 21 | SamplesPassed, | 21 | SamplesPassed, |
| 22 | }; | 22 | }; |
| 23 | constexpr std::size_t NumQueryTypes = 1; | ||
| 23 | 24 | ||
| 24 | enum class LoadCallbackStage { | 25 | enum class LoadCallbackStage { |
| 25 | Prepare, | 26 | Prepare, |
| @@ -48,8 +49,8 @@ public: | |||
| 48 | /// Resets the counter of a query | 49 | /// Resets the counter of a query |
| 49 | virtual void ResetCounter(QueryType type) = 0; | 50 | virtual void ResetCounter(QueryType type) = 0; |
| 50 | 51 | ||
| 51 | /// Returns the value of a GPU query | 52 | /// Records a GPU query and caches it |
| 52 | virtual u64 Query(QueryType type) = 0; | 53 | virtual void Query(GPUVAddr gpu_addr, QueryType type) = 0; |
| 53 | 54 | ||
| 54 | /// Notify rasterizer that all caches should be flushed to Switch memory | 55 | /// Notify rasterizer that all caches should be flushed to Switch memory |
| 55 | virtual void FlushAll() = 0; | 56 | virtual void FlushAll() = 0; |
diff --git a/src/video_core/renderer_opengl/gl_query_cache.cpp b/src/video_core/renderer_opengl/gl_query_cache.cpp index 1c7dc999a..8f0e8241d 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.cpp +++ b/src/video_core/renderer_opengl/gl_query_cache.cpp | |||
| @@ -2,58 +2,203 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 6 | #include <memory> | ||
| 7 | #include <utility> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 5 | #include <glad/glad.h> | 10 | #include <glad/glad.h> |
| 6 | 11 | ||
| 12 | #include "common/assert.h" | ||
| 13 | #include "core/core.h" | ||
| 14 | #include "video_core/engines/maxwell_3d.h" | ||
| 15 | #include "video_core/memory_manager.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_query_cache.h" | 16 | #include "video_core/renderer_opengl/gl_query_cache.h" |
| 17 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 8 | 18 | ||
| 9 | namespace OpenGL { | 19 | namespace OpenGL { |
| 10 | 20 | ||
| 11 | HostCounter::HostCounter(GLenum target) { | 21 | using VideoCore::QueryType; |
| 12 | query.Create(target); | 22 | |
| 23 | namespace { | ||
| 24 | |||
| 25 | constexpr std::array<GLenum, VideoCore::NumQueryTypes> QueryTargets = {GL_SAMPLES_PASSED}; | ||
| 26 | |||
| 27 | constexpr GLenum GetTarget(QueryType type) { | ||
| 28 | return QueryTargets[static_cast<std::size_t>(type)]; | ||
| 13 | } | 29 | } |
| 14 | 30 | ||
| 15 | HostCounter::~HostCounter() = default; | 31 | } // Anonymous namespace |
| 32 | |||
| 33 | CounterStream::CounterStream(QueryCache& cache, QueryType type) | ||
| 34 | : cache{cache}, type{type}, target{GetTarget(type)} {} | ||
| 16 | 35 | ||
| 17 | void HostCounter::UpdateState(bool enabled) { | 36 | CounterStream::~CounterStream() = default; |
| 37 | |||
| 38 | void CounterStream::Update(bool enabled, bool any_command_queued) { | ||
| 18 | if (enabled) { | 39 | if (enabled) { |
| 19 | Enable(); | 40 | if (!current) { |
| 20 | } else { | 41 | current = cache.GetHostCounter(last, type); |
| 21 | Disable(); | 42 | } |
| 43 | return; | ||
| 22 | } | 44 | } |
| 45 | |||
| 46 | if (current) { | ||
| 47 | EndQuery(any_command_queued); | ||
| 48 | } | ||
| 49 | last = std::exchange(current, nullptr); | ||
| 23 | } | 50 | } |
| 24 | 51 | ||
| 25 | void HostCounter::Reset() { | 52 | void CounterStream::Reset(bool any_command_queued) { |
| 26 | counter = 0; | 53 | if (current) { |
| 27 | Disable(); | 54 | EndQuery(any_command_queued); |
| 55 | } | ||
| 56 | current = nullptr; | ||
| 57 | last = nullptr; | ||
| 28 | } | 58 | } |
| 29 | 59 | ||
| 30 | u64 HostCounter::Query() { | 60 | std::shared_ptr<HostCounter> CounterStream::GetCurrent(bool any_command_queued) { |
| 31 | if (!is_beginned) { | 61 | if (!current) { |
| 32 | return counter; | 62 | return nullptr; |
| 63 | } | ||
| 64 | EndQuery(any_command_queued); | ||
| 65 | last = std::move(current); | ||
| 66 | current = cache.GetHostCounter(last, type); | ||
| 67 | return last; | ||
| 68 | } | ||
| 69 | |||
| 70 | void CounterStream::EndQuery(bool any_command_queued) { | ||
| 71 | if (!any_command_queued) { | ||
| 72 | // There are chances a query waited on without commands (glDraw, glClear, glDispatch). Not | ||
| 73 | // having any of these causes a lock. glFlush is considered a command, so we can safely wait | ||
| 74 | // for this. Insert to the OpenGL command stream a flush. | ||
| 75 | glFlush(); | ||
| 76 | } | ||
| 77 | glEndQuery(target); | ||
| 78 | } | ||
| 79 | |||
| 80 | QueryCache::QueryCache(Core::System& system, RasterizerOpenGL& rasterizer) | ||
| 81 | : RasterizerCache{rasterizer}, system{system}, | ||
| 82 | rasterizer{rasterizer}, streams{{CounterStream{*this, QueryType::SamplesPassed}}} {} | ||
| 83 | |||
| 84 | QueryCache::~QueryCache() = default; | ||
| 85 | |||
| 86 | void QueryCache::Query(GPUVAddr gpu_addr, QueryType type) { | ||
| 87 | auto& memory_manager = system.GPU().MemoryManager(); | ||
| 88 | const auto host_ptr = memory_manager.GetPointer(gpu_addr); | ||
| 89 | |||
| 90 | auto query = TryGet(host_ptr); | ||
| 91 | if (!query) { | ||
| 92 | const auto cpu_addr = memory_manager.GpuToCpuAddress(gpu_addr); | ||
| 93 | ASSERT_OR_EXECUTE(cpu_addr, return;); | ||
| 94 | |||
| 95 | query = std::make_shared<CachedQuery>(type, *cpu_addr, host_ptr); | ||
| 96 | Register(query); | ||
| 97 | } | ||
| 98 | |||
| 99 | query->SetCounter(GetStream(type).GetCurrent(rasterizer.AnyCommandQueued())); | ||
| 100 | query->MarkAsModified(true, *this); | ||
| 101 | } | ||
| 102 | |||
| 103 | void QueryCache::UpdateCounters() { | ||
| 104 | auto& samples_passed = GetStream(QueryType::SamplesPassed); | ||
| 105 | |||
| 106 | const auto& regs = system.GPU().Maxwell3D().regs; | ||
| 107 | samples_passed.Update(regs.samplecnt_enable, rasterizer.AnyCommandQueued()); | ||
| 108 | } | ||
| 109 | |||
| 110 | void QueryCache::ResetCounter(QueryType type) { | ||
| 111 | GetStream(type).Reset(rasterizer.AnyCommandQueued()); | ||
| 112 | } | ||
| 113 | |||
| 114 | void QueryCache::Reserve(QueryType type, OGLQuery&& query) { | ||
| 115 | reserved_queries[static_cast<std::size_t>(type)].push_back(std::move(query)); | ||
| 116 | } | ||
| 117 | |||
| 118 | std::shared_ptr<HostCounter> QueryCache::GetHostCounter(std::shared_ptr<HostCounter> dependency, | ||
| 119 | QueryType type) { | ||
| 120 | const auto type_index = static_cast<std::size_t>(type); | ||
| 121 | auto& reserve = reserved_queries[type_index]; | ||
| 122 | |||
| 123 | if (reserve.empty()) { | ||
| 124 | return std::make_shared<HostCounter>(*this, std::move(dependency), type); | ||
| 33 | } | 125 | } |
| 34 | Disable(); | ||
| 35 | u64 value; | ||
| 36 | glGetQueryObjectui64v(query.handle, GL_QUERY_RESULT, &value); | ||
| 37 | Enable(); | ||
| 38 | 126 | ||
| 39 | counter += value; | 127 | auto counter = std::make_shared<HostCounter>(*this, std::move(dependency), type, |
| 128 | std::move(reserve.back())); | ||
| 129 | reserve.pop_back(); | ||
| 40 | return counter; | 130 | return counter; |
| 41 | } | 131 | } |
| 42 | 132 | ||
| 43 | void HostCounter::Enable() { | 133 | void QueryCache::FlushObjectInner(const std::shared_ptr<CachedQuery>& counter_) { |
| 44 | if (is_beginned) { | 134 | auto& counter = *counter_; |
| 45 | return; | 135 | auto& stream = GetStream(counter.GetType()); |
| 136 | |||
| 137 | // Waiting for a query while another query of the same target is enabled locks Nvidia's driver. | ||
| 138 | // To avoid this disable and re-enable keeping the dependency stream. | ||
| 139 | const bool is_enabled = stream.IsEnabled(); | ||
| 140 | if (is_enabled) { | ||
| 141 | stream.Update(false, false); | ||
| 142 | } | ||
| 143 | |||
| 144 | counter.Flush(); | ||
| 145 | |||
| 146 | if (is_enabled) { | ||
| 147 | stream.Update(true, false); | ||
| 46 | } | 148 | } |
| 47 | is_beginned = true; | ||
| 48 | glBeginQuery(GL_SAMPLES_PASSED, query.handle); | ||
| 49 | } | 149 | } |
| 50 | 150 | ||
| 51 | void HostCounter::Disable() { | 151 | CounterStream& QueryCache::GetStream(QueryType type) { |
| 52 | if (!is_beginned) { | 152 | return streams[static_cast<std::size_t>(type)]; |
| 53 | return; | 153 | } |
| 154 | |||
| 155 | HostCounter::HostCounter(QueryCache& cache, std::shared_ptr<HostCounter> dependency, QueryType type) | ||
| 156 | : cache{cache}, type{type}, dependency{std::move(dependency)} { | ||
| 157 | const GLenum target = GetTarget(type); | ||
| 158 | query.Create(target); | ||
| 159 | glBeginQuery(target, query.handle); | ||
| 160 | } | ||
| 161 | |||
| 162 | HostCounter::HostCounter(QueryCache& cache, std::shared_ptr<HostCounter> dependency, QueryType type, | ||
| 163 | OGLQuery&& query_) | ||
| 164 | : cache{cache}, type{type}, dependency{std::move(dependency)}, query{std::move(query_)} { | ||
| 165 | glBeginQuery(GetTarget(type), query.handle); | ||
| 166 | } | ||
| 167 | |||
| 168 | HostCounter::~HostCounter() { | ||
| 169 | cache.Reserve(type, std::move(query)); | ||
| 170 | } | ||
| 171 | |||
| 172 | u64 HostCounter::Query() { | ||
| 173 | if (query.handle == 0) { | ||
| 174 | return result; | ||
| 175 | } | ||
| 176 | |||
| 177 | glGetQueryObjectui64v(query.handle, GL_QUERY_RESULT, &result); | ||
| 178 | |||
| 179 | if (dependency) { | ||
| 180 | result += dependency->Query(); | ||
| 54 | } | 181 | } |
| 55 | glEndQuery(GL_SAMPLES_PASSED); | 182 | |
| 56 | is_beginned = false; | 183 | return result; |
| 184 | } | ||
| 185 | |||
| 186 | CachedQuery::CachedQuery(QueryType type, VAddr cpu_addr, u8* host_ptr) | ||
| 187 | : RasterizerCacheObject{host_ptr}, type{type}, cpu_addr{cpu_addr}, host_ptr{host_ptr} {} | ||
| 188 | |||
| 189 | CachedQuery::~CachedQuery() = default; | ||
| 190 | |||
| 191 | void CachedQuery::Flush() { | ||
| 192 | const u64 value = counter->Query(); | ||
| 193 | std::memcpy(host_ptr, &value, sizeof(value)); | ||
| 194 | } | ||
| 195 | |||
| 196 | void CachedQuery::SetCounter(std::shared_ptr<HostCounter> counter_) { | ||
| 197 | counter = std::move(counter_); | ||
| 198 | } | ||
| 199 | |||
| 200 | QueryType CachedQuery::GetType() const { | ||
| 201 | return type; | ||
| 57 | } | 202 | } |
| 58 | 203 | ||
| 59 | } // namespace OpenGL | 204 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_query_cache.h b/src/video_core/renderer_opengl/gl_query_cache.h index 52c6546bf..91594b120 100644 --- a/src/video_core/renderer_opengl/gl_query_cache.h +++ b/src/video_core/renderer_opengl/gl_query_cache.h | |||
| @@ -4,38 +4,131 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <memory> | ||
| 9 | #include <optional> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 7 | #include <glad/glad.h> | 12 | #include <glad/glad.h> |
| 8 | 13 | ||
| 9 | #include "common/common_types.h" | 14 | #include "common/common_types.h" |
| 15 | #include "video_core/rasterizer_cache.h" | ||
| 16 | #include "video_core/rasterizer_interface.h" | ||
| 10 | #include "video_core/renderer_opengl/gl_resource_manager.h" | 17 | #include "video_core/renderer_opengl/gl_resource_manager.h" |
| 11 | 18 | ||
| 19 | namespace Core { | ||
| 20 | class System; | ||
| 21 | } | ||
| 22 | |||
| 12 | namespace OpenGL { | 23 | namespace OpenGL { |
| 13 | 24 | ||
| 14 | class HostCounter final { | 25 | class CachedQuery; |
| 26 | class HostCounter; | ||
| 27 | class RasterizerOpenGL; | ||
| 28 | class QueryCache; | ||
| 29 | |||
| 30 | class CounterStream final { | ||
| 15 | public: | 31 | public: |
| 16 | explicit HostCounter(GLenum target); | 32 | explicit CounterStream(QueryCache& cache, VideoCore::QueryType type); |
| 17 | ~HostCounter(); | 33 | ~CounterStream(); |
| 34 | |||
| 35 | void Update(bool enabled, bool any_command_queued); | ||
| 36 | |||
| 37 | void Reset(bool any_command_queued); | ||
| 38 | |||
| 39 | std::shared_ptr<HostCounter> GetCurrent(bool any_command_queued); | ||
| 40 | |||
| 41 | bool IsEnabled() const { | ||
| 42 | return current != nullptr; | ||
| 43 | } | ||
| 44 | |||
| 45 | private: | ||
| 46 | void EndQuery(bool any_command_queued); | ||
| 47 | |||
| 48 | QueryCache& cache; | ||
| 49 | |||
| 50 | std::shared_ptr<HostCounter> current; | ||
| 51 | std::shared_ptr<HostCounter> last; | ||
| 52 | VideoCore::QueryType type; | ||
| 53 | GLenum target; | ||
| 54 | }; | ||
| 55 | |||
| 56 | class QueryCache final : public RasterizerCache<std::shared_ptr<CachedQuery>> { | ||
| 57 | public: | ||
| 58 | explicit QueryCache(Core::System& system, RasterizerOpenGL& rasterizer); | ||
| 59 | ~QueryCache(); | ||
| 60 | |||
| 61 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type); | ||
| 62 | |||
| 63 | void UpdateCounters(); | ||
| 64 | |||
| 65 | void ResetCounter(VideoCore::QueryType type); | ||
| 18 | 66 | ||
| 19 | /// Enables or disables the counter as required. | 67 | void Reserve(VideoCore::QueryType type, OGLQuery&& query); |
| 20 | void UpdateState(bool enabled); | ||
| 21 | 68 | ||
| 22 | /// Resets the counter disabling it if needed. | 69 | std::shared_ptr<HostCounter> GetHostCounter(std::shared_ptr<HostCounter> dependency, |
| 23 | void Reset(); | 70 | VideoCore::QueryType type); |
| 71 | |||
| 72 | protected: | ||
| 73 | void FlushObjectInner(const std::shared_ptr<CachedQuery>& counter) override; | ||
| 74 | |||
| 75 | private: | ||
| 76 | CounterStream& GetStream(VideoCore::QueryType type); | ||
| 77 | |||
| 78 | Core::System& system; | ||
| 79 | RasterizerOpenGL& rasterizer; | ||
| 80 | |||
| 81 | std::array<CounterStream, VideoCore::NumQueryTypes> streams; | ||
| 82 | std::array<std::vector<OGLQuery>, VideoCore::NumQueryTypes> reserved_queries; | ||
| 83 | }; | ||
| 84 | |||
| 85 | class HostCounter final { | ||
| 86 | public: | ||
| 87 | explicit HostCounter(QueryCache& cache, std::shared_ptr<HostCounter> dependency, | ||
| 88 | VideoCore::QueryType type); | ||
| 89 | explicit HostCounter(QueryCache& cache, std::shared_ptr<HostCounter> dependency, | ||
| 90 | VideoCore::QueryType type, OGLQuery&& query); | ||
| 91 | ~HostCounter(); | ||
| 24 | 92 | ||
| 25 | /// Returns the current value of the query. | 93 | /// Returns the current value of the query. |
| 26 | /// @note It may harm precision of future queries if the counter is not disabled. | ||
| 27 | u64 Query(); | 94 | u64 Query(); |
| 28 | 95 | ||
| 29 | private: | 96 | private: |
| 30 | /// Enables the counter when disabled. | 97 | QueryCache& cache; |
| 31 | void Enable(); | 98 | VideoCore::QueryType type; |
| 32 | 99 | ||
| 33 | /// Disables the counter when enabled. | 100 | std::shared_ptr<HostCounter> dependency; ///< Counter queued before this one. |
| 34 | void Disable(); | 101 | OGLQuery query; ///< OpenGL query. |
| 102 | u64 result; ///< Added values of the counter. | ||
| 103 | }; | ||
| 104 | |||
| 105 | class CachedQuery final : public RasterizerCacheObject { | ||
| 106 | public: | ||
| 107 | explicit CachedQuery(VideoCore::QueryType type, VAddr cpu_addr, u8* host_ptr); | ||
| 108 | ~CachedQuery(); | ||
| 109 | |||
| 110 | /// Writes the counter value to host memory. | ||
| 111 | void Flush(); | ||
| 112 | |||
| 113 | /// Updates the counter this cached query registered in guest memory will write when requested. | ||
| 114 | void SetCounter(std::shared_ptr<HostCounter> counter); | ||
| 35 | 115 | ||
| 36 | OGLQuery query; ///< OpenGL query. | 116 | /// Returns the query type. |
| 37 | u64 counter{}; ///< Added values of the counter. | 117 | VideoCore::QueryType GetType() const; |
| 38 | bool is_beginned{}; ///< True when the OpenGL query is beginned. | 118 | |
| 119 | VAddr GetCpuAddr() const override { | ||
| 120 | return cpu_addr; | ||
| 121 | } | ||
| 122 | |||
| 123 | std::size_t GetSizeInBytes() const override { | ||
| 124 | return sizeof(u64); | ||
| 125 | } | ||
| 126 | |||
| 127 | private: | ||
| 128 | VideoCore::QueryType type; | ||
| 129 | VAddr cpu_addr; ///< Guest CPU address. | ||
| 130 | u8* host_ptr; ///< Writable host pointer. | ||
| 131 | std::shared_ptr<HostCounter> counter; ///< Host counter to query, owns the dependency tree. | ||
| 39 | }; | 132 | }; |
| 40 | 133 | ||
| 41 | } // namespace OpenGL | 134 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 652db705b..827f85884 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include "video_core/engines/maxwell_3d.h" | 25 | #include "video_core/engines/maxwell_3d.h" |
| 26 | #include "video_core/engines/shader_type.h" | 26 | #include "video_core/engines/shader_type.h" |
| 27 | #include "video_core/memory_manager.h" | 27 | #include "video_core/memory_manager.h" |
| 28 | #include "video_core/renderer_opengl/gl_query_cache.h" | ||
| 28 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 29 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 29 | #include "video_core/renderer_opengl/gl_shader_cache.h" | 30 | #include "video_core/renderer_opengl/gl_shader_cache.h" |
| 30 | #include "video_core/renderer_opengl/gl_shader_gen.h" | 31 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| @@ -92,8 +93,8 @@ std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer, | |||
| 92 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, | 93 | RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, |
| 93 | ScreenInfo& info) | 94 | ScreenInfo& info) |
| 94 | : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device}, | 95 | : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device}, |
| 95 | shader_cache{*this, system, emu_window, device}, system{system}, screen_info{info}, | 96 | shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system}, |
| 96 | buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} { | 97 | screen_info{info}, buffer_cache{*this, system, device, STREAM_BUFFER_SIZE} { |
| 97 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); | 98 | shader_program_manager = std::make_unique<GLShader::ProgramManager>(); |
| 98 | state.draw.shader_program = 0; | 99 | state.draw.shader_program = 0; |
| 99 | state.Apply(); | 100 | state.Apply(); |
| @@ -548,9 +549,9 @@ void RasterizerOpenGL::Clear() { | |||
| 548 | void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { | 549 | void RasterizerOpenGL::Draw(bool is_indexed, bool is_instanced) { |
| 549 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 550 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 550 | auto& gpu = system.GPU().Maxwell3D(); | 551 | auto& gpu = system.GPU().Maxwell3D(); |
| 551 | |||
| 552 | const auto& regs = gpu.regs; | 552 | const auto& regs = gpu.regs; |
| 553 | samples_passed.UpdateState(regs.samplecnt_enable); | 553 | |
| 554 | query_cache.UpdateCounters(); | ||
| 554 | 555 | ||
| 555 | SyncRasterizeEnable(state); | 556 | SyncRasterizeEnable(state); |
| 556 | SyncColorMask(); | 557 | SyncColorMask(); |
| @@ -718,24 +719,11 @@ void RasterizerOpenGL::DispatchCompute(GPUVAddr code_addr) { | |||
| 718 | } | 719 | } |
| 719 | 720 | ||
| 720 | void RasterizerOpenGL::ResetCounter(VideoCore::QueryType type) { | 721 | void RasterizerOpenGL::ResetCounter(VideoCore::QueryType type) { |
| 721 | switch (type) { | 722 | query_cache.ResetCounter(type); |
| 722 | case VideoCore::QueryType::SamplesPassed: | ||
| 723 | samples_passed.Reset(); | ||
| 724 | break; | ||
| 725 | default: | ||
| 726 | UNIMPLEMENTED_MSG("type={}", static_cast<u32>(type)); | ||
| 727 | break; | ||
| 728 | } | ||
| 729 | } | 723 | } |
| 730 | 724 | ||
| 731 | u64 RasterizerOpenGL::Query(VideoCore::QueryType type) { | 725 | void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCore::QueryType type) { |
| 732 | switch (type) { | 726 | query_cache.Query(gpu_addr, type); |
| 733 | case VideoCore::QueryType::SamplesPassed: | ||
| 734 | return samples_passed.Query(); | ||
| 735 | default: | ||
| 736 | UNIMPLEMENTED_MSG("type={}", static_cast<u32>(type)); | ||
| 737 | return 1; | ||
| 738 | } | ||
| 739 | } | 727 | } |
| 740 | 728 | ||
| 741 | void RasterizerOpenGL::FlushAll() {} | 729 | void RasterizerOpenGL::FlushAll() {} |
| @@ -747,6 +735,7 @@ void RasterizerOpenGL::FlushRegion(CacheAddr addr, u64 size) { | |||
| 747 | } | 735 | } |
| 748 | texture_cache.FlushRegion(addr, size); | 736 | texture_cache.FlushRegion(addr, size); |
| 749 | buffer_cache.FlushRegion(addr, size); | 737 | buffer_cache.FlushRegion(addr, size); |
| 738 | query_cache.FlushRegion(addr, size); | ||
| 750 | } | 739 | } |
| 751 | 740 | ||
| 752 | void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { | 741 | void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { |
| @@ -757,6 +746,7 @@ void RasterizerOpenGL::InvalidateRegion(CacheAddr addr, u64 size) { | |||
| 757 | texture_cache.InvalidateRegion(addr, size); | 746 | texture_cache.InvalidateRegion(addr, size); |
| 758 | shader_cache.InvalidateRegion(addr, size); | 747 | shader_cache.InvalidateRegion(addr, size); |
| 759 | buffer_cache.InvalidateRegion(addr, size); | 748 | buffer_cache.InvalidateRegion(addr, size); |
| 749 | query_cache.InvalidateRegion(addr, size); | ||
| 760 | } | 750 | } |
| 761 | 751 | ||
| 762 | void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { | 752 | void RasterizerOpenGL::FlushAndInvalidateRegion(CacheAddr addr, u64 size) { |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 857a6c073..4fb6811a7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -63,7 +63,7 @@ public: | |||
| 63 | void Clear() override; | 63 | void Clear() override; |
| 64 | void DispatchCompute(GPUVAddr code_addr) override; | 64 | void DispatchCompute(GPUVAddr code_addr) override; |
| 65 | void ResetCounter(VideoCore::QueryType type) override; | 65 | void ResetCounter(VideoCore::QueryType type) override; |
| 66 | u64 Query(VideoCore::QueryType type) override; | 66 | void Query(GPUVAddr gpu_addr, VideoCore::QueryType type) override; |
| 67 | void FlushAll() override; | 67 | void FlushAll() override; |
| 68 | void FlushRegion(CacheAddr addr, u64 size) override; | 68 | void FlushRegion(CacheAddr addr, u64 size) override; |
| 69 | void InvalidateRegion(CacheAddr addr, u64 size) override; | 69 | void InvalidateRegion(CacheAddr addr, u64 size) override; |
| @@ -78,6 +78,11 @@ public: | |||
| 78 | void LoadDiskResources(const std::atomic_bool& stop_loading, | 78 | void LoadDiskResources(const std::atomic_bool& stop_loading, |
| 79 | const VideoCore::DiskResourceLoadCallback& callback) override; | 79 | const VideoCore::DiskResourceLoadCallback& callback) override; |
| 80 | 80 | ||
| 81 | /// Returns true when there are commands queued to the OpenGL server. | ||
| 82 | bool AnyCommandQueued() const { | ||
| 83 | return num_queued_commands > 0; | ||
| 84 | } | ||
| 85 | |||
| 81 | private: | 86 | private: |
| 82 | /// Configures the color and depth framebuffer states. | 87 | /// Configures the color and depth framebuffer states. |
| 83 | void ConfigureFramebuffers(); | 88 | void ConfigureFramebuffers(); |
| @@ -207,6 +212,7 @@ private: | |||
| 207 | ShaderCacheOpenGL shader_cache; | 212 | ShaderCacheOpenGL shader_cache; |
| 208 | SamplerCacheOpenGL sampler_cache; | 213 | SamplerCacheOpenGL sampler_cache; |
| 209 | FramebufferCacheOpenGL framebuffer_cache; | 214 | FramebufferCacheOpenGL framebuffer_cache; |
| 215 | QueryCache query_cache; | ||
| 210 | 216 | ||
| 211 | Core::System& system; | 217 | Core::System& system; |
| 212 | ScreenInfo& screen_info; | 218 | ScreenInfo& screen_info; |
| @@ -224,8 +230,6 @@ private: | |||
| 224 | BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; | 230 | BindBuffersRangePushBuffer bind_ubo_pushbuffer{GL_UNIFORM_BUFFER}; |
| 225 | BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; | 231 | BindBuffersRangePushBuffer bind_ssbo_pushbuffer{GL_SHADER_STORAGE_BUFFER}; |
| 226 | 232 | ||
| 227 | HostCounter samples_passed{GL_SAMPLES_PASSED}; | ||
| 228 | |||
| 229 | /// Number of commands queued to the OpenGL driver. Reseted on flush. | 233 | /// Number of commands queued to the OpenGL driver. Reseted on flush. |
| 230 | std::size_t num_queued_commands = 0; | 234 | std::size_t num_queued_commands = 0; |
| 231 | }; | 235 | }; |