diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 8c6d48b79e..da9e5e3139 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp @@ -55,6 +55,10 @@ void Fermi2D::HandleSurfaceCopy() { } rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); + // We have to invalidate the destination region to evict any outdated surfaces from the cache. + // We do this before actually writing the new data because the destination address might contain + // a dirty surface that will have to be written back to memory. + rasterizer.InvalidateRegion(dest_cpu, dst_bytes_per_pixel * regs.dst.width * regs.dst.height); u8* src_buffer = Memory::GetPointer(source_cpu); u8* dst_buffer = Memory::GetPointer(dest_cpu); @@ -70,8 +74,6 @@ void Fermi2D::HandleSurfaceCopy() { dst_bytes_per_pixel, dst_buffer, src_buffer, false, regs.dst.BlockHeight()); } - - rasterizer.InvalidateRegion(dest_cpu, dst_bytes_per_pixel * regs.dst.width * regs.dst.height); } } // namespace Tegra::Engines diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index ca5e2843df..585290d9ff 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp @@ -41,10 +41,13 @@ void KeplerMemory::ProcessData(u32 data) { VAddr dest_address = *memory_manager.GpuToCpuAddress(address + state.write_offset * sizeof(u32)); - Memory::Write32(dest_address, data); - + // We have to invalidate the destination region to evict any outdated surfaces from the cache. + // We do this before actually writing the new data because the destination address might contain + // a dirty surface that will have to be written back to memory. rasterizer.InvalidateRegion(dest_address, sizeof(u32)); + Memory::Write32(dest_address, data); + state.write_offset++; } diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index e8881f1fff..9cf1f83e96 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -74,6 +74,11 @@ void MaxwellDMA::HandleCopy() { // TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated copying. rasterizer.FlushRegion(source_cpu, copy_size); + // We have to invalidate the destination region to evict any outdated surfaces from the cache. + // We do this before actually writing the new data because the destination address might contain + // a dirty surface that will have to be written back to memory. + rasterizer.InvalidateRegion(dest_cpu, copy_size); + u8* src_buffer = Memory::GetPointer(source_cpu); u8* dst_buffer = Memory::GetPointer(dest_cpu); @@ -104,9 +109,6 @@ void MaxwellDMA::HandleCopy() { Texture::CopySwizzledData(regs.dst_params.size_x, regs.dst_params.size_y, 1, 1, dst_buffer, src_buffer, false, regs.dst_params.BlockHeight()); } - - // We have to invalidate the destination region to evict any outdated surfaces from the cache. - rasterizer.InvalidateRegion(dest_cpu, copy_size); } } // namespace Engines diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h index 04a2da6613..4a34491a9f 100644 --- a/src/video_core/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache.h @@ -87,6 +87,7 @@ protected: void Unregister(const T& object) { auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer(); rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1); + object->Flush(); object_cache.subtract({GetInterval(object), ObjectSet{object}}); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c4c9249f12..959fdc3576 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -363,11 +363,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep } if (depth_surface) { - if (depth_surface) { - // Assume that a surface will be written to if it is used as a framebuffer, even if - // the shader doesn't actually write to it. - depth_surface->MarkAsDirty(); - } + // Assume that a surface will be written to if it is used as a framebuffer, even if + // the shader doesn't actually write to it. + depth_surface->MarkAsDirty(); if (regs.stencil_enable) { // Attach both depth and stencil diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 0df3109668..c5a68b315c 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -646,10 +646,6 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, void CachedSurface::FlushGLBuffer() { MICROPROFILE_SCOPE(OpenGL_SurfaceFlush); - // There is no need to flush the surface if it hasn't been modified by us. - if (!dirty) - return; - const auto& rect{params.GetRect()}; // Load data from memory to the surface @@ -706,8 +702,6 @@ void CachedSurface::FlushGLBuffer() { Memory::WriteBlock(params.addr + buffer_offset, &gl_buffer[buffer_offset], gl_buffer.size() - buffer_offset); } - - dirty = false; } MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 495fd7aa8d..dc4437f143 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -742,7 +742,12 @@ public: } void Flush() { + // There is no need to flush the surface if it hasn't been modified by us. + if (!dirty) + return; + FlushGLBuffer(); + dirty = false; } void MarkAsDirty() {