gl: Reuse framebuffer resources

- WIP optimizations for GL backend
This commit is contained in:
kd-11 2018-08-09 00:48:56 +03:00 committed by kd-11
parent cca488d0cf
commit 8c93db342f
5 changed files with 139 additions and 47 deletions

View File

@ -269,7 +269,7 @@ void GLGSRender::end()
GLfloat colors[] = { 0.f, 0.f, 0.f, 0.f }; GLfloat colors[] = { 0.f, 0.f, 0.f, 0.f };
//It is impossible for the render target to be type A or B here (clear all would have been flagged) //It is impossible for the render target to be type A or B here (clear all would have been flagged)
for (auto &i : buffers_to_clear) for (auto &i : buffers_to_clear)
glClearBufferfv(draw_fbo.id(), i, colors); glClearBufferfv(m_draw_fbo->id(), i, colors);
} }
if (clear_depth) if (clear_depth)
@ -924,11 +924,13 @@ void GLGSRender::on_exit()
m_prog_buffer.clear(); m_prog_buffer.clear();
if (draw_fbo) for (auto &fbo : m_framebuffer_cache)
{ {
draw_fbo.remove(); fbo.remove();
} }
m_framebuffer_cache.clear();
if (m_flip_fbo) if (m_flip_fbo)
{ {
m_flip_fbo.remove(); m_flip_fbo.remove();
@ -1596,6 +1598,16 @@ void GLGSRender::flip(int buffer)
m_rtts.free_invalidated(); m_rtts.free_invalidated();
m_vertex_cache->purge(); m_vertex_cache->purge();
if (m_framebuffer_cache.size() > 32)
{
for (auto &fbo : m_framebuffer_cache)
{
fbo.remove();
}
m_framebuffer_cache.clear();
}
//If we are skipping the next frame, do not reset perf counters //If we are skipping the next frame, do not reset perf counters
if (skip_frame) return; if (skip_frame) return;

View File

@ -331,7 +331,8 @@ private:
draw_context_t m_decompiler_context; draw_context_t m_decompiler_context;
//buffer //buffer
gl::fbo draw_fbo; gl::fbo* m_draw_fbo = nullptr;
std::list<gl::fbo> m_framebuffer_cache;
gl::fbo m_flip_fbo; gl::fbo m_flip_fbo;
std::unique_ptr<gl::texture> m_flip_tex_color; std::unique_ptr<gl::texture> m_flip_tex_color;

View File

@ -306,6 +306,20 @@ namespace gl
return m_size; return m_size;
} }
bool fbo::matches(std::array<GLuint, 4> color_targets, GLuint depth_stencil_target)
{
for (u32 index = 0; index < 4; ++index)
{
if (color[index].resource_id() != color_targets[index])
{
return false;
}
}
const auto depth_resource = depth.resource_id() | depth_stencil.resource_id();
return depth_resource == depth_stencil_target;
}
bool is_primitive_native(rsx::primitive_type in) bool is_primitive_native(rsx::primitive_type in)
{ {
switch (in) switch (in)

View File

@ -2026,6 +2026,9 @@ public:
GLuint m_id = GL_NONE; GLuint m_id = GL_NONE;
size2i m_size; size2i m_size;
protected:
std::unordered_map<GLenum, GLuint> m_resource_bindings;
public: public:
fbo() = default; fbo() = default;
@ -2095,9 +2098,21 @@ public:
return m_id; return m_id;
} }
GLuint resource_id() const
{
const auto found = m_parent.m_resource_bindings.find(m_id);
if (found != m_parent.m_resource_bindings.end())
{
return found->second;
}
return GL_NONE;
}
void operator = (const rbo& rhs) void operator = (const rbo& rhs)
{ {
save_binding_state save(m_parent); save_binding_state save(m_parent);
m_parent.m_resource_bindings[m_id] = rhs.id();
glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_id, GL_RENDERBUFFER, rhs.id()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_id, GL_RENDERBUFFER, rhs.id());
} }
@ -2106,12 +2121,14 @@ public:
save_binding_state save(m_parent); save_binding_state save(m_parent);
verify(HERE), rhs.get_target() == texture::target::texture2D; verify(HERE), rhs.get_target() == texture::target::texture2D;
m_parent.m_resource_bindings[m_id] = rhs.id();
glFramebufferTexture2D(GL_FRAMEBUFFER, m_id, GL_TEXTURE_2D, rhs.id(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, m_id, GL_TEXTURE_2D, rhs.id(), 0);
} }
void operator = (const GLuint rhs) void operator = (const GLuint rhs)
{ {
save_binding_state save(m_parent); save_binding_state save(m_parent);
m_parent.m_resource_bindings[m_id] = rhs;
glFramebufferTexture2D(GL_FRAMEBUFFER, m_id, GL_TEXTURE_2D, rhs, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, m_id, GL_TEXTURE_2D, rhs, 0);
} }
}; };
@ -2200,6 +2217,8 @@ public:
void set_extents(size2i extents); void set_extents(size2i extents);
size2i get_extents() const; size2i get_extents() const;
bool matches(std::array<GLuint, 4> color_targets, GLuint depth_stencil_target);
explicit operator bool() const explicit operator bool() const
{ {
return created(); return created();

View File

@ -179,7 +179,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_rtts_dirty = true; m_rtts_dirty = true;
} }
if (draw_fbo && !m_rtts_dirty) if (m_draw_fbo && !m_rtts_dirty)
{ {
set_viewport(); set_viewport();
return; return;
@ -195,7 +195,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
return; return;
} }
if (draw_fbo && layout.ignore_change) if (m_draw_fbo && layout.ignore_change)
{ {
// Nothing has changed, we're still using the same framebuffer // Nothing has changed, we're still using the same framebuffer
// Update flags to match current // Update flags to match current
@ -218,13 +218,12 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_rtts.prepare_render_target(nullptr, layout.color_format, layout.depth_format, layout.width, layout.height, m_rtts.prepare_render_target(nullptr, layout.color_format, layout.depth_format, layout.width, layout.height,
layout.target, layout.color_addresses, layout.zeta_address); layout.target, layout.color_addresses, layout.zeta_address);
draw_fbo.recreate();
draw_fbo.bind();
draw_fbo.set_extents({ (int)layout.width, (int)layout.height });
bool old_format_found = false; bool old_format_found = false;
gl::texture::format old_format; gl::texture::format old_format;
std::array<GLuint, 4> color_targets;
GLuint depth_stencil_target;
const auto color_offsets = get_offsets(); const auto color_offsets = get_offsets();
const auto color_locations = get_locations(); const auto color_locations = get_locations();
@ -245,7 +244,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
if (std::get<0>(m_rtts.m_bound_render_targets[i])) if (std::get<0>(m_rtts.m_bound_render_targets[i]))
{ {
auto rtt = std::get<1>(m_rtts.m_bound_render_targets[i]); auto rtt = std::get<1>(m_rtts.m_bound_render_targets[i]);
draw_fbo.color[i] = *rtt; color_targets[i] = rtt->id();
rtt->set_rsx_pitch(layout.color_pitch[i]); rtt->set_rsx_pitch(layout.color_pitch[i]);
m_surface_info[i] = { layout.color_addresses[i], layout.actual_color_pitch[i], false, layout.color_format, layout.depth_format, layout.width, layout.height }; m_surface_info[i] = { layout.color_addresses[i], layout.actual_color_pitch[i], false, layout.color_format, layout.depth_format, layout.width, layout.height };
@ -256,7 +255,10 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_gl_texture_cache.tag_framebuffer(m_surface_info[i].address); m_gl_texture_cache.tag_framebuffer(m_surface_info[i].address);
} }
else else
{
color_targets[i] = GL_NONE;
m_surface_info[i] = {}; m_surface_info[i] = {};
}
} }
if (std::get<0>(m_rtts.m_bound_depth_stencil)) if (std::get<0>(m_rtts.m_bound_depth_stencil))
@ -271,10 +273,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
} }
auto ds = std::get<1>(m_rtts.m_bound_depth_stencil); auto ds = std::get<1>(m_rtts.m_bound_depth_stencil);
if (layout.depth_format == rsx::surface_depth_format::z24s8) depth_stencil_target = ds->id();
draw_fbo.depth_stencil = *ds;
else
draw_fbo.depth = *ds;
std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch()); std::get<1>(m_rtts.m_bound_depth_stencil)->set_rsx_pitch(rsx::method_registers.surface_z_pitch());
m_depth_surface_info = { layout.zeta_address, layout.actual_zeta_pitch, true, layout.color_format, layout.depth_format, layout.width, layout.height }; m_depth_surface_info = { layout.zeta_address, layout.actual_zeta_pitch, true, layout.color_format, layout.depth_format, layout.width, layout.height };
@ -284,44 +283,91 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
m_gl_texture_cache.tag_framebuffer(layout.zeta_address); m_gl_texture_cache.tag_framebuffer(layout.zeta_address);
} }
else else
{
depth_stencil_target = GL_NONE;
m_depth_surface_info = {}; m_depth_surface_info = {};
}
framebuffer_status_valid = draw_fbo.check(); framebuffer_status_valid = false;
for (auto &fbo : m_framebuffer_cache)
{
if (fbo.matches(color_targets, depth_stencil_target))
{
m_draw_fbo = &fbo;
framebuffer_status_valid = true;
break;
}
}
if (!framebuffer_status_valid)
{
m_framebuffer_cache.emplace_back();
m_draw_fbo = &m_framebuffer_cache.back();
m_draw_fbo->create();
m_draw_fbo->bind();
m_draw_fbo->set_extents({ (int)layout.width, (int)layout.height });
for (int i = 0; i < 4; ++i)
{
if (color_targets[i])
{
m_draw_fbo->color[i] = color_targets[i];
}
}
if (depth_stencil_target)
{
if (layout.depth_format == rsx::surface_depth_format::z24s8)
{
m_draw_fbo->depth_stencil = depth_stencil_target;
}
else
{
m_draw_fbo->depth = depth_stencil_target;
}
}
switch (rsx::method_registers.surface_color_target())
{
case rsx::surface_target::none: break;
case rsx::surface_target::surface_a:
m_draw_fbo->draw_buffer(m_draw_fbo->color[0]);
m_draw_fbo->read_buffer(m_draw_fbo->color[0]);
break;
case rsx::surface_target::surface_b:
m_draw_fbo->draw_buffer(m_draw_fbo->color[1]);
m_draw_fbo->read_buffer(m_draw_fbo->color[1]);
break;
case rsx::surface_target::surfaces_a_b:
m_draw_fbo->draw_buffers({ m_draw_fbo->color[0], m_draw_fbo->color[1] });
m_draw_fbo->read_buffer(m_draw_fbo->color[0]);
break;
case rsx::surface_target::surfaces_a_b_c:
m_draw_fbo->draw_buffers({ m_draw_fbo->color[0], m_draw_fbo->color[1], m_draw_fbo->color[2] });
m_draw_fbo->read_buffer(m_draw_fbo->color[0]);
break;
case rsx::surface_target::surfaces_a_b_c_d:
m_draw_fbo->draw_buffers({ m_draw_fbo->color[0], m_draw_fbo->color[1], m_draw_fbo->color[2], m_draw_fbo->color[3] });
m_draw_fbo->read_buffer(m_draw_fbo->color[0]);
break;
}
framebuffer_status_valid = m_draw_fbo->check();
}
if (!framebuffer_status_valid) return; if (!framebuffer_status_valid) return;
m_draw_fbo->bind();
check_zcull_status(true); check_zcull_status(true);
set_viewport(); set_viewport();
switch (rsx::method_registers.surface_color_target())
{
case rsx::surface_target::none: break;
case rsx::surface_target::surface_a:
draw_fbo.draw_buffer(draw_fbo.color[0]);
draw_fbo.read_buffer(draw_fbo.color[0]);
break;
case rsx::surface_target::surface_b:
draw_fbo.draw_buffer(draw_fbo.color[1]);
draw_fbo.read_buffer(draw_fbo.color[1]);
break;
case rsx::surface_target::surfaces_a_b:
draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1] });
draw_fbo.read_buffer(draw_fbo.color[0]);
break;
case rsx::surface_target::surfaces_a_b_c:
draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2] });
draw_fbo.read_buffer(draw_fbo.color[0]);
break;
case rsx::surface_target::surfaces_a_b_c_d:
draw_fbo.draw_buffers({ draw_fbo.color[0], draw_fbo.color[1], draw_fbo.color[2], draw_fbo.color[3] });
draw_fbo.read_buffer(draw_fbo.color[0]);
break;
}
m_gl_texture_cache.clear_ro_tex_invalidate_intr(); m_gl_texture_cache.clear_ro_tex_invalidate_intr();
//Mark buffer regions as NO_ACCESS on Cell visible side //Mark buffer regions as NO_ACCESS on Cell visible side
@ -373,7 +419,7 @@ std::array<std::vector<gsl::byte>, 2> GLGSRender::copy_depth_stencil_buffer_to_m
void GLGSRender::read_buffers() void GLGSRender::read_buffers()
{ {
if (!draw_fbo) if (!m_draw_fbo)
return; return;
glDisable(GL_STENCIL_TEST); glDisable(GL_STENCIL_TEST);