mirror of https://github.com/RPCS3/rpcs3.git
rsx: Fix surface write coherency when MSAA is active
This commit is contained in:
parent
cd97d74f0f
commit
6812fa4764
|
@ -52,7 +52,6 @@ namespace rsx
|
||||||
rsx::address_range m_depth_stencil_memory_range;
|
rsx::address_range m_depth_stencil_memory_range;
|
||||||
|
|
||||||
bool m_invalidate_on_write = false;
|
bool m_invalidate_on_write = false;
|
||||||
bool m_skip_write_updates = false;
|
|
||||||
|
|
||||||
rsx::surface_raster_type m_active_raster_type = rsx::surface_raster_type::linear;
|
rsx::surface_raster_type m_active_raster_type = rsx::surface_raster_type::linear;
|
||||||
|
|
||||||
|
@ -1118,62 +1117,31 @@ namespace rsx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_write(const bool* color, bool z)
|
void on_write(const std::array<bool, 4>& color_mrt_writes_enabled, const bool depth_stencil_writes_enabled)
|
||||||
{
|
{
|
||||||
if (write_tag == cache_tag && m_skip_write_updates)
|
if (write_tag >= cache_tag && !m_invalidate_on_write)
|
||||||
{
|
{
|
||||||
// Nothing to do
|
|
||||||
ensure(!m_invalidate_on_write);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_tag = cache_tag;
|
// TODO: Take WCB/WDB into account. Should speed this up a bit by skipping sync_tag calls
|
||||||
m_skip_write_updates = false;
|
write_tag = rsx::get_shared_tag();
|
||||||
int tagged = 0;
|
|
||||||
|
|
||||||
// Tag surfaces
|
for (u8 i = m_bound_render_targets_config.first, count = 0;
|
||||||
if (color)
|
count < m_bound_render_targets_config.second;
|
||||||
|
++count, ++i)
|
||||||
{
|
{
|
||||||
for (int i = m_bound_render_targets_config.first, count = 0;
|
if (auto surface = m_bound_render_targets[i].second;
|
||||||
count < m_bound_render_targets_config.second;
|
surface && color_mrt_writes_enabled[i])
|
||||||
++i, ++count)
|
|
||||||
{
|
{
|
||||||
if (!color[i])
|
surface->on_write(write_tag);
|
||||||
continue;
|
|
||||||
|
|
||||||
auto& surface = m_bound_render_targets[i].second;
|
|
||||||
if (surface->last_use_tag != write_tag)
|
|
||||||
{
|
|
||||||
m_bound_render_targets[i].second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type);
|
|
||||||
}
|
|
||||||
else if (m_invalidate_on_write)
|
|
||||||
{
|
|
||||||
m_bound_render_targets[i].second->on_invalidate_children();
|
|
||||||
}
|
|
||||||
|
|
||||||
++tagged;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (z && m_bound_depth_stencil.first)
|
if (auto zsurface = m_bound_depth_stencil.second;
|
||||||
|
zsurface && depth_stencil_writes_enabled)
|
||||||
{
|
{
|
||||||
auto& surface = m_bound_depth_stencil.second;
|
zsurface->on_write(write_tag);
|
||||||
if (surface->last_use_tag != write_tag)
|
|
||||||
{
|
|
||||||
m_bound_depth_stencil.second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type);
|
|
||||||
}
|
|
||||||
else if (m_invalidate_on_write)
|
|
||||||
{
|
|
||||||
m_bound_depth_stencil.second->on_invalidate_children();
|
|
||||||
}
|
|
||||||
|
|
||||||
++tagged;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_invalidate_on_write && tagged == m_bound_buffers_count)
|
|
||||||
{
|
|
||||||
// Skip any further updates as all active surfaces have been updated
|
|
||||||
m_skip_write_updates = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ namespace rsx
|
||||||
virtual bool is_depth_surface() const = 0;
|
virtual bool is_depth_surface() const = 0;
|
||||||
virtual void release_ref(image_storage_type) const = 0;
|
virtual void release_ref(image_storage_type) const = 0;
|
||||||
|
|
||||||
virtual u32 get_surface_width(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
|
inline u32 get_surface_width(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
|
||||||
{
|
{
|
||||||
switch (metrics)
|
switch (metrics)
|
||||||
{
|
{
|
||||||
|
@ -193,7 +193,7 @@ namespace rsx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual u32 get_surface_height(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
|
inline u32 get_surface_height(rsx::surface_metrics metrics = rsx::surface_metrics::pixels) const
|
||||||
{
|
{
|
||||||
switch (metrics)
|
switch (metrics)
|
||||||
{
|
{
|
||||||
|
@ -207,22 +207,22 @@ namespace rsx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual u32 get_rsx_pitch() const
|
inline u32 get_rsx_pitch() const
|
||||||
{
|
{
|
||||||
return rsx_pitch;
|
return rsx_pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual u32 get_native_pitch() const
|
inline u32 get_native_pitch() const
|
||||||
{
|
{
|
||||||
return native_pitch;
|
return native_pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 get_bpp() const
|
inline u8 get_bpp() const
|
||||||
{
|
{
|
||||||
return u8(get_native_pitch() / get_surface_width(rsx::surface_metrics::samples));
|
return u8(get_native_pitch() / get_surface_width(rsx::surface_metrics::samples));
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 get_spp() const
|
inline u8 get_spp() const
|
||||||
{
|
{
|
||||||
return spp;
|
return spp;
|
||||||
}
|
}
|
||||||
|
@ -278,17 +278,17 @@ namespace rsx
|
||||||
format_info.gcm_depth_format = format;
|
format_info.gcm_depth_format = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsx::surface_color_format get_surface_color_format() const
|
inline rsx::surface_color_format get_surface_color_format() const
|
||||||
{
|
{
|
||||||
return format_info.gcm_color_format;
|
return format_info.gcm_color_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
rsx::surface_depth_format2 get_surface_depth_format() const
|
inline rsx::surface_depth_format2 get_surface_depth_format() const
|
||||||
{
|
{
|
||||||
return format_info.gcm_depth_format;
|
return format_info.gcm_depth_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 get_gcm_format() const
|
inline u32 get_gcm_format() const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(
|
(
|
||||||
|
@ -298,12 +298,12 @@ namespace rsx
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dirty() const
|
inline bool dirty() const
|
||||||
{
|
{
|
||||||
return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty();
|
return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool write_through() const
|
inline bool write_through() const
|
||||||
{
|
{
|
||||||
return (state_flags & rsx::surface_state_flags::erase_bkgnd) && old_contents.empty();
|
return (state_flags & rsx::surface_state_flags::erase_bkgnd) && old_contents.empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,26 +285,53 @@ namespace rsx
|
||||||
template <typename surface_store_type, typename surface_type = typename surface_store_type::surface_type>
|
template <typename surface_store_type, typename surface_type = typename surface_store_type::surface_type>
|
||||||
std::pair<bool, surface_type> is_expired(surface_store_type& surface_cache)
|
std::pair<bool, surface_type> is_expired(surface_store_type& surface_cache)
|
||||||
{
|
{
|
||||||
if (upload_context != rsx::texture_upload_context::framebuffer_storage ||
|
if (upload_context != rsx::texture_upload_context::framebuffer_storage)
|
||||||
surface_cache_tag == surface_cache.cache_tag)
|
|
||||||
{
|
{
|
||||||
return { false, nullptr };
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expired, but may still be valid. Check if the texture is still accessible
|
// Expired, but may still be valid. Check if the texture is still accessible
|
||||||
auto ref_image = image_handle ? image_handle->image() : external_subresource_desc.external_handle;
|
auto ref_image = image_handle ? image_handle->image() : external_subresource_desc.external_handle;
|
||||||
if (ref_image)
|
surface_type surface = dynamic_cast<surface_type>(ref_image);
|
||||||
|
|
||||||
|
// Try and grab a cache reference in case of MSAA resolve target or compositing op
|
||||||
|
if (!surface)
|
||||||
{
|
{
|
||||||
if (auto surface = dynamic_cast<surface_type>(ref_image);
|
if (!(surface = surface_cache.get_surface_at(ref_address)))
|
||||||
surface && surface == surface_cache.get_surface_at(ref_address))
|
|
||||||
{
|
{
|
||||||
// Fast sync
|
// Compositing op. Just ignore expiry for now
|
||||||
surface_cache_tag = surface_cache.cache_tag;
|
ensure(!ref_image);
|
||||||
is_cyclic_reference = surface_cache.address_is_bound(ref_address);
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure(surface);
|
||||||
|
if (!ref_image || surface->get_surface(rsx::surface_access::gpu_reference) == ref_image)
|
||||||
|
{
|
||||||
|
// Same image, so configuration did not change.
|
||||||
|
if (surface->last_use_tag <= surface_cache_tag)
|
||||||
|
{
|
||||||
|
external_subresource_desc.do_not_cache = false;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image was written to since last bind. Insert texture barrier.
|
||||||
|
surface_cache_tag = surface->last_use_tag;
|
||||||
|
is_cyclic_reference = surface_cache.address_is_bound(ref_address);
|
||||||
|
external_subresource_desc.do_not_cache = is_cyclic_reference;
|
||||||
|
|
||||||
|
switch (external_subresource_desc.op)
|
||||||
|
{
|
||||||
|
case deferred_request_command::copy_image_dynamic:
|
||||||
|
case deferred_request_command::copy_image_static:
|
||||||
|
external_subresource_desc.op = (is_cyclic_reference) ? deferred_request_command::copy_image_dynamic : deferred_request_command::copy_image_static;
|
||||||
|
[[ fallthrough ]];
|
||||||
|
default:
|
||||||
return { false, surface };
|
return { false, surface };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reupload
|
||||||
return { true, nullptr };
|
return { true, nullptr };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2155,7 +2182,7 @@ namespace rsx
|
||||||
}
|
}
|
||||||
|
|
||||||
result.ref_address = attributes.address;
|
result.ref_address = attributes.address;
|
||||||
result.surface_cache_tag = m_rtts.cache_tag;
|
result.surface_cache_tag = m_rtts.write_tag;
|
||||||
|
|
||||||
if (subsurface_count == 1)
|
if (subsurface_count == 1)
|
||||||
{
|
{
|
||||||
|
|
|
@ -677,7 +677,7 @@ void GLGSRender::end()
|
||||||
}
|
}
|
||||||
while (rsx::method_registers.current_draw_clause.next());
|
while (rsx::method_registers.current_draw_clause.next());
|
||||||
|
|
||||||
m_rtts.on_write(m_framebuffer_layout.color_write_enabled.data(), m_framebuffer_layout.zeta_write_enabled);
|
m_rtts.on_write(m_framebuffer_layout.color_write_enabled, m_framebuffer_layout.zeta_write_enabled);
|
||||||
|
|
||||||
m_attrib_ring_buffer->notify();
|
m_attrib_ring_buffer->notify();
|
||||||
m_index_ring_buffer->notify();
|
m_index_ring_buffer->notify();
|
||||||
|
|
|
@ -662,8 +662,7 @@ void GLGSRender::clear_surface(u32 arg)
|
||||||
|
|
||||||
if (update_color || update_z)
|
if (update_color || update_z)
|
||||||
{
|
{
|
||||||
const bool write_all_mask[] = { true, true, true, true };
|
m_rtts.on_write({ update_color, update_color, update_color, update_color }, update_z);
|
||||||
m_rtts.on_write(update_color ? write_all_mask : nullptr, update_z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glClear(mask);
|
glClear(mask);
|
||||||
|
|
|
@ -1116,7 +1116,7 @@ void VKGSRender::end()
|
||||||
m_current_command_buffer->flags &= ~(vk::command_buffer::cb_has_conditional_render);
|
m_current_command_buffer->flags &= ~(vk::command_buffer::cb_has_conditional_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rtts.on_write(m_framebuffer_layout.color_write_enabled.data(), m_framebuffer_layout.zeta_write_enabled);
|
m_rtts.on_write(m_framebuffer_layout.color_write_enabled, m_framebuffer_layout.zeta_write_enabled);
|
||||||
|
|
||||||
rsx::thread::end();
|
rsx::thread::end();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1449,8 +1449,7 @@ void VKGSRender::clear_surface(u32 mask)
|
||||||
|
|
||||||
if (update_color || update_z)
|
if (update_color || update_z)
|
||||||
{
|
{
|
||||||
const bool write_all_mask[] = { true, true, true, true };
|
m_rtts.on_write({ update_color, update_color, update_color, update_color }, update_z);
|
||||||
m_rtts.on_write(update_color ? write_all_mask : nullptr, update_z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clear_descriptors.empty())
|
if (!clear_descriptors.empty())
|
||||||
|
|
|
@ -772,6 +772,12 @@ namespace vk
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (access_type == rsx::surface_access::gpu_reference)
|
||||||
|
{
|
||||||
|
// WARNING: Can return MSAA data result if no read barrier was issued
|
||||||
|
return resolve_surface ? resolve_surface.get() : this;
|
||||||
|
}
|
||||||
|
|
||||||
// A read barrier should have been called before this!
|
// A read barrier should have been called before this!
|
||||||
ensure(resolve_surface); // "Read access without explicit barrier"
|
ensure(resolve_surface); // "Read access without explicit barrier"
|
||||||
ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve));
|
ensure(!(msaa_flags & rsx::surface_state_flags::require_resolve));
|
||||||
|
@ -801,9 +807,15 @@ namespace vk
|
||||||
{
|
{
|
||||||
if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync
|
if (!write_barrier_sync_tag) write_barrier_sync_tag++; // Activate barrier sync
|
||||||
cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags
|
cyclic_reference_sync_tag = write_barrier_sync_tag; // Match tags
|
||||||
|
|
||||||
|
vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::insert_texture_barrier(cmd, this, VK_IMAGE_LAYOUT_GENERAL);
|
if (msaa_flags & rsx::surface_state_flags::require_resolve)
|
||||||
|
{
|
||||||
|
resolve(cmd);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_target::reset_surface_counters()
|
void render_target::reset_surface_counters()
|
||||||
|
|
Loading…
Reference in New Issue