diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index c31d542395..6a6ee930da 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -6,6 +6,8 @@ #include +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 m_cache; + std::atomic m_cache_update_tag = {}; + std::pair read_only_range = std::make_pair(0xFFFFFFFF, 0); std::pair 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 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(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 - 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(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(extras)...); region.set_context(texture_upload_context::framebuffer_storage); + update_cache_tag(); } template @@ -636,7 +646,13 @@ namespace rsx template 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(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(extras)...); } template @@ -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(extras)...); + return invalidate_range_impl_base(address, range, is_writing, discard, false, allow_flush, std::forward(extras)...); } template @@ -655,29 +671,55 @@ namespace rsx { writer_lock lock(m_cache_mutex); - std::vector 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 old_protections; + for (int n = data.num_flushable; n < data.affected_sections.size(); ++n) { - if (!data.affected_sections[n]->flush(std::forward(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(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(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(extras)...); - invalidate_range_impl(dst_address, memcpy_bytes_length, true, false, true, std::forward(extras)...); + invalidate_range_impl_base(src_address, memcpy_bytes_length, false, false, false, true, std::forward(extras)...); + invalidate_range_impl_base(dst_address, memcpy_bytes_length, true, false, false, true, std::forward(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(extras)...); + invalidate_range_impl_base(src_address, src.pitch * src.slice_h, false, false, false, true, std::forward(extras)...); const u16 pitch_in_block = src_is_argb8 ? src.pitch >> 2 : src.pitch >> 1; std::vector 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(extras)...); + invalidate_range_impl_base(cached_dest->get_section_base(), cached_dest->get_section_size(), true, false, false, true, std::forward(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(extras)...); + invalidate_range_impl_base(dst_address, dst.pitch * dst.height, true, false, false, true, std::forward(extras)...); } //Validate clipping region diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index c355528caa..679721f3e4 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -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) diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 30d1a0f73f..91b3db0278 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -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; } diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 16c247258b..bd059e45a6 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -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); } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index e79b1bb01c..b2f3707c49 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -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 ®ion;