QueryCache: Implement Async Flushes.
This commit is contained in:
		| @@ -49,15 +49,17 @@ protected: | ||||
|     bool is_stubbed; | ||||
| }; | ||||
|  | ||||
| template <typename TFence, typename TTextureCache, typename TTBufferCache> | ||||
| template <typename TFence, typename TTextureCache, typename TTBufferCache, typename TQueryCache> | ||||
| class FenceManager { | ||||
| public: | ||||
|     void SignalSemaphore(GPUVAddr addr, u32 value) { | ||||
|         TryReleasePendingFences(); | ||||
|         bool should_flush = texture_cache.HasUncommitedFlushes(); | ||||
|         should_flush |= buffer_cache.HasUncommitedFlushes(); | ||||
|         should_flush |= query_cache.HasUncommitedFlushes(); | ||||
|         texture_cache.CommitAsyncFlushes(); | ||||
|         buffer_cache.CommitAsyncFlushes(); | ||||
|         query_cache.CommitAsyncFlushes(); | ||||
|         TFence new_fence = CreateFence(addr, value, !should_flush); | ||||
|         fences.push(new_fence); | ||||
|         QueueFence(new_fence); | ||||
| @@ -71,8 +73,10 @@ public: | ||||
|         TryReleasePendingFences(); | ||||
|         bool should_flush = texture_cache.HasUncommitedFlushes(); | ||||
|         should_flush |= buffer_cache.HasUncommitedFlushes(); | ||||
|         should_flush |= query_cache.HasUncommitedFlushes(); | ||||
|         texture_cache.CommitAsyncFlushes(); | ||||
|         buffer_cache.CommitAsyncFlushes(); | ||||
|         query_cache.CommitAsyncFlushes(); | ||||
|         TFence new_fence = CreateFence(value, !should_flush); | ||||
|         fences.push(new_fence); | ||||
|         QueueFence(new_fence); | ||||
| @@ -87,11 +91,13 @@ public: | ||||
|             TFence& current_fence = fences.front(); | ||||
|             bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); | ||||
|             should_wait |= buffer_cache.ShouldWaitAsyncFlushes(); | ||||
|             should_wait |= query_cache.ShouldWaitAsyncFlushes(); | ||||
|             if (should_wait) { | ||||
|                 WaitFence(current_fence); | ||||
|             } | ||||
|             texture_cache.PopAsyncFlushes(); | ||||
|             buffer_cache.PopAsyncFlushes(); | ||||
|             query_cache.PopAsyncFlushes(); | ||||
|             auto& gpu{system.GPU()}; | ||||
|             if (current_fence->IsSemaphore()) { | ||||
|                 auto& memory_manager{gpu.MemoryManager()}; | ||||
| @@ -105,9 +111,10 @@ public: | ||||
|  | ||||
| protected: | ||||
|     FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | ||||
|                  TTextureCache& texture_cache, TTBufferCache& buffer_cache) | ||||
|         : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{ | ||||
|                                                                                     buffer_cache} {} | ||||
|                  TTextureCache& texture_cache, TTBufferCache& buffer_cache, | ||||
|                  TQueryCache& query_cache) | ||||
|         : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, | ||||
|           buffer_cache{buffer_cache}, query_cache{query_cache} {} | ||||
|  | ||||
|     virtual TFence CreateFence(u32 value, bool is_stubbed) = 0; | ||||
|     virtual TFence CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) = 0; | ||||
| @@ -119,6 +126,7 @@ protected: | ||||
|     VideoCore::RasterizerInterface& rasterizer; | ||||
|     TTextureCache& texture_cache; | ||||
|     TTBufferCache& buffer_cache; | ||||
|     TQueryCache& query_cache; | ||||
|  | ||||
| private: | ||||
|     void TryReleasePendingFences() { | ||||
| @@ -126,11 +134,13 @@ private: | ||||
|             TFence& current_fence = fences.front(); | ||||
|             bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); | ||||
|             should_wait |= buffer_cache.ShouldWaitAsyncFlushes(); | ||||
|             should_wait |= query_cache.ShouldWaitAsyncFlushes(); | ||||
|             if (should_wait && !IsFenceSignaled(current_fence)) { | ||||
|                 return; | ||||
|             } | ||||
|             texture_cache.PopAsyncFlushes(); | ||||
|             buffer_cache.PopAsyncFlushes(); | ||||
|             query_cache.PopAsyncFlushes(); | ||||
|             auto& gpu{system.GPU()}; | ||||
|             if (current_fence->IsSemaphore()) { | ||||
|                 auto& memory_manager{gpu.MemoryManager()}; | ||||
|   | ||||
| @@ -12,6 +12,7 @@ | ||||
| #include <mutex> | ||||
| #include <optional> | ||||
| #include <unordered_map> | ||||
| #include <unordered_set> | ||||
| #include <vector> | ||||
|  | ||||
| #include "common/assert.h" | ||||
| @@ -130,6 +131,7 @@ public: | ||||
|         } | ||||
|  | ||||
|         query->BindCounter(Stream(type).Current(), timestamp); | ||||
|         AsyncFlushQuery(cpu_addr); | ||||
|     } | ||||
|  | ||||
|     /// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. | ||||
| @@ -170,6 +172,44 @@ public: | ||||
|         return streams[static_cast<std::size_t>(type)]; | ||||
|     } | ||||
|  | ||||
|     void CommitAsyncFlushes() { | ||||
|         commited_flushes.push_back(uncommited_flushes); | ||||
|         uncommited_flushes.reset(); | ||||
|     } | ||||
|  | ||||
|     bool HasUncommitedFlushes() { | ||||
|         if (uncommited_flushes) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     bool ShouldWaitAsyncFlushes() { | ||||
|         if (commited_flushes.empty()) { | ||||
|             return false; | ||||
|         } | ||||
|         auto& flush_list = commited_flushes.front(); | ||||
|         if (!flush_list) { | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     void PopAsyncFlushes() { | ||||
|         if (commited_flushes.empty()) { | ||||
|             return; | ||||
|         } | ||||
|         auto& flush_list = commited_flushes.front(); | ||||
|         if (!flush_list) { | ||||
|             commited_flushes.pop_front(); | ||||
|             return; | ||||
|         } | ||||
|         for (VAddr query_address : *flush_list) { | ||||
|             FlushAndRemoveRegion(query_address, 4); | ||||
|         } | ||||
|         commited_flushes.pop_front(); | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|     std::array<QueryPool, VideoCore::NumQueryTypes> query_pools; | ||||
|  | ||||
| @@ -224,6 +264,13 @@ private: | ||||
|         return found != std::end(contents) ? &*found : nullptr; | ||||
|     } | ||||
|  | ||||
|     void AsyncFlushQuery(VAddr addr) { | ||||
|         if (!uncommited_flushes) { | ||||
|             uncommited_flushes = std::make_shared<std::unordered_set<VAddr>>(); | ||||
|         } | ||||
|         uncommited_flushes->insert(addr); | ||||
|     } | ||||
|  | ||||
|     static constexpr std::uintptr_t PAGE_SIZE = 4096; | ||||
|     static constexpr unsigned PAGE_SHIFT = 12; | ||||
|  | ||||
| @@ -235,6 +282,9 @@ private: | ||||
|     std::unordered_map<u64, std::vector<CachedQuery>> cached_queries; | ||||
|  | ||||
|     std::array<CounterStream, VideoCore::NumQueryTypes> streams; | ||||
|  | ||||
|     std::shared_ptr<std::unordered_set<VAddr>> uncommited_flushes{}; | ||||
|     std::list<std::shared_ptr<std::unordered_set<VAddr>>> commited_flushes; | ||||
| }; | ||||
|  | ||||
| template <class QueryCache, class HostCounter> | ||||
|   | ||||
| @@ -44,9 +44,11 @@ void GLInnerFence::Wait() { | ||||
|         ; | ||||
| } | ||||
|  | ||||
| FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | ||||
|                                TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache) | ||||
|     : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {} | ||||
| FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, | ||||
|                                        VideoCore::RasterizerInterface& rasterizer, | ||||
|                                        TextureCacheOpenGL& texture_cache, | ||||
|                                        OGLBufferCache& buffer_cache, QueryCache& query_cache) | ||||
|     : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache, query_cache) {} | ||||
|  | ||||
| Fence FenceManagerOpenGL::CreateFence(u32 value, bool is_stubbed) { | ||||
|     return std::make_shared<GLInnerFence>(value, is_stubbed); | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/fence_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_buffer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_query_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_texture_cache.h" | ||||
|  | ||||
| @@ -32,12 +33,14 @@ private: | ||||
| }; | ||||
|  | ||||
| using Fence = std::shared_ptr<GLInnerFence>; | ||||
| using GenericFenceManager = VideoCommon::FenceManager<Fence, TextureCacheOpenGL, OGLBufferCache>; | ||||
| using GenericFenceManager = | ||||
|     VideoCommon::FenceManager<Fence, TextureCacheOpenGL, OGLBufferCache, QueryCache>; | ||||
|  | ||||
| class FenceManagerOpenGL final : public GenericFenceManager { | ||||
| public: | ||||
|     FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | ||||
|                        TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache); | ||||
|                        TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache, | ||||
|                        QueryCache& query_cache); | ||||
|  | ||||
| protected: | ||||
|     Fence CreateFence(u32 value, bool is_stubbed) override; | ||||
|   | ||||
| @@ -101,9 +101,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind | ||||
|     : RasterizerAccelerated{system.Memory()}, texture_cache{system, *this, device, state_tracker}, | ||||
|       shader_cache{*this, system, emu_window, device}, query_cache{system, *this}, system{system}, | ||||
|       screen_info{info}, program_manager{program_manager}, state_tracker{state_tracker}, | ||||
|       buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{system, *this, | ||||
|                                                                              texture_cache, | ||||
|                                                                              buffer_cache} { | ||||
|       buffer_cache{*this, system, device, STREAM_BUFFER_SIZE}, fence_manager{ | ||||
|                                                                    system, *this, texture_cache, | ||||
|                                                                    buffer_cache, query_cache} { | ||||
|     CheckExtensions(); | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user