rsx: Tag cache blocks returned on access violation to validate data passed

to flush_all is up to date. Should prevent recursive exceptions

Partially revert Jarves' fix to invalidate cache on tile unbind. This will
need alot more work. Fixes hangs
This commit is contained in:
kd-11 2017-10-28 22:17:27 +03:00
parent 395b4bfa45
commit 361e80f7dc
5 changed files with 85 additions and 33 deletions

View file

@ -6,6 +6,8 @@
#include <atomic>
extern u64 get_system_time();
namespace rsx
{
enum texture_create_flags
@ -156,6 +158,8 @@ namespace rsx
shared_mutex m_cache_mutex;
std::unordered_map<u32, ranged_storage> m_cache;
std::atomic<u64> m_cache_update_tag = {};
std::pair<u32, u32> read_only_range = std::make_pair(0xFFFFFFFF, 0);
std::pair<u32, u32> no_access_range = std::make_pair(0xFFFFFFFF, 0);
@ -183,6 +187,11 @@ namespace rsx
constexpr u32 get_block_size() const { return 0x1000000; }
inline u32 get_block_address(u32 address) const { return (address & ~0xFFFFFF); }
inline void update_cache_tag()
{
m_cache_update_tag = get_system_time();
}
public:
//Struct to hold data on sections to be paged back onto cpu memory
struct thrashed_set
@ -190,6 +199,9 @@ namespace rsx
bool violation_handled = false;
std::vector<section_storage_type*> affected_sections; //Always laid out with flushable sections first then other affected sections last
int num_flushable = 0;
u64 cache_tag = 0;
u32 address_base = 0;
u32 address_range = 0;
};
private:
@ -368,6 +380,9 @@ namespace rsx
{
result.num_flushable = static_cast<int>(sections_to_flush.size());
result.affected_sections = std::move(sections_to_flush);
result.address_base = address;
result.address_range = range;
result.cache_tag = m_cache_update_tag.load(std::memory_order_consume);
}
for (auto It = to_reprotect; It != trampled_set.end(); It++)
@ -392,12 +407,6 @@ namespace rsx
return {};
}
template <typename ...Args>
thrashed_set invalidate_range_impl(u32 address, u32 range, bool is_writing, bool discard, bool allow_flush, Args&&... extras)
{
return invalidate_range_impl_base(address, range, is_writing, discard, true, allow_flush, std::forward<Args>(extras)...);
}
bool is_hw_blit_engine_compatible(const u32 format) const
{
switch (format)
@ -546,6 +555,7 @@ namespace rsx
region.protect(utils::protection::no);
region.create(width, height, 1, 1, nullptr, image, pitch, false, std::forward<Args>(extras)...);
region.set_context(texture_upload_context::framebuffer_storage);
update_cache_tag();
}
template <typename ...Args>
@ -636,7 +646,13 @@ namespace rsx
template <typename ...Args>
thrashed_set invalidate_address(u32 address, bool is_writing, bool allow_flush, Args&&... extras)
{
return invalidate_range(address, 4096 - (address & 4095), is_writing, false, allow_flush, std::forward<Args>(extras)...);
//Test before trying to acquire the lock
const auto range = 4096 - (address & 4095);
if (!region_intersects_cache(address, range, is_writing))
return{};
writer_lock lock(m_cache_mutex);
return invalidate_range_impl_base(address, range, is_writing, false, true, allow_flush, std::forward<Args>(extras)...);
}
template <typename ...Args>
@ -647,7 +663,7 @@ namespace rsx
return {};
writer_lock lock(m_cache_mutex);
return invalidate_range_impl(address, range, is_writing, discard, allow_flush, std::forward<Args>(extras)...);
return invalidate_range_impl_base(address, range, is_writing, discard, false, allow_flush, std::forward<Args>(extras)...);
}
template <typename ...Args>
@ -655,29 +671,55 @@ namespace rsx
{
writer_lock lock(m_cache_mutex);
std::vector<utils::protection> old_protections;
for (int n = data.num_flushable; n < data.affected_sections.size(); ++n)
if (data.cache_tag == m_cache_update_tag.load(std::memory_order_consume))
{
old_protections.push_back(data.affected_sections[n]->get_protection());
data.affected_sections[n]->unprotect();
}
for (int n = 0, i = 0; n < data.affected_sections.size(); ++n)
{
if (n < data.num_flushable)
std::vector<utils::protection> old_protections;
for (int n = data.num_flushable; n < data.affected_sections.size(); ++n)
{
if (!data.affected_sections[n]->flush(std::forward<Args>(extras)...))
old_protections.push_back(data.affected_sections[n]->get_protection());
data.affected_sections[n]->unprotect();
}
for (int n = 0, i = 0; n < data.affected_sections.size(); ++n)
{
if (n < data.num_flushable)
{
//Missed address, note this
//TODO: Lower severity when successful to keep the cache from overworking
record_cache_miss(*data.affected_sections[n]);
if (!data.affected_sections[n]->flush(std::forward<Args>(extras)...))
{
//Missed address, note this
//TODO: Lower severity when successful to keep the cache from overworking
record_cache_miss(*data.affected_sections[n]);
}
}
else
{
//Restore protection on the remaining sections
data.affected_sections[n]->protect(old_protections[i++]);
}
}
else
}
else
{
//The cache contents have changed between the two readings. This means the data held is useless
//Restore memory protection for the scan to work properly
for (int n = 0; n < data.num_flushable; n++)
{
//Restore protection on the remaining sections
data.affected_sections[n]->protect(old_protections[i++]);
if (data.affected_sections[n]->get_protection() == utils::protection::rw)
{
const u32 address = data.affected_sections[n]->get_section_base();
const u32 size = data.affected_sections[n]->get_section_size();
data.affected_sections[n]->protect(utils::protection::no);
m_cache[get_block_address(address)].notify(address, size);
}
else
{
LOG_WARNING(RSX, "Texture Cache: Section at address 0x%X was lost", data.affected_sections[n]->get_section_base());
}
}
update_cache_tag();
invalidate_range_impl_base(data.address_base, data.address_range, true, false, true, true, std::forward<Args>(extras)...);
}
return true;
@ -1080,8 +1122,8 @@ namespace rsx
const u32 memcpy_bytes_length = dst.clip_width * bpp * dst.clip_height;
lock.upgrade();
invalidate_range_impl(src_address, memcpy_bytes_length, false, false, true, std::forward<Args>(extras)...);
invalidate_range_impl(dst_address, memcpy_bytes_length, true, false, true, std::forward<Args>(extras)...);
invalidate_range_impl_base(src_address, memcpy_bytes_length, false, false, false, true, std::forward<Args>(extras)...);
invalidate_range_impl_base(dst_address, memcpy_bytes_length, true, false, false, true, std::forward<Args>(extras)...);
memcpy(dst.pixels, src.pixels, memcpy_bytes_length);
return true;
}
@ -1188,7 +1230,7 @@ namespace rsx
{
lock.upgrade();
invalidate_range_impl(src_address, src.pitch * src.slice_h, false, false, true, std::forward<Args>(extras)...);
invalidate_range_impl_base(src_address, src.pitch * src.slice_h, false, false, false, true, std::forward<Args>(extras)...);
const u16 pitch_in_block = src_is_argb8 ? src.pitch >> 2 : src.pitch >> 1;
std::vector<rsx_subresource_layout> subresource_layout;
@ -1260,7 +1302,7 @@ namespace rsx
if (format_mismatch)
{
lock.upgrade();
invalidate_range_impl(cached_dest->get_section_base(), cached_dest->get_section_size(), true, false, true, std::forward<Args>(extras)...);
invalidate_range_impl_base(cached_dest->get_section_base(), cached_dest->get_section_size(), true, false, false, true, std::forward<Args>(extras)...);
dest_texture = 0;
cached_dest = nullptr;
@ -1268,7 +1310,7 @@ namespace rsx
else if (invalidate_dst_range)
{
lock.upgrade();
invalidate_range_impl(dst_address, dst.pitch * dst.height, true, false, true, std::forward<Args>(extras)...);
invalidate_range_impl_base(dst_address, dst.pitch * dst.height, true, false, false, true, std::forward<Args>(extras)...);
}
//Validate clipping region

View file

@ -1296,8 +1296,10 @@ bool GLGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst
void GLGSRender::notify_tile_unbound(u32 tile)
{
u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
m_rtts.invalidate_surface_address(addr, false);
//TODO: Handle texture writeback
//u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
//on_notify_memory_unmapped(addr, tiles[tile].size);
//m_rtts.invalidate_surface_address(addr, false);
}
void GLGSRender::check_zcull_status(bool framebuffer_swap, bool force_read)

View file

@ -673,7 +673,10 @@ namespace gl
//Its not necessary to lock blit dst textures as they are just reused as necessary
if (context != rsx::texture_upload_context::blit_engine_dst || g_cfg.video.strict_rendering_mode)
{
cached.protect(utils::protection::ro);
update_cache_tag();
}
return &cached;
}

View file

@ -2716,6 +2716,8 @@ bool VKGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst
void VKGSRender::notify_tile_unbound(u32 tile)
{
u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
m_rtts.invalidate_surface_address(addr, false);
//TODO: Handle texture writeback
//u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
//on_notify_memory_unmapped(addr, tiles[tile].size);
//m_rtts.invalidate_surface_address(addr, false);
}

View file

@ -547,7 +547,10 @@ namespace vk
//Its not necessary to lock blit dst textures as they are just reused as necessary
if (context != rsx::texture_upload_context::blit_engine_dst || g_cfg.video.strict_rendering_mode)
{
region.protect(utils::protection::ro);
update_cache_tag();
}
read_only_range = region.get_min_max(read_only_range);
return &region;