From 568af756cc26ac82ab8199016b3061808272b700 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 5 Jun 2021 20:05:12 +0300 Subject: [PATCH] rsx: Fix expired sampler descriptors - Rebuilding when strict mode is enabled was incomplete. The copy has to be redone if the source has been updated. --- rpcs3/Emu/RSX/Common/texture_cache.h | 42 +++++++++++++++++++--- rpcs3/Emu/RSX/GL/GLDraw.cpp | 16 +++++---- rpcs3/Emu/RSX/VK/VKDraw.cpp | 52 +++++++++++++++------------- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index f6b59a0ab3..6a58028256 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -1830,8 +1830,8 @@ namespace rsx return {}; } - template - bool test_if_descriptor_expired(commandbuffer_type& cmd, surface_store_type& surface_cache, sampled_image_descriptor* descriptor) + template + bool test_if_descriptor_expired(commandbuffer_type& cmd, surface_store_type& surface_cache, sampled_image_descriptor* descriptor, const RsxTextureType& tex) { auto result = descriptor->is_expired(surface_cache); if (result.second && descriptor->is_cyclic_reference) @@ -1849,9 +1849,41 @@ namespace rsx } else if (descriptor->image_handle) { - descriptor->external_subresource_desc.external_handle = descriptor->image_handle->image(); - descriptor->external_subresource_desc.op = deferred_request_command::copy_image_dynamic; + // Rebuild duplicate surface + auto src = descriptor->image_handle->image(); + rsx::image_section_attributes_t attr; + attr.address = descriptor->ref_address; + attr.gcm_format = tex.format() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + attr.width = src->width(); + attr.height = src->height(); + attr.depth = 1; + attr.mipmaps = 1; + attr.pitch = 0; // Unused + attr.slice_h = src->height(); + attr.bpp = get_format_block_size_in_bytes(attr.gcm_format); + attr.swizzled = false; + + // Sanity checks + const bool gcm_format_is_depth = helpers::is_gcm_depth_format(attr.gcm_format); + const bool bound_surface_is_depth = surface_cache.m_bound_depth_stencil.first == attr.address; + if (!gcm_format_is_depth && bound_surface_is_depth) + { + // While the copy routines can perform a typeless cast, prefer to not cross the aspect barrier if possible + // This avoids messing with other solutions such as texture redirection as well + attr.gcm_format = helpers::get_compatible_depth_format(attr.gcm_format); + } + + descriptor->external_subresource_desc = + { + src, + rsx::deferred_request_command::copy_image_dynamic, + attr, + {}, + rsx::default_remap_vector + }; + descriptor->external_subresource_desc.do_not_cache = true; + descriptor->image_handle = nullptr; } else { @@ -1864,7 +1896,7 @@ namespace rsx } template - sampled_image_descriptor upload_texture(commandbuffer_type& cmd, RsxTextureType& tex, surface_store_type& m_rtts, Args&&... extras) + sampled_image_descriptor upload_texture(commandbuffer_type& cmd, const RsxTextureType& tex, surface_store_type& m_rtts, Args&&... extras) { m_texture_upload_calls_this_frame++; diff --git a/rpcs3/Emu/RSX/GL/GLDraw.cpp b/rpcs3/Emu/RSX/GL/GLDraw.cpp index 04c0b7a65e..3381ac0578 100644 --- a/rpcs3/Emu/RSX/GL/GLDraw.cpp +++ b/rpcs3/Emu/RSX/GL/GLDraw.cpp @@ -285,14 +285,16 @@ void GLGSRender::load_texture_env() fs_sampler_state[i] = std::make_unique(); auto sampler_state = static_cast(fs_sampler_state[i].get()); - if (m_samplers_dirty || m_textures_dirty[i] || m_gl_texture_cache.test_if_descriptor_expired(cmd, m_rtts, sampler_state)) + const auto& tex = rsx::method_registers.fragment_textures[i]; + + if (m_samplers_dirty || m_textures_dirty[i] || m_gl_texture_cache.test_if_descriptor_expired(cmd, m_rtts, sampler_state, tex)) { - if (rsx::method_registers.fragment_textures[i].enabled()) + if (tex.enabled()) { - *sampler_state = m_gl_texture_cache.upload_texture(cmd, rsx::method_registers.fragment_textures[i], m_rtts); + *sampler_state = m_gl_texture_cache.upload_texture(cmd, tex, m_rtts); if (m_textures_dirty[i]) - m_fs_sampler_states[i].apply(rsx::method_registers.fragment_textures[i], fs_sampler_state[i].get()); + m_fs_sampler_states[i].apply(tex, fs_sampler_state[i].get()); } else { @@ -312,14 +314,16 @@ void GLGSRender::load_texture_env() vs_sampler_state[i] = std::make_unique(); auto sampler_state = static_cast(vs_sampler_state[i].get()); - if (m_samplers_dirty || m_vertex_textures_dirty[i] || m_gl_texture_cache.test_if_descriptor_expired(cmd, m_rtts, sampler_state)) + const auto& tex = rsx::method_registers.vertex_textures[i]; + + if (m_samplers_dirty || m_vertex_textures_dirty[i] || m_gl_texture_cache.test_if_descriptor_expired(cmd, m_rtts, sampler_state, tex)) { if (rsx::method_registers.vertex_textures[i].enabled()) { *sampler_state = m_gl_texture_cache.upload_texture(cmd, rsx::method_registers.vertex_textures[i], m_rtts); if (m_vertex_textures_dirty[i]) - m_vs_sampler_states[i].apply(rsx::method_registers.vertex_textures[i], vs_sampler_state[i].get()); + m_vs_sampler_states[i].apply(tex, vs_sampler_state[i].get()); } else *sampler_state = {}; diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index 34ba98e71d..f52dff0cde 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -146,9 +146,9 @@ void VKGSRender::load_texture_env() { // Load textures bool check_for_cyclic_refs = false; - auto check_surface_cache_sampler = [&](auto descriptor) + auto check_surface_cache_sampler = [&](auto descriptor, const auto& tex) { - if (!m_texture_cache.test_if_descriptor_expired(*m_current_command_buffer, m_rtts, descriptor)) + if (!m_texture_cache.test_if_descriptor_expired(*m_current_command_buffer, m_rtts, descriptor, tex)) { check_for_cyclic_refs |= descriptor->is_cyclic_reference; return true; @@ -168,12 +168,14 @@ void VKGSRender::load_texture_env() fs_sampler_state[i] = std::make_unique(); auto sampler_state = static_cast(fs_sampler_state[i].get()); - if (m_samplers_dirty || m_textures_dirty[i] || !check_surface_cache_sampler(sampler_state)) + const auto& tex = rsx::method_registers.fragment_textures[i]; + + if (m_samplers_dirty || m_textures_dirty[i] || !check_surface_cache_sampler(sampler_state, tex)) { - if (rsx::method_registers.fragment_textures[i].enabled()) + if (tex.enabled()) { check_heap_status(VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE); - *sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, rsx::method_registers.fragment_textures[i], m_rtts); + *sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts); if (sampler_state->is_cyclic_reference) { @@ -186,21 +188,21 @@ void VKGSRender::load_texture_env() f32 min_lod = 0.f, max_lod = 0.f; f32 lod_bias = 0.f; - const u32 texture_format = rsx::method_registers.fragment_textures[i].format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); + const u32 texture_format = tex.format() & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); VkBool32 compare_enabled = VK_FALSE; VkCompareOp depth_compare_mode = VK_COMPARE_OP_NEVER; if (texture_format >= CELL_GCM_TEXTURE_DEPTH24_D8 && texture_format <= CELL_GCM_TEXTURE_DEPTH16_FLOAT) { compare_enabled = VK_TRUE; - depth_compare_mode = vk::get_compare_func(rsx::method_registers.fragment_textures[i].zfunc(), true); + depth_compare_mode = vk::get_compare_func(tex.zfunc(), true); } - const f32 af_level = vk::max_aniso(rsx::method_registers.fragment_textures[i].max_aniso()); - const auto wrap_s = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_s()); - const auto wrap_t = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_t()); - const auto wrap_r = vk::vk_wrap_mode(rsx::method_registers.fragment_textures[i].wrap_r()); - const auto border_color = vk::get_border_color(rsx::method_registers.fragment_textures[i].border_color()); + const f32 af_level = vk::max_aniso(tex.max_aniso()); + const auto wrap_s = vk::vk_wrap_mode(tex.wrap_s()); + const auto wrap_t = vk::vk_wrap_mode(tex.wrap_t()); + const auto wrap_r = vk::vk_wrap_mode(tex.wrap_r()); + const auto border_color = vk::get_border_color(tex.border_color()); // Check if non-point filtering can even be used on this format bool can_sample_linear; @@ -218,12 +220,12 @@ void VKGSRender::load_texture_env() can_sample_linear = m_device->get_format_properties(vk_format).optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; } - const auto mipmap_count = rsx::method_registers.fragment_textures[i].get_exact_mipmap_count(); - min_filter = vk::get_min_filter(rsx::method_registers.fragment_textures[i].min_filter()); + const auto mipmap_count = tex.get_exact_mipmap_count(); + min_filter = vk::get_min_filter(tex.min_filter()); if (can_sample_linear) { - mag_filter = vk::get_mag_filter(rsx::method_registers.fragment_textures[i].mag_filter()); + mag_filter = vk::get_mag_filter(tex.mag_filter()); } else { @@ -250,9 +252,9 @@ void VKGSRender::load_texture_env() if (actual_mipmaps > 1.f) { - min_lod = rsx::method_registers.fragment_textures[i].min_lod(); - max_lod = rsx::method_registers.fragment_textures[i].max_lod(); - lod_bias = rsx::method_registers.fragment_textures[i].bias(); + min_lod = tex.min_lod(); + max_lod = tex.max_lod(); + lod_bias = tex.bias(); min_lod = std::min(min_lod, actual_mipmaps - 1.f); max_lod = std::min(max_lod, actual_mipmaps - 1.f); @@ -304,12 +306,14 @@ void VKGSRender::load_texture_env() vs_sampler_state[i] = std::make_unique(); auto sampler_state = static_cast(vs_sampler_state[i].get()); - if (m_samplers_dirty || m_vertex_textures_dirty[i] || !check_surface_cache_sampler(sampler_state)) + const auto& tex = rsx::method_registers.vertex_textures[i]; + + if (m_samplers_dirty || m_vertex_textures_dirty[i] || !check_surface_cache_sampler(sampler_state, tex)) { if (rsx::method_registers.vertex_textures[i].enabled()) { check_heap_status(VK_HEAP_CHECK_TEXTURE_UPLOAD_STORAGE); - *sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, rsx::method_registers.vertex_textures[i], m_rtts); + *sampler_state = m_texture_cache.upload_texture(*m_current_command_buffer, tex, m_rtts); if (sampler_state->is_cyclic_reference || sampler_state->external_subresource_desc.do_not_cache) { @@ -317,10 +321,10 @@ void VKGSRender::load_texture_env() } bool replace = !vs_sampler_handles[i]; - const VkBool32 unnormalized_coords = !!(rsx::method_registers.vertex_textures[i].format() & CELL_GCM_TEXTURE_UN); - const auto min_lod = rsx::method_registers.vertex_textures[i].min_lod(); - const auto max_lod = rsx::method_registers.vertex_textures[i].max_lod(); - const auto border_color = vk::get_border_color(rsx::method_registers.vertex_textures[i].border_color()); + const VkBool32 unnormalized_coords = !!(tex.format() & CELL_GCM_TEXTURE_UN); + const auto min_lod = tex.min_lod(); + const auto max_lod = tex.max_lod(); + const auto border_color = vk::get_border_color(tex.border_color()); if (vs_sampler_handles[i]) {