gl: Fix problems with framebuffer reuse

- Matching attachments with resource id fails because drivers are reusing
  handles!
- Properly sets up stale fbo ref counting and removal
- Properly sets up resource reference test with subsequent removal to
  avoid using a broken fbo entry
This commit is contained in:
kd-11 2018-09-19 13:16:26 +03:00 committed by kd-11
parent fc486a1bac
commit 2b6e6a9ae9
6 changed files with 81 additions and 54 deletions

View File

@ -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;

View File

@ -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<gl::fbo> m_framebuffer_cache;
std::list<gl::framebuffer_holder> m_framebuffer_cache;
gl::fbo m_flip_fbo;
std::unique_ptr<gl::texture> m_flip_tex_color;

View File

@ -1,4 +1,4 @@
#include "stdafx.h"
#include "stdafx.h"
#include "GLHelpers.h"
#include "Utilities/Log.h"
@ -35,13 +35,17 @@ namespace gl
switch (type)
{
case GL_DEBUG_TYPE_ERROR:
{
LOG_ERROR(RSX, "%s", message);
return;
}
default:
{
LOG_WARNING(RSX, "%s", message);
return;
}
}
}
#endif
void enable_debugging()
@ -306,7 +310,7 @@ namespace gl
return m_size;
}
bool fbo::matches(std::array<GLuint, 4> color_targets, GLuint depth_stencil_target)
bool fbo::matches(const std::array<GLuint, 4>& 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<GLuint>& 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)

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <exception>
#include <string>
@ -2234,7 +2234,8 @@ public:
void set_extents(size2i extents);
size2i get_extents() const;
bool matches(std::array<GLuint, 4> color_targets, GLuint depth_stencil_target);
bool matches(const std::array<GLuint, 4>& color_targets, GLuint depth_stencil_target) const;
bool references_any(const std::vector<GLuint>& resources) const;
explicit operator bool() const
{

View File

@ -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,6 +332,7 @@ 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())
{
@ -359,12 +365,8 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
}
framebuffer_status_valid = m_draw_fbo->check();
}
if (!framebuffer_status_valid) return;
m_draw_fbo->bind();
check_zcull_status(true);
set_viewport();

View File

@ -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<gl_render_target_traits>
{
void free_invalidated()
std::vector<GLuint> free_invalidated()
{
std::vector<GLuint> 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;
}
};