diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index df4c0211e..d72df90ef 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -21,6 +21,7 @@ #include "common/common_types.h" #include "core/core.h" #include "core/memory.h" +#include "core/settings.h" #include "video_core/buffer_cache/buffer_block.h" #include "video_core/buffer_cache/map_interval.h" #include "video_core/memory_manager.h" @@ -80,6 +81,9 @@ public: auto map = MapAddress(block, gpu_addr, cpu_addr, size); if (is_written) { map->MarkAsModified(true, GetModifiedTicks()); + if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { + AsyncFlushMap(map); + } if (!map->IsWritten()) { map->MarkAsWritten(true); MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1); @@ -193,6 +197,39 @@ public: marked_for_unregister.clear(); } + void CommitAsyncFlushes() { + commited_flushes.push_back(uncommited_flushes); + uncommited_flushes.reset(); + } + + 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 (MapInterval& map : *flush_list) { + if (map->IsRegistered()) { + FlushMap(map); + } + } + commited_flushes.pop_front(); + } + virtual BufferType GetEmptyBuffer(std::size_t size) = 0; protected: @@ -316,6 +353,9 @@ private: MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr); if (modified_inheritance) { new_map->MarkAsModified(true, GetModifiedTicks()); + if (Settings::IsGPULevelHigh() && Settings::values.use_asynchronous_gpu_emulation) { + AsyncFlushMap(new_map); + } } Register(new_map, write_inheritance); return new_map; @@ -502,6 +542,13 @@ private: return false; } + void AsyncFlushMap(MapInterval& map) { + if (!uncommited_flushes) { + uncommited_flushes = std::make_shared>(); + } + uncommited_flushes->push_back(map); + } + VideoCore::RasterizerInterface& rasterizer; Core::System& system; @@ -533,6 +580,9 @@ private: std::vector staging_buffer; std::list marked_for_unregister; + std::shared_ptr> uncommited_flushes{}; + std::list>> commited_flushes; + std::recursive_mutex mutex; }; diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index 036f3996c..c4b190503 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h @@ -6,8 +6,8 @@ #include #include -#include #include +#include #include "common/assert.h" #include "common/common_types.h" @@ -37,7 +37,7 @@ private: u32 payload; }; -template +template class FenceManager { public: void SignalFence(GPUVAddr addr, u32 value) { @@ -46,6 +46,7 @@ public: QueueFence(new_fence); fences.push(new_fence); texture_cache.CommitAsyncFlushes(); + buffer_cache.CommitAsyncFlushes(); rasterizer.FlushCommands(); rasterizer.SyncGuestHost(); } @@ -54,10 +55,12 @@ public: while (!fences.empty()) { TFence& current_fence = fences.front(); bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); + should_wait |= buffer_cache.ShouldWaitAsyncFlushes(); if (should_wait) { WaitFence(current_fence); } texture_cache.PopAsyncFlushes(); + buffer_cache.PopAsyncFlushes(); auto& gpu{system.GPU()}; auto& memory_manager{gpu.MemoryManager()}; memory_manager.Write(current_fence->GetAddress(), current_fence->GetPayload()); @@ -67,8 +70,9 @@ public: protected: FenceManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer, - TTextureCache& texture_cache) - : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache} {} + TTextureCache& texture_cache, TTBufferCache& buffer_cache) + : system{system}, rasterizer{rasterizer}, texture_cache{texture_cache}, buffer_cache{ + buffer_cache} {} virtual TFence CreateFence(GPUVAddr addr, u32 value) = 0; virtual void QueueFence(TFence& fence) = 0; @@ -78,16 +82,19 @@ protected: Core::System& system; VideoCore::RasterizerInterface& rasterizer; TTextureCache& texture_cache; + TTBufferCache& buffer_cache; private: void TryReleasePendingFences() { while (!fences.empty()) { TFence& current_fence = fences.front(); bool should_wait = texture_cache.ShouldWaitAsyncFlushes(); + should_wait |= buffer_cache.ShouldWaitAsyncFlushes(); if (should_wait && !IsFenceSignaled(current_fence)) { return; } texture_cache.PopAsyncFlushes(); + buffer_cache.PopAsyncFlushes(); auto& gpu{system.GPU()}; auto& memory_manager{gpu.MemoryManager()}; memory_manager.Write(current_fence->GetAddress(), current_fence->GetPayload()); diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 1c3ab2145..3e2be00e9 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -81,7 +81,7 @@ void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { } void ThreadManager::FlushRegion(VAddr addr, u64 size) { - if (!Settings::IsGPULevelExtreme()) { + if (!Settings::IsGPULevelHigh()) { return; } if (system.Renderer().Rasterizer().MustFlushRegion(addr, size)) { diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp index 4517ef150..69dd3211b 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.cpp +++ b/src/video_core/renderer_opengl/gl_fence_manager.cpp @@ -33,8 +33,8 @@ void GLInnerFence::Wait() { } FenceManagerOpenGL::FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, - TextureCacheOpenGL& texture_cache) - : GenericFenceManager(system, rasterizer, texture_cache) {} + TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache) + : GenericFenceManager(system, rasterizer, texture_cache, buffer_cache) {} Fence FenceManagerOpenGL::CreateFence(GPUVAddr addr, u32 value) { return std::make_shared(addr, value); diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h index 3cfa8b1d0..b48d5eaa0 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.h +++ b/src/video_core/renderer_opengl/gl_fence_manager.h @@ -9,6 +9,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_resource_manager.h" #include "video_core/renderer_opengl/gl_texture_cache.h" @@ -30,12 +31,12 @@ private: }; using Fence = std::shared_ptr; -using GenericFenceManager = VideoCommon::FenceManager; +using GenericFenceManager = VideoCommon::FenceManager; class FenceManagerOpenGL final : public GenericFenceManager { public: FenceManagerOpenGL(Core::System& system, VideoCore::RasterizerInterface& rasterizer, - TextureCacheOpenGL& texture_cache); + TextureCacheOpenGL& texture_cache, OGLBufferCache& buffer_cache); protected: Fence CreateFence(GPUVAddr addr, u32 value) override; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index db7eae065..88914828c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -102,7 +102,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind 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} { + texture_cache, + buffer_cache} { CheckExtensions(); }