1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-23 11:13:19 +01:00

rsx: Fix self-intersection with previous occupant of the address being replaced

This commit is contained in:
kd-11 2019-05-11 13:16:46 +03:00 committed by kd-11
parent b840f6da28
commit 4b443be881
3 changed files with 65 additions and 28 deletions

View File

@ -438,8 +438,8 @@ namespace rsx
std::pair<u32, surface_type> m_bound_depth_stencil = {};
std::list<surface_storage_type> invalidated_resources;
u64 cache_tag = 0ull;
u64 write_tag = 0ull;
u64 cache_tag = 1ull; // Use 1 as the start since 0 is default tag on new surfaces
u64 write_tag = 1ull;
surface_store() = default;
~surface_store() = default;
@ -555,10 +555,10 @@ namespace rsx
}
template <bool is_depth_surface>
void intersect_surface_region(command_list_type cmd, u32 address, surface_type new_surface)
void intersect_surface_region(command_list_type cmd, u32 address, surface_type new_surface, surface_type prev_surface)
{
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
auto scan_list = [&new_surface](const rsx::address_range& mem_range,
auto scan_list = [&new_surface, address](const rsx::address_range& mem_range, u64 timestamp_check,
std::unordered_map<u32, surface_storage_type>& data) -> std::vector<std::pair<u32, surface_type>>
{
std::vector<std::pair<u32, surface_type>> result;
@ -566,7 +566,10 @@ namespace rsx
{
auto surface = Traits::get(e.second);
if (new_surface == surface || e.second->dirty || e.second->last_use_tag <= new_surface->last_use_tag)
if (e.second->last_use_tag <= timestamp_check ||
new_surface == surface ||
address == e.first ||
e.second->dirty)
{
// Do not bother synchronizing with uninitialized data
continue;
@ -602,13 +605,31 @@ namespace rsx
};
const rsx::address_range mem_range = new_surface->get_memory_range();
const auto list1 = scan_list(mem_range, m_render_targets_storage);
const auto list2 = scan_list(mem_range, m_depth_stencil_storage);
const u64 timestamp_check = prev_surface ? prev_surface->last_use_tag : new_surface->last_use_tag;
auto list1 = scan_list(mem_range, timestamp_check, m_render_targets_storage);
auto list2 = scan_list(mem_range, timestamp_check, m_depth_stencil_storage);
if (prev_surface)
{
// Append the previous removed surface to the intersection list
std::pair<u32, surface_type> e = { address, prev_surface };
if constexpr (is_depth_surface)
{
list2.push_back({ address, prev_surface });
}
else
{
list1.push_back({ address, prev_surface });
}
}
else
{
if (list1.empty() && list2.empty())
{
return;
}
}
std::vector<std::pair<u32, surface_type>> surface_info;
if (list1.empty())
@ -784,13 +805,9 @@ namespace rsx
if (!new_surface)
{
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, pitch, std::forward<Args>(extra_params)...);
new_surface = Traits::get(m_render_targets_storage[address]);
}
else if (store)
{
// New surface was found among invalidated surfaces
m_render_targets_storage[address] = std::move(new_surface_storage);
verify(HERE), store;
new_surface_storage = Traits::create_new_surface(address, color_format, width, height, pitch, std::forward<Args>(extra_params)...);
new_surface = Traits::get(new_surface_storage);
}
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
@ -802,7 +819,13 @@ namespace rsx
else
#endif
{
intersect_surface_region<false>(command_list, address, new_surface);
intersect_surface_region<false>(command_list, address, new_surface, old_surface);
}
if (store)
{
// New surface was found among invalidated surfaces
m_render_targets_storage[address] = std::move(new_surface_storage);
}
// Remove and preserve if possible any overlapping/replaced depth surface
@ -906,20 +929,16 @@ namespace rsx
if (old_surface != nullptr && new_surface == nullptr)
{
//This was already determined to be invalid and is excluded from testing above
// This was already determined to be invalid and is excluded from testing above
Traits::notify_surface_invalidated(old_surface_storage);
invalidated_resources.push_back(std::move(old_surface_storage));
}
if (!new_surface)
{
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, pitch, std::forward<Args>(extra_params)...);
new_surface = Traits::get(m_depth_stencil_storage[address]);
}
else if (store)
{
// New surface was found among invalidated surfaces
m_depth_stencil_storage[address] = std::move(new_surface_storage);
verify(HERE), store;
new_surface_storage = Traits::create_new_surface(address, depth_format, width, height, pitch, std::forward<Args>(extra_params)...);
new_surface = Traits::get(new_surface_storage);
}
#ifndef INCOMPLETE_SURFACE_CACHE_IMPL
@ -931,7 +950,13 @@ namespace rsx
else
#endif
{
intersect_surface_region<true>(command_list, address, new_surface);
intersect_surface_region<true>(command_list, address, new_surface, old_surface);
}
if (store)
{
// New surface was found among invalidated surfaces
m_depth_stencil_storage[address] = std::move(new_surface_storage);
}
// Remove and preserve if possible any overlapping/replaced color surface

View File

@ -284,12 +284,18 @@ struct gl_render_target_traits
surface->reset_aa_mode();
surface->queue_tag(address);
surface->set_cleared(false);
surface->last_use_tag = 0;
}
static
void notify_surface_invalidated(const std::unique_ptr<gl::render_target>& surface)
{
if (surface->old_contents) surface->clear_rw_barrier();
if (surface->old_contents)
{
// TODO: Retire the deferred writes
surface->clear_rw_barrier();
}
surface->release();
}

View File

@ -341,6 +341,7 @@ namespace rsx
surface->reset_aa_mode();
surface->queue_tag(address);
surface->dirty = true;
surface->last_use_tag = 0;
}
static void notify_surface_invalidated(const std::unique_ptr<vk::render_target> &surface)
@ -348,7 +349,12 @@ namespace rsx
surface->frame_tag = vk::get_current_frame_id();
if (!surface->frame_tag) surface->frame_tag = 1;
if (surface->old_contents) surface->clear_rw_barrier();
if (surface->old_contents)
{
// TODO: Retire the deferred writes
surface->clear_rw_barrier();
}
surface->release();
}