gl_rasterizer_cache: Use accurate framebuffer setting for accurate copies.

This commit is contained in:
bunnei 2018-08-30 20:27:23 -04:00
parent 123c065086
commit 7f7eb29323
2 changed files with 57 additions and 76 deletions

View File

@ -432,16 +432,6 @@ void RasterizerOpenGL::Clear() {
glClearStencil(regs.clear_stencil); glClearStencil(regs.clear_stencil);
glClear(clear_mask); glClear(clear_mask);
// Mark framebuffer surfaces as dirty
if (Settings::values.use_accurate_framebuffers) {
if (dirty_color_surface != nullptr) {
res_cache.FlushSurface(dirty_color_surface);
}
if (dirty_depth_surface != nullptr) {
res_cache.FlushSurface(dirty_depth_surface);
}
}
} }
std::pair<u8*, GLintptr> RasterizerOpenGL::AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset, std::pair<u8*, GLintptr> RasterizerOpenGL::AlignBuffer(u8* buffer_ptr, GLintptr buffer_offset,
@ -557,16 +547,6 @@ void RasterizerOpenGL::DrawArrays() {
texture_unit.Unbind(); texture_unit.Unbind();
} }
state.Apply(); state.Apply();
// Mark framebuffer surfaces as dirty
if (Settings::values.use_accurate_framebuffers) {
if (dirty_color_surface != nullptr) {
res_cache.FlushSurface(dirty_color_surface);
}
if (dirty_depth_surface != nullptr) {
res_cache.FlushSurface(dirty_depth_surface);
}
}
} }
void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {} void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 method) {}

View File

@ -760,11 +760,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
// Look up surface in the cache based on address // Look up surface in the cache based on address
Surface surface{TryGet(params.addr)}; Surface surface{TryGet(params.addr)};
if (surface) { if (surface) {
if (Settings::values.use_accurate_framebuffers) { if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
// If use_accurate_framebuffers is enabled, always load from memory
FlushSurface(surface);
Unregister(surface);
} else if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
// Use the cached surface as-is // Use the cached surface as-is
return surface; return surface;
} else if (preserve_contents) { } else if (preserve_contents) {
@ -818,63 +814,68 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
return new_surface; return new_surface;
} }
auto source_format = GetFormatTuple(params.pixel_format, params.component_type); // When using accurate framebuffers, always copy old data to new surface, regardless of format
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type); if (Settings::values.use_accurate_framebuffers) {
auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes()); size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one // Use a Pixel Buffer Object to download the previous texture and then upload it to the new
// using the new format. // one using the new format.
OGLBuffer pbo; OGLBuffer pbo;
pbo.Create(); pbo.Create();
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle); glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
if (source_format.compressed) { if (source_format.compressed) {
glGetCompressedTextureImage(surface->Texture().handle, 0, glGetCompressedTextureImage(surface->Texture().handle, 0,
static_cast<GLsizei>(params.SizeInBytes()), nullptr); static_cast<GLsizei>(params.SizeInBytes()), nullptr);
} else { } else {
glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type, glGetTextureImage(surface->Texture().handle, 0, source_format.format,
static_cast<GLsizei>(params.SizeInBytes()), nullptr); source_format.type, static_cast<GLsizei>(params.SizeInBytes()),
} nullptr);
// If the new texture is bigger than the previous one, we need to fill in the rest with data
// from the CPU.
if (params.SizeInBytes() < new_params.SizeInBytes()) {
// Upload the rest of the memory.
if (new_params.is_tiled) {
// TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest of
// the data in this case. Games like Super Mario Odyssey seem to hit this case when
// drawing, it re-uses the memory of a previous texture as a bigger framebuffer but it
// doesn't clear it beforehand, the texture is already full of zeros.
LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
"reinterpretation but the texture is tiled.");
} }
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes(); // If the new texture is bigger than the previous one, we need to fill in the rest with data
std::vector<u8> data(remaining_size); // from the CPU.
Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size()); if (params.SizeInBytes() < new_params.SizeInBytes()) {
glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size, data.data()); // Upload the rest of the memory.
if (new_params.is_tiled) {
// TODO(Subv): We might have to de-tile the subtexture and re-tile it with the rest
// of the data in this case. Games like Super Mario Odyssey seem to hit this case
// when drawing, it re-uses the memory of a previous texture as a bigger framebuffer
// but it doesn't clear it beforehand, the texture is already full of zeros.
LOG_CRITICAL(HW_GPU, "Trying to upload extra texture data from the CPU during "
"reinterpretation but the texture is tiled.");
}
size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
std::vector<u8> data(remaining_size);
Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size());
glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size,
data.data());
}
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
const auto& dest_rect{new_params.GetRect()};
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
if (dest_format.compressed) {
glCompressedTexSubImage2D(
GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
} else {
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
dest_format.type, nullptr);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pbo.Release();
} }
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
const auto& dest_rect{new_params.GetRect()};
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
if (dest_format.compressed) {
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
} else {
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
dest_format.type, nullptr);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pbo.Release();
return new_surface; return new_surface;
} }