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:
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}});
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user