diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 5b14d52e2..df4c0211e 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -145,6 +145,18 @@ public: } } + bool MustFlushRegion(VAddr addr, std::size_t size) { + std::lock_guard lock{mutex}; + + std::vector objects = GetMapsInRange(addr, size); + for (auto& object : objects) { + if (object->IsModified() && object->IsRegistered()) { + return true; + } + } + return false; + } + /// Mark the specified region as being invalidated void InvalidateRegion(VAddr addr, u64 size) { std::lock_guard lock{mutex}; diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index d05b6a9d2..19d3bd305 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp @@ -147,7 +147,7 @@ void GPU::SyncGuestHost() { } void GPU::OnCommandListEnd() { - renderer.Rasterizer().ReleaseFences(); + renderer->Rasterizer().ReleaseFences(); } // Note that, traditionally, methods are treated as 4-byte addressable locations, and hence // their numbers are written down multiplied by 4 in Docs. Here we are not multiply by 4. diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp index 251a9d911..672f8d2fa 100644 --- a/src/video_core/gpu_thread.cpp +++ b/src/video_core/gpu_thread.cpp @@ -6,6 +6,7 @@ #include "common/microprofile.h" #include "core/core.h" #include "core/frontend/emu_window.h" +#include "core/settings.h" #include "video_core/dma_pusher.h" #include "video_core/gpu.h" #include "video_core/gpu_thread.h" @@ -80,7 +81,11 @@ void ThreadManager::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { } void ThreadManager::FlushRegion(VAddr addr, u64 size) { - PushCommand(FlushRegionCommand(addr, size)); + if (system.Renderer().Rasterizer().MustFlushRegion(addr, size)) { + u64 fence = PushCommand(FlushRegionCommand(addr, size)); + while (fence < state.signaled_fence.load(std::memory_order_relaxed)) { + } + } } void ThreadManager::InvalidateRegion(VAddr addr, u64 size) { diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 72f65b166..228752131 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -49,13 +49,9 @@ public: /// Records a GPU query and caches it virtual void Query(GPUVAddr gpu_addr, QueryType type, std::optional timestamp) = 0; - virtual void SignalFence(GPUVAddr addr, u32 value) { + virtual void SignalFence(GPUVAddr addr, u32 value) {} - } - - virtual void ReleaseFences() { - - } + virtual void ReleaseFences() {} /// Notify rasterizer that all caches should be flushed to Switch memory virtual void FlushAll() = 0; @@ -63,6 +59,8 @@ public: /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory virtual void FlushRegion(VAddr addr, u64 size) = 0; + virtual bool MustFlushRegion(VAddr addr, u64 size) = 0; + /// Notify rasterizer that any caches of the specified region should be invalidated virtual void InvalidateRegion(VAddr addr, u64 size) = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 35bed444f..bbf37a00d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -650,6 +650,10 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) { query_cache.FlushRegion(addr, size); } +bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) { + return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); +} + void RasterizerOpenGL::InvalidateRegion(VAddr addr, u64 size) { MICROPROFILE_SCOPE(OpenGL_CacheManagement); if (addr == 0 || size == 0) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 6d173a922..5c0f88e6f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -67,6 +67,7 @@ public: void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; void FlushAll() override; void FlushRegion(VAddr addr, u64 size) override; + bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; void SyncGuestHost() override; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 4d0c90aa3..9437a4aa1 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -514,6 +514,10 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) { query_cache.FlushRegion(addr, size); } +bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) { + return texture_cache.MustFlushRegion(addr, size) || buffer_cache.MustFlushRegion(addr, size); +} + void RasterizerVulkan::InvalidateRegion(VAddr addr, u64 size) { if (addr == 0 || size == 0) { return; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 285f731bc..7002a4fa3 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -118,6 +118,7 @@ public: void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; void FlushAll() override; void FlushRegion(VAddr addr, u64 size) override; + bool MustFlushRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override; void SyncGuestHost() override; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 04fe69c11..e251a30c3 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -116,6 +116,21 @@ public: } } + bool MustFlushRegion(VAddr addr, std::size_t size) { + std::lock_guard lock{mutex}; + + auto surfaces = GetSurfacesInRegion(addr, size); + if (surfaces.empty()) { + return false; + } + for (const auto& surface : surfaces) { + if (surface->IsModified()) { + return true; + } + } + return false; + } + TView GetTextureSurface(const Tegra::Texture::TICEntry& tic, const VideoCommon::Shader::Sampler& entry) { std::lock_guard lock{mutex};