diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 5e188d062e..09c2a810c3 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1616,19 +1616,17 @@ void GLGSRender::flip(int buffer) // Cleanup m_gl_texture_cache.on_frame_end(); - - m_rtts.free_invalidated(); m_vertex_cache->purge(); - if (m_framebuffer_cache.size() > 32) + auto removed_textures = m_rtts.free_invalidated(); + m_framebuffer_cache.remove_if([&](auto& fbo) { - for (auto &fbo : m_framebuffer_cache) - { - fbo.remove(); - } + if (fbo.deref_count >= 2) return true; // Remove if stale + if (fbo.references_any(removed_textures)) return true; // Remove if any of the attachments is invalid - m_framebuffer_cache.clear(); - } + fbo.deref_count++; + return false; + }); //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 9b19c86614..1b2f3d2548 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Emu/RSX/GSRender.h" #include "GLHelpers.h" #include "GLTexture.h" @@ -330,7 +330,7 @@ private: //buffer gl::fbo* m_draw_fbo = nullptr; - std::list m_framebuffer_cache; + 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 6e9ad3f783..29a47d3b8d 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.cpp +++ b/rpcs3/Emu/RSX/GL/GLHelpers.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "GLHelpers.h" #include "Utilities/Log.h" @@ -35,12 +35,16 @@ namespace gl switch (type) { case GL_DEBUG_TYPE_ERROR: + { LOG_ERROR(RSX, "%s", message); return; + } default: + { LOG_WARNING(RSX, "%s", message); return; } + } } #endif @@ -306,7 +310,7 @@ namespace gl return m_size; } - bool fbo::matches(std::array color_targets, GLuint depth_stencil_target) + bool fbo::matches(const std::array& color_targets, GLuint depth_stencil_target) const { for (u32 index = 0; index < 4; ++index) { @@ -317,7 +321,18 @@ namespace gl } const auto depth_resource = depth.resource_id() | depth_stencil.resource_id(); - return depth_resource == depth_stencil_target; + return (depth_resource == depth_stencil_target); + } + + bool fbo::references_any(const std::vector& resources) const + { + for (const auto &e : m_resource_bindings) + { + if (std::find(resources.begin(), resources.end(), e.second) != resources.end()) + return true; + } + + return false; } bool is_primitive_native(rsx::primitive_type in) diff --git a/rpcs3/Emu/RSX/GL/GLHelpers.h b/rpcs3/Emu/RSX/GL/GLHelpers.h index ffe71c40fd..8d289b78b4 100644 --- a/rpcs3/Emu/RSX/GL/GLHelpers.h +++ b/rpcs3/Emu/RSX/GL/GLHelpers.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -2234,7 +2234,8 @@ public: void set_extents(size2i extents); size2i get_extents() const; - bool matches(std::array color_targets, GLuint depth_stencil_target); + bool matches(const std::array& color_targets, GLuint depth_stencil_target) const; + bool references_any(const std::vector& resources) const; explicit operator bool() const { diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index 44fe5ef044..85fbcfb126 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "../rsx_methods.h" #include "GLGSRender.h" #include "Emu/System.h" @@ -294,7 +294,12 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk { if (fbo.matches(color_targets, depth_stencil_target)) { + fbo.reset_refs(); + m_draw_fbo = &fbo; + m_draw_fbo->bind(); + m_draw_fbo->set_extents({ (int)layout.width, (int)layout.height }); + framebuffer_status_valid = true; break; } @@ -327,43 +332,40 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk 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(); + 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; check_zcull_status(true); set_viewport(); diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index ddde8116bb..cd1d124b07 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "../Common/surface_store.h" #include "GLHelpers.h" #include "stdafx.h" @@ -131,6 +131,11 @@ namespace gl return (rsx::apply_resolution_scale(_width, true) == internal_width) && (rsx::apply_resolution_scale(_height, true) == internal_height); } }; + + struct framebuffer_holder : public gl::fbo, public rsx::ref_counted + { + using gl::fbo::fbo; + }; } struct gl_render_target_traits @@ -291,15 +296,21 @@ struct gl_render_target_traits struct gl_render_targets : public rsx::surface_store { - void free_invalidated() + std::vector free_invalidated() { + std::vector removed; invalidated_resources.remove_if([&](auto &rtt) { if (rtt->deref_count >= 2) + { + removed.push_back(rtt->id()); return true; + } rtt->deref_count++; return false; }); + + return removed; } };