forked from suyu/suyu
gl_rasterizer_cache: Blit surfaces on recreation instead of flush and load.
This commit is contained in:
parent
4301f0b539
commit
63fbf9a7d3
2 changed files with 86 additions and 2 deletions
|
@ -254,6 +254,60 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup
|
||||||
cur_state.Apply();
|
cur_state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool BlitTextures(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect, GLuint dst_tex,
|
||||||
|
const MathUtil::Rectangle<u32>& dst_rect, SurfaceType type,
|
||||||
|
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||||
|
OpenGLState prev_state{OpenGLState::GetCurState()};
|
||||||
|
SCOPE_EXIT({ prev_state.Apply(); });
|
||||||
|
|
||||||
|
OpenGLState state;
|
||||||
|
state.draw.read_framebuffer = read_fb_handle;
|
||||||
|
state.draw.draw_framebuffer = draw_fb_handle;
|
||||||
|
state.Apply();
|
||||||
|
|
||||||
|
u32 buffers{};
|
||||||
|
|
||||||
|
if (type == SurfaceType::ColorTexture) {
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, src_tex,
|
||||||
|
0);
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_tex,
|
||||||
|
0);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||||
|
0);
|
||||||
|
|
||||||
|
buffers = GL_COLOR_BUFFER_BIT;
|
||||||
|
} else if (type == SurfaceType::Depth) {
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, src_tex, 0);
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst_tex, 0);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
|
||||||
|
|
||||||
|
buffers = GL_DEPTH_BUFFER_BIT;
|
||||||
|
} else if (type == SurfaceType::DepthStencil) {
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||||
|
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
|
src_tex, 0);
|
||||||
|
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
|
||||||
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||||
|
dst_tex, 0);
|
||||||
|
|
||||||
|
buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBlitFramebuffer(src_rect.left, src_rect.bottom, src_rect.right, src_rect.top, dst_rect.left,
|
||||||
|
dst_rect.bottom, dst_rect.right, dst_rect.top, buffers,
|
||||||
|
buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) {
|
CachedSurface::CachedSurface(const SurfaceParams& params) : params(params) {
|
||||||
texture.Create();
|
texture.Create();
|
||||||
const auto& rect{params.GetRect()};
|
const auto& rect{params.GetRect()};
|
||||||
|
@ -580,19 +634,25 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
|
||||||
if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none)
|
if (gpu.memory_manager->GpuToCpuAddress(params.addr) == boost::none)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
// Check for an exact match in existing surfaces
|
// Look up surface in the cache based on address
|
||||||
const auto& search{surface_cache.find(params.addr)};
|
const auto& search{surface_cache.find(params.addr)};
|
||||||
Surface surface;
|
Surface surface;
|
||||||
if (search != surface_cache.end()) {
|
if (search != surface_cache.end()) {
|
||||||
surface = search->second;
|
surface = search->second;
|
||||||
if (surface->GetSurfaceParams() != params || Settings::values.use_accurate_framebuffers) {
|
if (Settings::values.use_accurate_framebuffers) {
|
||||||
|
// If use_accurate_framebuffers is enabled, always load from memory
|
||||||
FlushSurface(surface);
|
FlushSurface(surface);
|
||||||
UnregisterSurface(surface);
|
UnregisterSurface(surface);
|
||||||
|
} else if (surface->GetSurfaceParams() != params) {
|
||||||
|
// If surface parameters changed, recreate the surface from the old one
|
||||||
|
return RecreateSurface(surface, params);
|
||||||
} else {
|
} else {
|
||||||
|
// Use the cached surface as-is
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No surface found - create a new one
|
||||||
surface = std::make_shared<CachedSurface>(params);
|
surface = std::make_shared<CachedSurface>(params);
|
||||||
RegisterSurface(surface);
|
RegisterSurface(surface);
|
||||||
LoadSurface(surface);
|
LoadSurface(surface);
|
||||||
|
@ -600,6 +660,27 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params) {
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
|
const SurfaceParams& new_params) {
|
||||||
|
// Verify surface is compatible for blitting
|
||||||
|
const auto& params{surface->GetSurfaceParams()};
|
||||||
|
ASSERT(params.type == new_params.type);
|
||||||
|
ASSERT(params.pixel_format == new_params.pixel_format);
|
||||||
|
ASSERT(params.component_type == new_params.component_type);
|
||||||
|
|
||||||
|
// Create a new surface with the new parameters, and blit the previous surface to it
|
||||||
|
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
|
||||||
|
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
|
||||||
|
new_surface->GetSurfaceParams().GetRect(), params.type, read_framebuffer.handle,
|
||||||
|
draw_framebuffer.handle);
|
||||||
|
|
||||||
|
// Update cache accordingly
|
||||||
|
UnregisterSurface(surface);
|
||||||
|
RegisterSurface(new_surface);
|
||||||
|
|
||||||
|
return new_surface;
|
||||||
|
}
|
||||||
|
|
||||||
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const {
|
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr cpu_addr) const {
|
||||||
// Tries to find the GPU address of a framebuffer based on the CPU address. This is because
|
// Tries to find the GPU address of a framebuffer based on the CPU address. This is because
|
||||||
// final output framebuffers are specified by CPU address, but internally our GPU cache uses
|
// final output framebuffers are specified by CPU address, but internally our GPU cache uses
|
||||||
|
|
|
@ -454,6 +454,9 @@ private:
|
||||||
void LoadSurface(const Surface& surface);
|
void LoadSurface(const Surface& surface);
|
||||||
Surface GetSurface(const SurfaceParams& params);
|
Surface GetSurface(const SurfaceParams& params);
|
||||||
|
|
||||||
|
/// Recreates a surface with new parameters
|
||||||
|
Surface RecreateSurface(const Surface& surface, const SurfaceParams& new_params);
|
||||||
|
|
||||||
/// Register surface into the cache
|
/// Register surface into the cache
|
||||||
void RegisterSurface(const Surface& surface);
|
void RegisterSurface(const Surface& surface);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue