From 8c93db342f12104c7efdcd689d22a4bd2a840a83 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 9 Aug 2018 00:48:56 +0300 Subject: [PATCH] gl: Reuse framebuffer resources - WIP optimizations for GL backend --- rpcs3/Emu/RSX/GL/GLGSRender.cpp | 18 +++- rpcs3/Emu/RSX/GL/GLGSRender.h | 3 +- rpcs3/Emu/RSX/GL/GLHelpers.cpp | 14 +++ rpcs3/Emu/RSX/GL/GLHelpers.h | 19 ++++ rpcs3/Emu/RSX/GL/GLRenderTargets.cpp | 132 ++++++++++++++++++--------- 5 files changed, 139 insertions(+), 47 deletions(-) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 2a1fe879dd..853360aca2 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -269,7 +269,7 @@ void GLGSRender::end() 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) for (auto &i : buffers_to_clear) - glClearBufferfv(draw_fbo.id(), i, colors); + glClearBufferfv(m_draw_fbo->id(), i, colors); } if (clear_depth) @@ -924,11 +924,13 @@ void GLGSRender::on_exit() 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) { m_flip_fbo.remove(); @@ -1596,6 +1598,16 @@ void GLGSRender::flip(int buffer) m_rtts.free_invalidated(); 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 (skip_frame) return; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index ef9928e856..5567de229e 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -331,7 +331,8 @@ private: draw_context_t m_decompiler_context; //buffer - gl::fbo draw_fbo; + gl::fbo* m_draw_fbo = nullptr; + std::list m_framebuffer_cache; gl::fbo m_flip_fbo; std::unique_ptr m_flip_tex_color; diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.cpp b/rpcs3/Emu/RSX/GL/GLHelpers.cpp index 31ca4a8ce5..6e9ad3f783 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.cpp +++ b/rpcs3/Emu/RSX/GL/GLHelpers.cpp @@ -306,6 +306,20 @@ namespace gl return m_size; } + bool fbo::matches(std::array 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) { switch (in) diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index 4ac36582fa..dcd5b859b2 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -2026,6 +2026,9 @@ public: GLuint m_id = GL_NONE; size2i m_size; + protected: + std::unordered_map m_resource_bindings; + public: fbo() = default; @@ -2095,9 +2098,21 @@ public: 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) { save_binding_state save(m_parent); + m_parent.m_resource_bindings[m_id] = rhs.id(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, m_id, GL_RENDERBUFFER, rhs.id()); } @@ -2106,12 +2121,14 @@ public: save_binding_state save(m_parent); 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); } void operator = (const GLuint rhs) { save_binding_state save(m_parent); + m_parent.m_resource_bindings[m_id] = rhs; glFramebufferTexture2D(GL_FRAMEBUFFER, m_id, GL_TEXTURE_2D, rhs, 0); } }; @@ -2200,6 +2217,8 @@ public: void set_extents(size2i extents); size2i get_extents() const; + bool matches(std::array color_targets, GLuint depth_stencil_target); + explicit operator bool() const { return created(); diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index 81f226b9a0..44fe5ef044 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -179,7 +179,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk m_rtts_dirty = true; } - if (draw_fbo && !m_rtts_dirty) + if (m_draw_fbo && !m_rtts_dirty) { set_viewport(); return; @@ -195,7 +195,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk return; } - if (draw_fbo && layout.ignore_change) + if (m_draw_fbo && layout.ignore_change) { // Nothing has changed, we're still using the same framebuffer // 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, 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; gl::texture::format old_format; + std::array color_targets; + GLuint depth_stencil_target; + const auto color_offsets = get_offsets(); 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])) { 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]); 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); } else + { + color_targets[i] = GL_NONE; m_surface_info[i] = {}; + } } 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); - if (layout.depth_format == rsx::surface_depth_format::z24s8) - draw_fbo.depth_stencil = *ds; - else - draw_fbo.depth = *ds; + depth_stencil_target = ds->id(); 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 }; @@ -284,44 +283,91 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk m_gl_texture_cache.tag_framebuffer(layout.zeta_address); } else + { + depth_stencil_target = GL_NONE; 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; + m_draw_fbo->bind(); + check_zcull_status(true); 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(); //Mark buffer regions as NO_ACCESS on Cell visible side @@ -373,7 +419,7 @@ std::array, 2> GLGSRender::copy_depth_stencil_buffer_to_m void GLGSRender::read_buffers() { - if (!draw_fbo) + if (!m_draw_fbo) return; glDisable(GL_STENCIL_TEST);