diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 5f6ac1f514..dbaa8aed0e 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -17,6 +17,7 @@ namespace rsx struct surface_subresource_storage { surface_type surface = nullptr; + u32 base_address = 0; u16 x = 0; u16 y = 0; @@ -29,8 +30,8 @@ namespace rsx surface_subresource_storage() {} - surface_subresource_storage(surface_type src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false) - : surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped) + surface_subresource_storage(u32 addr, surface_type src, u16 X, u16 Y, u16 W, u16 H, bool _Bound, bool _Depth, bool _Clipped = false) + : base_address(addr), surface(src), x(X), y(Y), w(W), h(H), is_bound(_Bound), is_depth_surface(_Depth), is_clipped(_Clipped) {} }; @@ -114,6 +115,7 @@ namespace rsx std::tuple m_bound_depth_stencil = {}; std::list invalidated_resources; + u64 cache_tag = 0ull; surface_store() = default; ~surface_store() = default; @@ -272,6 +274,8 @@ namespace rsx // u32 clip_x = clip_horizontal_reg; // u32 clip_y = clip_vertical_reg; + cache_tag++; + // Make previous RTTs sampleable for (std::tuple &rtt : m_bound_render_targets) { @@ -496,6 +500,8 @@ namespace rsx { invalidated_resources.push_back(std::move(It->second)); m_render_targets_storage.erase(It); + + cache_tag++; return; } } @@ -511,6 +517,8 @@ namespace rsx { invalidated_resources.push_back(std::move(It->second)); m_depth_stencil_storage.erase(It); + + cache_tag++; return; } } @@ -535,6 +543,9 @@ namespace rsx { invalidated_resources.push_back(std::move(It->second)); m_render_targets_storage.erase(It); + + cache_tag++; + return; } } else @@ -544,6 +555,9 @@ namespace rsx { invalidated_resources.push_back(std::move(It->second)); m_depth_stencil_storage.erase(It); + + cache_tag++; + return; } } } @@ -725,11 +739,11 @@ namespace rsx if (!surface_overlaps_address_fast(surface, this_address, texaddr)) continue; else - return{ surface, 0, 0, 0, 0, false, false, false }; + return{ this_address, surface, 0, 0, 0, 0, false, false, false }; } if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped)) - return{ surface, x_offset, y_offset, w, h, address_is_bound(this_address, false), false, clipped }; + return{ this_address, surface, x_offset, y_offset, w, h, address_is_bound(this_address, false), false, clipped }; } } @@ -751,11 +765,11 @@ namespace rsx if (!surface_overlaps_address_fast(surface, this_address, texaddr)) continue; else - return{ surface, 0, 0, 0, 0, false, true, false }; + return{ this_address, surface, 0, 0, 0, 0, false, true, false }; } if (test_surface(surface, this_address, x_offset, y_offset, w, h, clipped)) - return{ surface, x_offset, y_offset, w, h, address_is_bound(this_address, true), true, clipped }; + return{ this_address, surface, x_offset, y_offset, w, h, address_is_bound(this_address, true), true, clipped }; } } diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index c18360beab..1569baeee9 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -878,6 +878,10 @@ namespace rsx } const auto extended_dimension = tex.get_extended_texture_dimension(); + u16 depth = 0; + u16 tex_height = (u16)tex.height(); + u16 tex_pitch = tex.pitch(); + const u16 tex_width = tex.width(); if (!is_compressed_format) { @@ -891,28 +895,44 @@ namespace rsx LOG_ERROR(RSX, "Texture resides in render target memory, but requested type is not 2D (%d)", (u32)extended_dimension); f32 internal_scale = (f32)texptr->get_native_pitch() / tex.pitch(); - for (const auto& tex : m_rtts.m_bound_render_targets) + bool requires_processing = texptr->get_surface_width() != tex_width || texptr->get_surface_height() != tex_height; + + if (!requires_processing) { - if (std::get<0>(tex) == texaddr) + for (const auto& tex : m_rtts.m_bound_render_targets) { - if (g_cfg.video.strict_rendering_mode) + if (std::get<0>(tex) == texaddr) { - LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr); - return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height()), texture_upload_context::framebuffer_storage, false, internal_scale }; - } - else - { - //issue a texture barrier to ensure previous writes are visible - insert_texture_barrier(); - break; + if (g_cfg.video.strict_rendering_mode) + { + LOG_WARNING(RSX, "Attempting to sample a currently bound render target @ 0x%x", texaddr); + requires_processing = true; + break; + } + else + { + //issue a texture barrier to ensure previous writes are visible + insert_texture_barrier(); + break; + } } } } + if (requires_processing) + { + const auto w = rsx::apply_resolution_scale(tex_width, true); + const auto h = rsx::apply_resolution_scale(tex_height, true); + return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage, false, internal_scale }; + } + return{ texptr->get_view(), texture_upload_context::framebuffer_storage, false, internal_scale }; } else + { m_rtts.invalidate_surface_address(texaddr, false); + invalidate_address(texaddr, false, true, std::forward(extras)...); + } } if (auto texptr = m_rtts.get_texture_from_depth_stencil_if_applicable(texaddr)) @@ -923,12 +943,14 @@ namespace rsx LOG_ERROR(RSX, "Texture resides in depth buffer memory, but requested type is not 2D (%d)", (u32)extended_dimension); f32 internal_scale = (f32)texptr->get_native_pitch() / tex.pitch(); - if (texaddr == std::get<0>(m_rtts.m_bound_depth_stencil)) + bool requires_processing = texptr->get_surface_width() != tex_width || texptr->get_surface_height() != tex_height; + + if (!requires_processing && texaddr == std::get<0>(m_rtts.m_bound_depth_stencil)) { if (g_cfg.video.strict_rendering_mode) { LOG_WARNING(RSX, "Attempting to sample a currently bound depth surface @ 0x%x", texaddr); - return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, texptr->width(), texptr->height()), texture_upload_context::framebuffer_storage, true, internal_scale }; + requires_processing = true; } else { @@ -937,18 +959,23 @@ namespace rsx } } + if (requires_processing) + { + const auto w = rsx::apply_resolution_scale(tex_width, true); + const auto h = rsx::apply_resolution_scale(tex_height, true); + return{ create_temporary_subresource_view(cmd, texptr, format, 0, 0, w, h), texture_upload_context::framebuffer_storage, true, internal_scale }; + } + return{ texptr->get_view(), texture_upload_context::framebuffer_storage, true, internal_scale }; } else + { m_rtts.invalidate_surface_address(texaddr, true); + invalidate_address(texaddr, false, true, std::forward(extras)...); + } } } - u16 depth = 0; - u16 tex_height = (u16)tex.height(); - u16 tex_pitch = tex.pitch(); - const u16 tex_width = tex.width(); - tex_pitch = is_compressed_format? (tex_size / tex_height) : tex_pitch; //NOTE: Compressed textures dont have a real pitch (tex_size = (w*h)/6) if (tex_pitch == 0) tex_pitch = tex_width * get_format_block_size_in_bytes(format); @@ -987,9 +1014,10 @@ namespace rsx if (rsc.surface) { //TODO: Check that this region is not cpu-dirty before doing a copy - if (!test_framebuffer(texaddr)) + if (!test_framebuffer(rsc.base_address)) { - m_rtts.invalidate_surface_address(texaddr, rsc.is_depth_surface); + m_rtts.invalidate_surface_address(rsc.base_address, rsc.is_depth_surface); + invalidate_address(rsc.base_address, false, true, std::forward(extras)...); } else if (extended_dimension != rsx::texture_dimension_extended::texture_dimension_2d) { @@ -1165,6 +1193,20 @@ namespace rsx src_is_render_target = false; } + if (src_is_render_target && !test_framebuffer(src_subres.base_address)) + { + m_rtts.invalidate_surface_address(src_subres.base_address, src_subres.is_depth_surface); + invalidate_address(src_subres.base_address, false, true, std::forward(extras)...); + src_is_render_target = false; + } + + if (dst_is_render_target && !test_framebuffer(dst_subres.base_address)) + { + m_rtts.invalidate_surface_address(dst_subres.base_address, dst_subres.is_depth_surface); + invalidate_address(dst_subres.base_address, false, true, std::forward(extras)...); + dst_is_render_target = false; + } + //Always use GPU blit if src or dst is in the surface store if (!g_cfg.video.use_gpu_texture_scaling && !(src_is_render_target || dst_is_render_target)) return false; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 3b0c901642..a595a41906 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -358,6 +358,12 @@ void GLGSRender::end() std::lock_guard lock(m_sampler_mutex); void* unused = nullptr; + if (surface_store_tag != m_rtts.cache_tag) + { + m_samplers_dirty.store(true); + surface_store_tag = m_rtts.cache_tag; + } + for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { if (m_samplers_dirty || m_textures_dirty[i]) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index b7b9bebafd..e51187dffd 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -379,6 +379,7 @@ private: std::array occlusion_query_data = {}; std::mutex m_sampler_mutex; + u64 surface_store_tag = 0; std::atomic_bool m_samplers_dirty = {true}; std::array, rsx::limits::fragment_textures_count> fs_sampler_state = {}; std::array, rsx::limits::vertex_textures_count> vs_sampler_state = {}; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 60c83a1743..354efe8af3 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -1051,6 +1051,12 @@ void VKGSRender::end() { std::lock_guard lock(m_sampler_mutex); + if (surface_store_tag != m_rtts.cache_tag) + { + m_samplers_dirty.store(true); + surface_store_tag = m_rtts.cache_tag; + } + for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) { if (m_samplers_dirty || m_textures_dirty[i]) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 80f774d0fe..f1b4be7575 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -130,6 +130,7 @@ private: std::unique_ptr m_text_writer; std::mutex m_sampler_mutex; + u64 surface_store_tag = 0; std::atomic_bool m_samplers_dirty = { true }; std::array, rsx::limits::fragment_textures_count> fs_sampler_state = {}; std::array, rsx::limits::vertex_textures_count> vs_sampler_state = {}; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index bd7d857b68..5c61525f95 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -112,7 +112,10 @@ namespace vk vk::image_view* get_raw_view() { - return uploaded_image_view.get(); + if (context != rsx::texture_upload_context::framebuffer_storage) + return uploaded_image_view.get(); + else + return static_cast(vram_texture)->get_view(); } vk::image* get_raw_texture()