diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index bcf0c15a44..b239dff842 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -104,7 +104,7 @@ protected: } /// Register an object into the cache - void Register(const T& object) { + virtual void Register(const T& object) { object->SetIsRegistered(true); interval_cache.add({GetInterval(object), ObjectSet{object}}); map_cache.insert({object->GetAddr(), object}); @@ -112,7 +112,7 @@ protected: } /// Unregisters an object from the cache - void Unregister(const T& object) { + virtual void Unregister(const T& object) { object->SetIsRegistered(false); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); // Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit @@ -129,6 +129,15 @@ protected: return ++modified_ticks; } + /// Flushes the specified object, updating appropriate cache state as needed + void FlushObject(const T& object) { + if (!object->IsDirty()) { + return; + } + object->Flush(); + object->MarkAsModified(false, *this); + } + private: /// Returns a list of cached objects from the specified memory region, ordered by access time std::vector GetSortedObjectsFromRegion(VAddr addr, u64 size) { @@ -154,15 +163,6 @@ private: return objects; } - /// Flushes the specified object, updating appropriate cache state as needed - void FlushObject(const T& object) { - if (!object->IsDirty()) { - return; - } - object->Flush(); - object->MarkAsModified(false, *this); - } - using ObjectSet = std::set; using ObjectCache = std::unordered_map; using IntervalCache = boost::icl::interval_map; diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 77da135a0d..c2c7e8bb44 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -66,5 +66,7 @@ public: /// Initialize disk cached resources for the game being emulated virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false, const DiskResourceLoadCallback& callback = {}) {} + /// Notify rasterizer that dma push has finished. + virtual void SignalFinish() = 0; }; } // namespace VideoCore diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 974ca6a20e..5fd24c88f6 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -1283,4 +1283,8 @@ void RasterizerOpenGL::CheckAlphaTests() { } } +void RasterizerOpenGL::SignalFinish() { + res_cache.SignalFinish(); +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index f3b607f4d6..a031517626 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -69,6 +69,8 @@ public: void LoadDiskResources(const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback) override; + void SignalFinish() override; + /// Maximum supported size that a constbuffer can have in bytes. static constexpr std::size_t MaxConstbufferSize = 0x10000; static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index fd7da3ea92..97f71536ba 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -700,7 +700,8 @@ void CachedSurface::LoadGLBuffer() { u32 bpp = params.GetFormatBpp() / 8; u32 copy_size = params.width * bpp; if (params.pitch == copy_size) { - std::memcpy(gl_buffer[0].data(), Memory::GetPointer(params.addr), params.size_in_bytes_gl); + std::memcpy(gl_buffer[0].data(), Memory::GetPointer(params.addr), + params.size_in_bytes_gl); } else { u8* start = Memory::GetPointer(params.addr); u8* write_to = gl_buffer[0].data(); @@ -1132,4 +1133,10 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params return {}; } +void RasterizerCacheOpenGL::SignalFinish() { + for (const auto& o : surfaces_to_flush) { + FlushObject(o); + } +} + } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index c6895909fb..a97496ae8c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "common/alignment.h" @@ -424,6 +425,26 @@ public: void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config, const Tegra::Engines::Fermi2D::Regs::Surface& dst_config); + void SignalFinish(); + +protected: + void Register(const Surface& object) { + RasterizerCache::Register(object); + const auto& params = object->GetSurfaceParams(); + if (!params.is_tiled) { + surfaces_to_flush.insert(object); + } + } + + /// Unregisters an object from the cache + void Unregister(const Surface& object) { + const auto& params = object->GetSurfaceParams(); + if (!params.is_tiled) { + surfaces_to_flush.erase(object); + } + RasterizerCache::Unregister(object); + } + private: void LoadSurface(const Surface& surface); Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); @@ -449,6 +470,8 @@ private: /// destroyed when used with different surface parameters. std::unordered_map surface_reserve; + std::unordered_set surfaces_to_flush; + OGLFramebuffer read_framebuffer; OGLFramebuffer draw_framebuffer; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 6476a9e1a8..3fd36cd8af 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -142,6 +142,7 @@ void RendererOpenGL::SwapBuffers( // Restore the rasterizer state prev_state.Apply(); + rasterizer->SignalFinish(); } /**