mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 06:21:26 +12:00
[WIP] rsx: Use a sane reference counting model
This commit is contained in:
parent
e3cf3ab6b8
commit
b840f6da28
9 changed files with 193 additions and 44 deletions
|
@ -134,12 +134,24 @@ namespace rsx
|
||||||
GcmTileInfo *tile = nullptr;
|
GcmTileInfo *tile = nullptr;
|
||||||
rsx::surface_antialiasing write_aa_mode = rsx::surface_antialiasing::center_1_sample;
|
rsx::surface_antialiasing write_aa_mode = rsx::surface_antialiasing::center_1_sample;
|
||||||
|
|
||||||
|
render_target_descriptor() {}
|
||||||
|
|
||||||
|
virtual ~render_target_descriptor()
|
||||||
|
{
|
||||||
|
if (old_contents)
|
||||||
|
{
|
||||||
|
// Cascade resource derefs
|
||||||
|
LOG_ERROR(RSX, "Resource was destroyed whilst holding a resource reference!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual image_storage_type get_surface() = 0;
|
virtual image_storage_type get_surface() = 0;
|
||||||
virtual u16 get_surface_width() const = 0;
|
virtual u16 get_surface_width() const = 0;
|
||||||
virtual u16 get_surface_height() const = 0;
|
virtual u16 get_surface_height() const = 0;
|
||||||
virtual u16 get_rsx_pitch() const = 0;
|
virtual u16 get_rsx_pitch() const = 0;
|
||||||
virtual u16 get_native_pitch() const = 0;
|
virtual u16 get_native_pitch() const = 0;
|
||||||
virtual bool is_depth_surface() const = 0;
|
virtual bool is_depth_surface() const = 0;
|
||||||
|
virtual void release_ref(image_storage_type) const = 0;
|
||||||
|
|
||||||
u8 get_bpp() const
|
u8 get_bpp() const
|
||||||
{
|
{
|
||||||
|
@ -179,9 +191,17 @@ namespace rsx
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_rw_barrier()
|
||||||
|
{
|
||||||
|
release_ref(old_contents.source);
|
||||||
|
old_contents = {};
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set_old_contents(T* other)
|
void set_old_contents(T* other)
|
||||||
{
|
{
|
||||||
|
verify(HERE), !old_contents;
|
||||||
|
|
||||||
if (!other || other->get_rsx_pitch() != this->get_rsx_pitch())
|
if (!other || other->get_rsx_pitch() != this->get_rsx_pitch())
|
||||||
{
|
{
|
||||||
old_contents = {};
|
old_contents = {};
|
||||||
|
@ -190,14 +210,29 @@ namespace rsx
|
||||||
|
|
||||||
old_contents = {};
|
old_contents = {};
|
||||||
old_contents.source = other;
|
old_contents.source = other;
|
||||||
|
other->add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void set_old_contents_region(const T& region, bool normalized)
|
void set_old_contents_region(const T& region, bool normalized)
|
||||||
{
|
{
|
||||||
|
if (old_contents)
|
||||||
|
{
|
||||||
|
// This can happen when doing memory splits
|
||||||
|
auto old_surface = static_cast<decltype(region.source)>(old_contents.source);
|
||||||
|
if (old_surface->last_use_tag > region.source->last_use_tag)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_rw_barrier();
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This method will not perform pitch verification!
|
// NOTE: This method will not perform pitch verification!
|
||||||
verify(HERE), region.source;
|
verify(HERE), !old_contents, region.source, region.source != this;
|
||||||
|
|
||||||
old_contents = region.template cast<image_storage_type>();
|
old_contents = region.template cast<image_storage_type>();
|
||||||
|
region.source->add_ref();
|
||||||
|
|
||||||
// Reverse normalization process if needed
|
// Reverse normalization process if needed
|
||||||
if (normalized)
|
if (normalized)
|
||||||
|
@ -298,7 +333,11 @@ namespace rsx
|
||||||
|
|
||||||
read_aa_mode = write_aa_mode;
|
read_aa_mode = write_aa_mode;
|
||||||
dirty = false;
|
dirty = false;
|
||||||
old_contents = {};
|
|
||||||
|
if (old_contents.source)
|
||||||
|
{
|
||||||
|
clear_rw_barrier();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the rect area occupied by this surface expressed as an 8bpp image with no AA
|
// Returns the rect area occupied by this surface expressed as an 8bpp image with no AA
|
||||||
|
@ -712,7 +751,9 @@ namespace rsx
|
||||||
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height, true))
|
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height, true))
|
||||||
{
|
{
|
||||||
new_surface_storage = std::move(rtt);
|
new_surface_storage = std::move(rtt);
|
||||||
|
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
|
||||||
|
Traits::notify_surface_reused(new_surface_storage);
|
||||||
|
#endif
|
||||||
if (old_surface)
|
if (old_surface)
|
||||||
{
|
{
|
||||||
// Exchange this surface with the invalidated one
|
// Exchange this surface with the invalidated one
|
||||||
|
@ -843,7 +884,9 @@ namespace rsx
|
||||||
if (Traits::ds_has_format_width_height(ds, depth_format, width, height, true))
|
if (Traits::ds_has_format_width_height(ds, depth_format, width, height, true))
|
||||||
{
|
{
|
||||||
new_surface_storage = std::move(ds);
|
new_surface_storage = std::move(ds);
|
||||||
|
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
|
||||||
|
Traits::notify_surface_reused(new_surface_storage);
|
||||||
|
#endif
|
||||||
if (old_surface)
|
if (old_surface)
|
||||||
{
|
{
|
||||||
//Exchange this surface with the invalidated one
|
//Exchange this surface with the invalidated one
|
||||||
|
@ -1440,5 +1483,29 @@ namespace rsx
|
||||||
{
|
{
|
||||||
cache_tag = rsx::get_shared_tag();
|
cache_tag = rsx::get_shared_tag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void invalidate_all()
|
||||||
|
{
|
||||||
|
// Unbind and invalidate all resources
|
||||||
|
auto free_resource_list = [&](auto &data)
|
||||||
|
{
|
||||||
|
for (auto &e : data)
|
||||||
|
{
|
||||||
|
Traits::notify_surface_invalidated(e.second);
|
||||||
|
invalidated_resources.push_back(std::move(e.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
free_resource_list(m_render_targets_storage);
|
||||||
|
free_resource_list(m_depth_stencil_storage);
|
||||||
|
|
||||||
|
m_bound_depth_stencil = std::make_pair(0, nullptr);
|
||||||
|
for (auto &rtt : m_bound_render_targets)
|
||||||
|
{
|
||||||
|
rtt = std::make_pair(0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1013,6 +1013,7 @@ void GLGSRender::on_exit()
|
||||||
zcull_ctrl.release();
|
zcull_ctrl.release();
|
||||||
|
|
||||||
m_prog_buffer.clear();
|
m_prog_buffer.clear();
|
||||||
|
m_rtts.destroy();
|
||||||
|
|
||||||
for (auto &fbo : m_framebuffer_cache)
|
for (auto &fbo : m_framebuffer_cache)
|
||||||
{
|
{
|
||||||
|
@ -1800,10 +1801,9 @@ void GLGSRender::flip(int buffer, bool emu_flip)
|
||||||
auto removed_textures = m_rtts.free_invalidated();
|
auto removed_textures = m_rtts.free_invalidated();
|
||||||
m_framebuffer_cache.remove_if([&](auto& fbo)
|
m_framebuffer_cache.remove_if([&](auto& fbo)
|
||||||
{
|
{
|
||||||
if (fbo.deref_count >= 2) return true; // Remove if stale
|
if (fbo.unused_check_count() >= 2) return true; // Remove if stale
|
||||||
if (fbo.references_any(removed_textures)) return true; // Remove if any of the attachments is invalid
|
if (fbo.references_any(removed_textures)) return true; // Remove if any of the attachments is invalid
|
||||||
|
|
||||||
fbo.deref_count++;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -298,11 +298,17 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
|
||||||
|
|
||||||
framebuffer_status_valid = false;
|
framebuffer_status_valid = false;
|
||||||
|
|
||||||
|
if (m_draw_fbo)
|
||||||
|
{
|
||||||
|
// Release resource
|
||||||
|
static_cast<gl::framebuffer_holder*>(m_draw_fbo)->release();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &fbo : m_framebuffer_cache)
|
for (auto &fbo : m_framebuffer_cache)
|
||||||
{
|
{
|
||||||
if (fbo.matches(color_targets, depth_stencil_target))
|
if (fbo.matches(color_targets, depth_stencil_target))
|
||||||
{
|
{
|
||||||
fbo.reset_refs();
|
fbo.add_ref();
|
||||||
|
|
||||||
m_draw_fbo = &fbo;
|
m_draw_fbo = &fbo;
|
||||||
m_draw_fbo->bind();
|
m_draw_fbo->bind();
|
||||||
|
@ -316,6 +322,8 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
|
||||||
if (!framebuffer_status_valid)
|
if (!framebuffer_status_valid)
|
||||||
{
|
{
|
||||||
m_framebuffer_cache.emplace_back();
|
m_framebuffer_cache.emplace_back();
|
||||||
|
m_framebuffer_cache.back().add_ref();
|
||||||
|
|
||||||
m_draw_fbo = &m_framebuffer_cache.back();
|
m_draw_fbo = &m_framebuffer_cache.back();
|
||||||
m_draw_fbo->create();
|
m_draw_fbo->create();
|
||||||
m_draw_fbo->bind();
|
m_draw_fbo->bind();
|
||||||
|
@ -609,6 +617,8 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, bool force_init
|
||||||
if (!rsx::pitch_compatible(this, src_texture))
|
if (!rsx::pitch_compatible(this, src_texture))
|
||||||
{
|
{
|
||||||
LOG_TRACE(RSX, "Pitch mismatch, could not transfer inherited memory");
|
LOG_TRACE(RSX, "Pitch mismatch, could not transfer inherited memory");
|
||||||
|
|
||||||
|
clear_rw_barrier();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,11 @@ namespace gl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release_ref(texture* t) const override
|
||||||
|
{
|
||||||
|
static_cast<gl::render_target*>(t)->release();
|
||||||
|
}
|
||||||
|
|
||||||
texture* get_surface() override
|
texture* get_surface() override
|
||||||
{
|
{
|
||||||
return (gl::texture*)this;
|
return (gl::texture*)this;
|
||||||
|
@ -184,6 +189,7 @@ struct gl_render_target_traits
|
||||||
|
|
||||||
result->set_cleared(false);
|
result->set_cleared(false);
|
||||||
result->queue_tag(address);
|
result->queue_tag(address);
|
||||||
|
result->add_ref();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +215,7 @@ struct gl_render_target_traits
|
||||||
|
|
||||||
result->set_cleared(false);
|
result->set_cleared(false);
|
||||||
result->queue_tag(address);
|
result->queue_tag(address);
|
||||||
|
result->add_ref();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +232,7 @@ struct gl_render_target_traits
|
||||||
const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height());
|
const auto new_h = rsx::apply_resolution_scale(prev.height, true, ref->get_surface_height());
|
||||||
|
|
||||||
sink.reset(new gl::render_target(new_w, new_h, internal_format));
|
sink.reset(new gl::render_target(new_w, new_h, internal_format));
|
||||||
|
sink->add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev.target = sink.get();
|
prev.target = sink.get();
|
||||||
|
@ -257,10 +265,10 @@ struct gl_render_target_traits
|
||||||
info->bpp = surface->get_bpp();
|
info->bpp = surface->get_bpp();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_rtt_for_drawing(gl::command_context&, gl::render_target *rtt) { rtt->reset_refs(); }
|
static void prepare_rtt_for_drawing(gl::command_context&, gl::render_target*) {}
|
||||||
static void prepare_rtt_for_sampling(gl::command_context&, gl::render_target*) {}
|
static void prepare_rtt_for_sampling(gl::command_context&, gl::render_target*) {}
|
||||||
|
|
||||||
static void prepare_ds_for_drawing(gl::command_context&, gl::render_target *ds) { ds->reset_refs(); }
|
static void prepare_ds_for_drawing(gl::command_context&, gl::render_target*) {}
|
||||||
static void prepare_ds_for_sampling(gl::command_context&, gl::render_target*) {}
|
static void prepare_ds_for_sampling(gl::command_context&, gl::render_target*) {}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -279,8 +287,11 @@ struct gl_render_target_traits
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void notify_surface_invalidated(const std::unique_ptr<gl::render_target>&)
|
void notify_surface_invalidated(const std::unique_ptr<gl::render_target>& surface)
|
||||||
{}
|
{
|
||||||
|
if (surface->old_contents) surface->clear_rw_barrier();
|
||||||
|
surface->release();
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void notify_surface_persist(const std::unique_ptr<gl::render_target>& surface)
|
void notify_surface_persist(const std::unique_ptr<gl::render_target>& surface)
|
||||||
|
@ -288,24 +299,30 @@ struct gl_render_target_traits
|
||||||
surface->save_aa_mode();
|
surface->save_aa_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void notify_surface_reused(const std::unique_ptr<gl::render_target>& surface)
|
||||||
|
{
|
||||||
|
surface->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false)
|
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false)
|
||||||
{
|
{
|
||||||
if (check_refs) //TODO
|
if (check_refs && rtt->has_refs())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto internal_fmt = rsx::internals::sized_internal_format(format);
|
const auto internal_fmt = rsx::internals::sized_internal_format(format);
|
||||||
return rtt->get_internal_format() == internal_fmt && rtt->matches_dimensions((u16)width, (u16)height);
|
return rtt->get_internal_format() == internal_fmt && rtt->matches_dimensions((u16)width, (u16)height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_depth_format, size_t width, size_t height, bool check_refs=false)
|
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &ds, rsx::surface_depth_format format, size_t width, size_t height, bool check_refs=false)
|
||||||
{
|
{
|
||||||
if (check_refs) //TODO
|
if (check_refs && ds->has_refs())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: check format
|
const auto internal_fmt = rsx::internals::surface_depth_format_to_gl(format).internal_format;
|
||||||
return rtt->matches_dimensions((u16)width, (u16)height);
|
return ds->get_internal_format() == internal_fmt && ds->matches_dimensions((u16)width, (u16)height);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note : pbo breaks fbo here so use classic texture copy
|
// Note : pbo breaks fbo here so use classic texture copy
|
||||||
|
@ -353,18 +370,23 @@ struct gl_render_target_traits
|
||||||
|
|
||||||
struct gl_render_targets : public rsx::surface_store<gl_render_target_traits>
|
struct gl_render_targets : public rsx::surface_store<gl_render_target_traits>
|
||||||
{
|
{
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
invalidate_all();
|
||||||
|
invalidated_resources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<GLuint> free_invalidated()
|
std::vector<GLuint> free_invalidated()
|
||||||
{
|
{
|
||||||
std::vector<GLuint> removed;
|
std::vector<GLuint> removed;
|
||||||
invalidated_resources.remove_if([&](auto &rtt)
|
invalidated_resources.remove_if([&](auto &rtt)
|
||||||
{
|
{
|
||||||
if (rtt->deref_count >= 2)
|
if (rtt->unused_check_count() >= 2)
|
||||||
{
|
{
|
||||||
removed.push_back(rtt->id());
|
removed.push_back(rtt->id());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtt->deref_count++;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -2334,8 +2334,7 @@ void VKGSRender::advance_queued_frames()
|
||||||
//Remove stale framebuffers. Ref counted to prevent use-after-free
|
//Remove stale framebuffers. Ref counted to prevent use-after-free
|
||||||
m_framebuffers_to_clean.remove_if([](std::unique_ptr<vk::framebuffer_holder>& fbo)
|
m_framebuffers_to_clean.remove_if([](std::unique_ptr<vk::framebuffer_holder>& fbo)
|
||||||
{
|
{
|
||||||
if (fbo->deref_count >= 2) return true;
|
if (fbo->unused_check_count() >= 2) return true;
|
||||||
fbo->deref_count++;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3102,17 +3101,23 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||||
auto vk_depth_format = (layout.zeta_address == 0) ? VK_FORMAT_UNDEFINED : vk::get_compatible_depth_surface_format(m_device->get_formats_support(), layout.depth_format);
|
auto vk_depth_format = (layout.zeta_address == 0) ? VK_FORMAT_UNDEFINED : vk::get_compatible_depth_surface_format(m_device->get_formats_support(), layout.depth_format);
|
||||||
m_current_renderpass_id = vk::get_render_pass_location(vk::get_compatible_surface_format(layout.color_format).first, vk_depth_format, (u8)m_draw_buffers.size());
|
m_current_renderpass_id = vk::get_render_pass_location(vk::get_compatible_surface_format(layout.color_format).first, vk_depth_format, (u8)m_draw_buffers.size());
|
||||||
|
|
||||||
//Search old framebuffers for this same configuration
|
// Search old framebuffers for this same configuration
|
||||||
bool framebuffer_found = false;
|
bool framebuffer_found = false;
|
||||||
const auto fbo_width = rsx::apply_resolution_scale(layout.width, true);
|
const auto fbo_width = rsx::apply_resolution_scale(layout.width, true);
|
||||||
const auto fbo_height = rsx::apply_resolution_scale(layout.height, true);
|
const auto fbo_height = rsx::apply_resolution_scale(layout.height, true);
|
||||||
|
|
||||||
|
if (m_draw_fbo)
|
||||||
|
{
|
||||||
|
// Release old ref
|
||||||
|
m_draw_fbo->release();
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &fbo : m_framebuffers_to_clean)
|
for (auto &fbo : m_framebuffers_to_clean)
|
||||||
{
|
{
|
||||||
if (fbo->matches(bound_images, fbo_width, fbo_height))
|
if (fbo->matches(bound_images, fbo_width, fbo_height))
|
||||||
{
|
{
|
||||||
m_draw_fbo.swap(fbo);
|
m_draw_fbo.swap(fbo);
|
||||||
m_draw_fbo->reset_refs();
|
m_draw_fbo->add_ref();
|
||||||
framebuffer_found = true;
|
framebuffer_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3159,6 +3164,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
|
||||||
m_framebuffers_to_clean.push_back(std::move(m_draw_fbo));
|
m_framebuffers_to_clean.push_back(std::move(m_draw_fbo));
|
||||||
|
|
||||||
m_draw_fbo.reset(new vk::framebuffer_holder(*m_device, current_render_pass, fbo_width, fbo_height, std::move(fbo_images)));
|
m_draw_fbo.reset(new vk::framebuffer_holder(*m_device, current_render_pass, fbo_width, fbo_height, std::move(fbo_images)));
|
||||||
|
m_draw_fbo->add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
set_viewport();
|
set_viewport();
|
||||||
|
@ -3199,10 +3205,10 @@ void VKGSRender::reinitialize_swapchain()
|
||||||
present(&ctx);
|
present(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Remove any old refs to the old images as they are about to be destroyed
|
// Remove any old refs to the old images as they are about to be destroyed
|
||||||
m_framebuffers_to_clean.clear();
|
//m_framebuffers_to_clean;
|
||||||
|
|
||||||
//Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
// Rebuild swapchain. Old swapchain destruction is handled by the init_swapchain call
|
||||||
if (!m_swapchain->init(new_width, new_height))
|
if (!m_swapchain->init(new_width, new_height))
|
||||||
{
|
{
|
||||||
LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", new_width, new_height);
|
LOG_WARNING(RSX, "Swapchain initialization failed. Request ignored [%dx%d]", new_width, new_height);
|
||||||
|
@ -3539,7 +3545,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
||||||
if (fbo->attachments[0]->info.image == target_image)
|
if (fbo->attachments[0]->info.image == target_image)
|
||||||
{
|
{
|
||||||
direct_fbo.swap(fbo);
|
direct_fbo.swap(fbo);
|
||||||
direct_fbo->reset_refs();
|
direct_fbo->add_ref();
|
||||||
m_framebuffers_to_clean.erase(It);
|
m_framebuffers_to_clean.erase(It);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3549,6 +3555,7 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
||||||
{
|
{
|
||||||
swap_image_view.push_back(std::make_unique<vk::image_view>(*m_device, target_image, VK_IMAGE_VIEW_TYPE_2D, m_swapchain->get_surface_format(), vk::default_component_map(), subres));
|
swap_image_view.push_back(std::make_unique<vk::image_view>(*m_device, target_image, VK_IMAGE_VIEW_TYPE_2D, m_swapchain->get_surface_format(), vk::default_component_map(), subres));
|
||||||
direct_fbo.reset(new vk::framebuffer_holder(*m_device, single_target_pass, m_client_width, m_client_height, std::move(swap_image_view)));
|
direct_fbo.reset(new vk::framebuffer_holder(*m_device, single_target_pass, m_client_width, m_client_height, std::move(swap_image_view)));
|
||||||
|
direct_fbo->add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_overlay)
|
if (has_overlay)
|
||||||
|
@ -3588,6 +3595,8 @@ void VKGSRender::flip(int buffer, bool emu_flip)
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, present_layout, subres);
|
vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, present_layout, subres);
|
||||||
|
|
||||||
|
direct_fbo->release();
|
||||||
m_framebuffers_to_clean.push_back(std::move(direct_fbo));
|
m_framebuffers_to_clean.push_back(std::move(direct_fbo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,7 @@ namespace vk
|
||||||
auto fbo = It->get();
|
auto fbo = It->get();
|
||||||
if (fbo->matches(test, target->width(), target->height()))
|
if (fbo->matches(test, target->width(), target->height()))
|
||||||
{
|
{
|
||||||
fbo->deref_count = 0;
|
fbo->add_ref();
|
||||||
return fbo;
|
return fbo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -338,6 +338,7 @@ namespace vk
|
||||||
auto result = fbo.get();
|
auto result = fbo.get();
|
||||||
framebuffer_resources.push_back(std::move(fbo));
|
framebuffer_resources.push_back(std::move(fbo));
|
||||||
|
|
||||||
|
result->add_ref();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -381,7 +382,10 @@ namespace vk
|
||||||
void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, const std::vector<VkImageView>& src, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, const std::vector<VkImageView>& src, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
||||||
{
|
{
|
||||||
vk::framebuffer *fbo = get_framebuffer(target, render_pass, framebuffer_resources);
|
vk::framebuffer *fbo = get_framebuffer(target, render_pass, framebuffer_resources);
|
||||||
|
|
||||||
run(cmd, w, h, fbo, src, render_pass);
|
run(cmd, w, h, fbo, src, render_pass);
|
||||||
|
|
||||||
|
static_cast<vk::framebuffer_holder*>(fbo)->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, VkImageView src, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
void run(vk::command_buffer &cmd, u16 w, u16 h, vk::image* target, VkImageView src, VkRenderPass render_pass, std::list<std::unique_ptr<vk::framebuffer_holder>>& framebuffer_resources)
|
||||||
|
|
|
@ -53,6 +53,11 @@ namespace vk
|
||||||
return !!(aspect() & VK_IMAGE_ASPECT_DEPTH_BIT);
|
return !!(aspect() & VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void release_ref(vk::image* t) const override
|
||||||
|
{
|
||||||
|
static_cast<vk::render_target*>(t)->release();
|
||||||
|
}
|
||||||
|
|
||||||
bool matches_dimensions(u16 _width, u16 _height) const
|
bool matches_dimensions(u16 _width, u16 _height) const
|
||||||
{
|
{
|
||||||
//Use forward scaling to account for rounding and clamping errors
|
//Use forward scaling to account for rounding and clamping errors
|
||||||
|
@ -100,6 +105,8 @@ namespace vk
|
||||||
if (!rsx::pitch_compatible(this, src_texture))
|
if (!rsx::pitch_compatible(this, src_texture))
|
||||||
{
|
{
|
||||||
LOG_TRACE(RSX, "Pitch mismatch, could not transfer inherited memory");
|
LOG_TRACE(RSX, "Pitch mismatch, could not transfer inherited memory");
|
||||||
|
|
||||||
|
clear_rw_barrier();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +204,7 @@ namespace rsx
|
||||||
rtt->queue_tag(address);
|
rtt->queue_tag(address);
|
||||||
rtt->dirty = true;
|
rtt->dirty = true;
|
||||||
|
|
||||||
|
rtt->add_ref();
|
||||||
return rtt;
|
return rtt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +247,7 @@ namespace rsx
|
||||||
ds->queue_tag(address);
|
ds->queue_tag(address);
|
||||||
ds->dirty = true;
|
ds->dirty = true;
|
||||||
|
|
||||||
|
ds->add_ref();
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +272,8 @@ namespace rsx
|
||||||
VK_IMAGE_TILING_OPTIMAL,
|
VK_IMAGE_TILING_OPTIMAL,
|
||||||
ref->info.usage,
|
ref->info.usage,
|
||||||
ref->info.flags));
|
ref->info.flags));
|
||||||
|
|
||||||
|
sink->add_ref();
|
||||||
}
|
}
|
||||||
|
|
||||||
prev.target = sink.get();
|
prev.target = sink.get();
|
||||||
|
@ -300,9 +311,6 @@ namespace rsx
|
||||||
static void prepare_rtt_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
|
static void prepare_rtt_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
|
||||||
{
|
{
|
||||||
surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
surface->change_layout(cmd, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
//Reset deref count
|
|
||||||
surface->deref_count = 0;
|
|
||||||
surface->frame_tag = 0;
|
surface->frame_tag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,9 +322,6 @@ namespace rsx
|
||||||
static void prepare_ds_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
|
static void prepare_ds_for_drawing(vk::command_buffer& cmd, vk::render_target *surface)
|
||||||
{
|
{
|
||||||
surface->change_layout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
surface->change_layout(cmd, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||||
|
|
||||||
//Reset deref count
|
|
||||||
surface->deref_count = 0;
|
|
||||||
surface->frame_tag = 0;
|
surface->frame_tag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +347,9 @@ namespace rsx
|
||||||
{
|
{
|
||||||
surface->frame_tag = vk::get_current_frame_id();
|
surface->frame_tag = vk::get_current_frame_id();
|
||||||
if (!surface->frame_tag) surface->frame_tag = 1;
|
if (!surface->frame_tag) surface->frame_tag = 1;
|
||||||
|
|
||||||
|
if (surface->old_contents) surface->clear_rw_barrier();
|
||||||
|
surface->release();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface)
|
static void notify_surface_persist(const std::unique_ptr<vk::render_target> &surface)
|
||||||
|
@ -349,9 +357,14 @@ namespace rsx
|
||||||
surface->save_aa_mode();
|
surface->save_aa_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void notify_surface_reused(const std::unique_ptr<vk::render_target> &surface)
|
||||||
|
{
|
||||||
|
surface->add_ref();
|
||||||
|
}
|
||||||
|
|
||||||
static bool rtt_has_format_width_height(const std::unique_ptr<vk::render_target> &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false)
|
static bool rtt_has_format_width_height(const std::unique_ptr<vk::render_target> &rtt, surface_color_format format, size_t width, size_t height, bool check_refs=false)
|
||||||
{
|
{
|
||||||
if (check_refs && rtt->deref_count == 0) //Surface may still have read refs from data 'copy'
|
if (check_refs && rtt->has_refs()) // Surface may still have read refs from data 'copy'
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
VkFormat fmt = vk::get_compatible_surface_format(format).first;
|
VkFormat fmt = vk::get_compatible_surface_format(format).first;
|
||||||
|
@ -365,7 +378,7 @@ namespace rsx
|
||||||
|
|
||||||
static bool ds_has_format_width_height(const std::unique_ptr<vk::render_target> &ds, surface_depth_format format, size_t width, size_t height, bool check_refs=false)
|
static bool ds_has_format_width_height(const std::unique_ptr<vk::render_target> &ds, surface_depth_format format, size_t width, size_t height, bool check_refs=false)
|
||||||
{
|
{
|
||||||
if (check_refs && ds->deref_count == 0) //Surface may still have read refs from data 'copy'
|
if (check_refs && ds->has_refs()) //Surface may still have read refs from data 'copy'
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (ds->matches_dimensions((u16)width, (u16)height))
|
if (ds->matches_dimensions((u16)width, (u16)height))
|
||||||
|
@ -418,8 +431,7 @@ namespace rsx
|
||||||
{
|
{
|
||||||
void destroy()
|
void destroy()
|
||||||
{
|
{
|
||||||
m_render_targets_storage.clear();
|
invalidate_all();
|
||||||
m_depth_stencil_storage.clear();
|
|
||||||
invalidated_resources.clear();
|
invalidated_resources.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,10 +442,9 @@ namespace rsx
|
||||||
{
|
{
|
||||||
verify(HERE), rtt->frame_tag != 0;
|
verify(HERE), rtt->frame_tag != 0;
|
||||||
|
|
||||||
if (rtt->deref_count >= 2 && rtt->frame_tag < last_finished_frame)
|
if (rtt->unused_check_count() >= 2 && rtt->frame_tag < last_finished_frame)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
rtt->deref_count++;
|
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -555,7 +555,6 @@ namespace vk
|
||||||
verify(HERE), section.dst_z == 0;
|
verify(HERE), section.dst_z == 0;
|
||||||
|
|
||||||
u16 dst_x = section.dst_x, dst_y = section.dst_y;
|
u16 dst_x = section.dst_x, dst_y = section.dst_y;
|
||||||
auto xform = section.xform;
|
|
||||||
vk::image* _dst;
|
vk::image* _dst;
|
||||||
|
|
||||||
if (LIKELY(src_image->info.format == dst->info.format))
|
if (LIKELY(src_image->info.format == dst->info.format))
|
||||||
|
|
|
@ -33,11 +33,38 @@ namespace rsx
|
||||||
extern atomic_t<u64> g_rsx_shared_tag;
|
extern atomic_t<u64> g_rsx_shared_tag;
|
||||||
|
|
||||||
//Base for resources with reference counting
|
//Base for resources with reference counting
|
||||||
struct ref_counted
|
class ref_counted
|
||||||
{
|
{
|
||||||
u8 deref_count = 0;
|
atomic_t<s32> ref_count{ 0 }; // References held
|
||||||
|
atomic_t<u8> idle_time{ 0 }; // Number of times the resource has been tagged idle
|
||||||
|
|
||||||
void reset_refs() { deref_count = 0; }
|
public:
|
||||||
|
void add_ref()
|
||||||
|
{
|
||||||
|
ref_count++;
|
||||||
|
idle_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void release()
|
||||||
|
{
|
||||||
|
ref_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_refs()
|
||||||
|
{
|
||||||
|
return (ref_count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns number of times the resource has been checked without being used in-between checks
|
||||||
|
u8 unused_check_count()
|
||||||
|
{
|
||||||
|
if (ref_count)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return idle_time++;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue