RasterizerGL: Flush dirty cached objects before removing them from the cache.

There might be a case where we draw to a framebuffer (thus making it dirty) and then proceed to overwrite only a portion of it from the CPU. The current code would cause the rest of the modified framebuffer to be discarded.
This commit is contained in:
Subv
2018-09-20 10:31:40 -05:00
parent b87b8db879
commit 47826fd090
7 changed files with 23 additions and 18 deletions

View File

@@ -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

View File

@@ -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++;
}

View File

@@ -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

View File

@@ -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}});
}

View File

@@ -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

View File

@@ -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));

View File

@@ -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() {