diff --git a/rpcs3/Emu/RSX/Common/surface_store.h b/rpcs3/Emu/RSX/Common/surface_store.h index 758a169e5..1e57604d1 100644 --- a/rpcs3/Emu/RSX/Common/surface_store.h +++ b/rpcs3/Emu/RSX/Common/surface_store.h @@ -52,6 +52,8 @@ namespace rsx bool m_invalidate_on_write = false; bool m_skip_write_updates = false; + rsx::surface_raster_type m_active_raster_type = rsx::surface_raster_type::linear; + public: std::pair m_bound_render_targets_config = {}; std::array, 4> m_bound_render_targets = {}; @@ -672,6 +674,7 @@ namespace rsx u32 clip_horizontal_reg, u32 clip_vertical_reg, surface_target set_surface_target, surface_antialiasing antialias, + surface_raster_type raster_type, const std::array &surface_addresses, u32 address_z, const std::array &surface_pitch, u32 zeta_pitch, Args&&... extra_params) @@ -681,6 +684,7 @@ namespace rsx cache_tag = rsx::get_shared_tag(); m_invalidate_on_write = (antialias != rsx::surface_antialiasing::center_1_sample); + m_active_raster_type = raster_type; m_bound_buffers_count = 0; // Make previous RTTs sampleable @@ -995,7 +999,7 @@ namespace rsx auto& surface = m_bound_render_targets[i].second; if (surface->last_use_tag != write_tag) { - m_bound_render_targets[i].second->on_write(write_tag); + m_bound_render_targets[i].second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type); } else if (m_invalidate_on_write) { @@ -1011,7 +1015,7 @@ namespace rsx auto& surface = m_bound_depth_stencil.second; if (surface->last_use_tag != write_tag) { - m_bound_depth_stencil.second->on_write(write_tag); + m_bound_depth_stencil.second->on_write(write_tag, surface_state_flags::require_resolve, m_active_raster_type); } else if (m_invalidate_on_write) { diff --git a/rpcs3/Emu/RSX/Common/surface_utils.h b/rpcs3/Emu/RSX/Common/surface_utils.h index fe4c9cb17..9173ddd74 100644 --- a/rpcs3/Emu/RSX/Common/surface_utils.h +++ b/rpcs3/Emu/RSX/Common/surface_utils.h @@ -139,6 +139,7 @@ namespace rsx std::unique_ptr::type> resolve_surface; surface_sample_layout sample_layout = surface_sample_layout::null; + surface_raster_type raster_type = surface_raster_type::linear; flags32_t memory_usage_flags = surface_usage_flags::unknown; flags32_t state_flags = surface_state_flags::ready; @@ -506,7 +507,9 @@ namespace rsx } } - void on_write(u64 write_tag = 0, rsx::surface_state_flags resolve_flags = surface_state_flags::require_resolve) + void on_write(u64 write_tag = 0, + rsx::surface_state_flags resolve_flags = surface_state_flags::require_resolve, + surface_raster_type type = rsx::surface_raster_type::undefined) { if (write_tag) { @@ -529,11 +532,18 @@ namespace rsx { clear_rw_barrier(); } + + if (type != rsx::surface_raster_type::undefined) + { + raster_type = type; + } } - void on_write_copy(u64 write_tag = 0, bool keep_optimizations = false) + void on_write_copy(u64 write_tag = 0, + bool keep_optimizations = false, + surface_raster_type type = rsx::surface_raster_type::undefined) { - on_write(write_tag, rsx::surface_state_flags::require_unresolve); + on_write(write_tag, rsx::surface_state_flags::require_unresolve, type); if (!keep_optimizations && is_depth_surface()) { diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index e5807f09b..1b7e2f89c 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -318,7 +318,7 @@ namespace rsx virtual image_view_type create_temporary_subresource_view(commandbuffer_type&, image_storage_type* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h, const texture_channel_remap_t& remap_vector) = 0; virtual void release_temporary_subresource(image_view_type rsc) = 0; virtual section_storage_type* create_new_texture(commandbuffer_type&, const address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, - rsx::texture_upload_context context, rsx::texture_dimension_extended type, texture_create_flags flags) = 0; + rsx::texture_upload_context context, rsx::texture_dimension_extended type, bool swizzled, texture_create_flags flags) = 0; virtual section_storage_type* upload_image_from_cpu(commandbuffer_type&, const address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool swizzled) = 0; virtual section_storage_type* create_nul_section(commandbuffer_type&, const address_range &rsx_range, bool memory_load) = 0; @@ -1597,6 +1597,14 @@ namespace rsx continue; } #endif + if (attr.swizzled != cached_texture->is_swizzled()) + { + // We can have the correct data in cached_texture but it needs decoding before it can be sampled. + // Usually a sign of a game bug where the developer forgot to mark the texture correctly the first time we see it. + rsx_log.error("A texture was found in cache for address 0x%x, but swizzle flag does not match", attr.address); + continue; + } + return{ cached_texture->get_view(encoded_remap, remap), cached_texture->get_context(), cached_texture->get_format_type(), scale, cached_texture->get_image_type() }; } } @@ -1743,9 +1751,9 @@ namespace rsx attributes.bpp = get_format_block_size_in_bytes(attributes.gcm_format); attributes.width = tex.width(); attributes.height = tex.height(); + attributes.swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN); const bool is_unnormalized = !!(tex.format() & CELL_GCM_TEXTURE_UN); - const bool is_swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN); auto extended_dimension = tex.get_extended_texture_dimension(); options.is_compressed_format = helpers::is_compressed_gcm_format(attributes.gcm_format); @@ -1767,8 +1775,8 @@ namespace rsx } } - const auto packed_pitch = get_format_packed_pitch(attributes.gcm_format, attributes.width, !tex.border_type(), is_swizzled); - if (!is_swizzled) [[likely]] + const auto packed_pitch = get_format_packed_pitch(attributes.gcm_format, attributes.width, !tex.border_type(), attributes.swizzled); + if (!attributes.swizzled) [[likely]] { if (attributes.pitch = tex.pitch(); !attributes.pitch) { @@ -1883,7 +1891,7 @@ namespace rsx attr2.height = std::max(attr2.height / 2, 1); attr2.slice_h = attr2.height; - if (is_swizzled) + if (attributes.swizzled) { attr2.pitch = attr2.width * attr2.bpp; } @@ -1943,7 +1951,7 @@ namespace rsx // Upload from CPU. Note that sRGB conversion is handled in the FS auto uploaded = upload_image_from_cpu(cmd, tex_range, attributes.width, attributes.height, attributes.depth, tex.get_exact_mipmap_count(), attributes.pitch, attributes.gcm_format, - texture_upload_context::shader_read, subresources_layout, extended_dimension, is_swizzled); + texture_upload_context::shader_read, subresources_layout, extended_dimension, attributes.swizzled); return{ uploaded->get_view(tex.remap(), tex.decoded_remap()), texture_upload_context::shader_read, format_class, scale, extended_dimension }; @@ -2672,7 +2680,7 @@ namespace rsx { cached_dest = create_new_texture(cmd, rsx_range, dst_dimensions.width, dst_dimensions.height, 1, 1, dst.pitch, preferred_dst_format, rsx::texture_upload_context::blit_engine_dst, rsx::texture_dimension_extended::texture_dimension_2d, - channel_order); + false, channel_order); } else { @@ -2710,6 +2718,9 @@ namespace rsx // Invalidate any cached subresources in modified range notify_surface_changed(dst_range); + // What type of data is being moved? + const auto raster_type = src_is_render_target ? src_subres.surface->raster_type : rsx::surface_raster_type::undefined; + if (cached_dest) { // Validate modified range @@ -2721,12 +2732,15 @@ namespace rsx cached_dest->reprotect(utils::protection::no, { mem_offset, dst_payload_length }); cached_dest->touch(m_cache_update_tag); update_cache_tag(); + + // Set swizzle flag + cached_dest->set_swizzled(raster_type == rsx::surface_raster_type::swizzle); } else { // NOTE: This doesn't work very well in case of Cell access // Need to lock the affected memory range and actually attach this subres to a locked_region - dst_subres.surface->on_write_copy(rsx::get_shared_tag()); + dst_subres.surface->on_write_copy(rsx::get_shared_tag(), false, raster_type); m_rtts.notify_memory_structure_changed(); // Reset this object's synchronization status if it is locked diff --git a/rpcs3/Emu/RSX/Common/texture_cache_helpers.h b/rpcs3/Emu/RSX/Common/texture_cache_helpers.h index 236ffaf60..ea496a4f9 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache_helpers.h +++ b/rpcs3/Emu/RSX/Common/texture_cache_helpers.h @@ -56,6 +56,7 @@ namespace rsx u16 pitch; u16 slice_h; u8 bpp; + bool swizzled; }; struct blit_op_result diff --git a/rpcs3/Emu/RSX/Common/texture_cache_utils.h b/rpcs3/Emu/RSX/Common/texture_cache_utils.h index 27df2fc79..c03fd4bfc 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache_utils.h +++ b/rpcs3/Emu/RSX/Common/texture_cache_utils.h @@ -1019,6 +1019,7 @@ namespace rsx u32 gcm_format = 0; bool pack_unpack_swap_bytes = false; + bool swizzled = false; u64 sync_timestamp = 0; bool synchronized = false; @@ -1584,6 +1585,11 @@ namespace rsx gcm_format = format; } + void set_swizzled(bool is_swizzled) + { + swizzled = is_swizzled; + } + void set_memory_read_flags(memory_read_flags flags, bool notify_texture_cache = true) { const bool changed = (flags != readback_behaviour); @@ -1651,6 +1657,11 @@ namespace rsx return gcm_format; } + bool is_swizzled() const + { + return swizzled; + } + memory_read_flags get_memory_read_flags() const { return readback_behaviour; @@ -1681,12 +1692,12 @@ namespace rsx /** * Comparison */ - inline bool matches(const address_range &memory_range) + inline bool matches(const address_range &memory_range) const { return valid_range() && rsx::buffered_section::matches(memory_range); } - bool matches(u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) + bool matches(u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) const { if (!valid_range()) return false; @@ -1712,7 +1723,7 @@ namespace rsx return true; } - bool matches(u32 rsx_address, u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) + bool matches(u32 rsx_address, u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) const { if (!valid_range()) return false; @@ -1723,7 +1734,7 @@ namespace rsx return matches(format, width, height, depth, mipmaps); } - bool matches(const address_range& memory_range, u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) + bool matches(const address_range& memory_range, u32 format, u32 width, u32 height, u32 depth, u32 mipmaps) const { if (!valid_range()) return false; diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp index e0c90bbe0..665875e53 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.cpp @@ -163,7 +163,7 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk m_rtts.prepare_render_target(cmd, m_framebuffer_layout.color_format, m_framebuffer_layout.depth_format, m_framebuffer_layout.width, m_framebuffer_layout.height, - m_framebuffer_layout.target, m_framebuffer_layout.aa_mode, + m_framebuffer_layout.target, m_framebuffer_layout.aa_mode, m_framebuffer_layout.raster_type, m_framebuffer_layout.color_addresses, m_framebuffer_layout.zeta_address, m_framebuffer_layout.actual_color_pitch, m_framebuffer_layout.actual_zeta_pitch); diff --git a/rpcs3/Emu/RSX/GL/GLRenderTargets.h b/rpcs3/Emu/RSX/GL/GLRenderTargets.h index b790af304..728d9094c 100644 --- a/rpcs3/Emu/RSX/GL/GLRenderTargets.h +++ b/rpcs3/Emu/RSX/GL/GLRenderTargets.h @@ -240,6 +240,7 @@ struct gl_render_target_traits sink->set_rsx_pitch(ref->get_rsx_pitch()); sink->set_old_contents_region(prev, false); sink->last_use_tag = ref->last_use_tag; + sink->raster_type = ref->raster_type; // Can't actually cut up swizzled data } static @@ -275,6 +276,7 @@ struct gl_render_target_traits surface->last_use_tag = 0; surface->stencil_init_flags = 0; surface->memory_usage_flags = rsx::surface_usage_flags::unknown; + surface->raster_type = rsx::surface_raster_type::linear; } static diff --git a/rpcs3/Emu/RSX/GL/GLTextureCache.h b/rpcs3/Emu/RSX/GL/GLTextureCache.h index 1a0bc4fac..f825ffb66 100644 --- a/rpcs3/Emu/RSX/GL/GLTextureCache.h +++ b/rpcs3/Emu/RSX/GL/GLTextureCache.h @@ -818,7 +818,7 @@ namespace gl } cached_texture_section* create_new_texture(gl::command_context&, const utils::address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, - u32 gcm_format, rsx::texture_upload_context context, rsx::texture_dimension_extended type, rsx::texture_create_flags flags) override + u32 gcm_format, rsx::texture_upload_context context, rsx::texture_dimension_extended type, bool swizzled, rsx::texture_create_flags flags) override { auto image = gl::create_texture(gcm_format, width, height, depth, mipmaps, type); @@ -834,6 +834,7 @@ namespace gl cached.set_context(context); cached.set_image_type(type); cached.set_gcm_format(gcm_format); + cached.set_swizzled(swizzled); cached.create(width, height, depth, mipmaps, image, pitch, true); cached.set_dirty(false); @@ -901,7 +902,7 @@ namespace gl cached_texture_section* upload_image_from_cpu(gl::command_context &cmd, const utils::address_range& rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, rsx::texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool input_swizzled) override { - auto section = create_new_texture(cmd, rsx_range, width, height, depth, mipmaps, pitch, gcm_format, context, type, + auto section = create_new_texture(cmd, rsx_range, width, height, depth, mipmaps, pitch, gcm_format, context, type, input_swizzled, rsx::texture_create_flags::default_component_order); gl::upload_texture(section->get_raw_texture()->id(), gcm_format, width, height, depth, mipmaps, diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 6c19383c2..57ac6d15d 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -1119,10 +1119,10 @@ namespace rsx u32 minimum_color_pitch = 64u; u32 minimum_zeta_pitch = 64u; - switch (const auto mode = rsx::method_registers.surface_type()) + switch (layout.raster_type = rsx::method_registers.surface_type()) { default: - rsx_log.error("Unknown raster mode 0x%x", static_cast(mode)); + rsx_log.error("Unknown raster mode 0x%x", static_cast(layout.raster_type)); [[fallthrough]]; case rsx::surface_raster_type::linear: break; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 853e1c72d..858d32b07 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -342,6 +342,7 @@ namespace rsx rsx::surface_color_format color_format; rsx::surface_depth_format depth_format; rsx::surface_antialiasing aa_mode; + rsx::surface_raster_type raster_type; u32 aa_factors[2]; bool depth_float; bool ignore_change; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index f527443f6..97d6a24e2 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2030,7 +2030,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context) m_rtts.prepare_render_target(*m_current_command_buffer, m_framebuffer_layout.color_format, m_framebuffer_layout.depth_format, m_framebuffer_layout.width, m_framebuffer_layout.height, - m_framebuffer_layout.target, m_framebuffer_layout.aa_mode, + m_framebuffer_layout.target, m_framebuffer_layout.aa_mode, m_framebuffer_layout.raster_type, m_framebuffer_layout.color_addresses, m_framebuffer_layout.zeta_address, m_framebuffer_layout.actual_color_pitch, m_framebuffer_layout.actual_zeta_pitch, (*m_device), *m_current_command_buffer); diff --git a/rpcs3/Emu/RSX/VK/VKRenderTargets.h b/rpcs3/Emu/RSX/VK/VKRenderTargets.h index 9189ae6fb..c7d8e8579 100644 --- a/rpcs3/Emu/RSX/VK/VKRenderTargets.h +++ b/rpcs3/Emu/RSX/VK/VKRenderTargets.h @@ -813,6 +813,7 @@ namespace rsx sink->rsx_pitch = ref->get_rsx_pitch(); sink->set_old_contents_region(prev, false); sink->last_use_tag = ref->last_use_tag; + sink->raster_type = ref->raster_type; // Can't actually cut up swizzled data } static bool is_compatible_surface(const vk::render_target* surface, const vk::render_target* ref, u16 width, u16 height, u8 sample_count) @@ -853,6 +854,7 @@ namespace rsx surface->last_use_tag = 0; surface->stencil_init_flags = 0; surface->memory_usage_flags = rsx::surface_usage_flags::unknown; + surface->raster_type = rsx::surface_raster_type::linear; } static void notify_surface_invalidated(const std::unique_ptr &surface) diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index 7f753a3a5..88aefec7f 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -1100,7 +1100,7 @@ namespace vk } cached_texture_section* create_new_texture(vk::command_buffer& cmd, const utils::address_range &rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, - u32 gcm_format, rsx::texture_upload_context context, rsx::texture_dimension_extended type, rsx::texture_create_flags flags) override + u32 gcm_format, rsx::texture_upload_context context, rsx::texture_dimension_extended type, bool swizzled, rsx::texture_create_flags flags) override { const u16 section_depth = depth; const bool is_cubemap = type == rsx::texture_dimension_extended::texture_dimension_cubemap; @@ -1180,6 +1180,7 @@ namespace vk region.set_context(context); region.set_gcm_format(gcm_format); region.set_image_type(type); + region.set_swizzled(swizzled); region.create(width, height, section_depth, mipmaps, image, pitch, true, gcm_format); region.set_dirty(false); @@ -1232,7 +1233,7 @@ namespace vk cached_texture_section* upload_image_from_cpu(vk::command_buffer& cmd, const utils::address_range& rsx_range, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format, rsx::texture_upload_context context, const std::vector& subresource_layout, rsx::texture_dimension_extended type, bool swizzled) override { - auto section = create_new_texture(cmd, rsx_range, width, height, depth, mipmaps, pitch, gcm_format, context, type, + auto section = create_new_texture(cmd, rsx_range, width, height, depth, mipmaps, pitch, gcm_format, context, type, swizzled, rsx::texture_create_flags::default_component_order); auto image = section->get_raw_texture(); diff --git a/rpcs3/Emu/RSX/gcm_enums.h b/rpcs3/Emu/RSX/gcm_enums.h index 9315e1c73..e43b7bf1f 100644 --- a/rpcs3/Emu/RSX/gcm_enums.h +++ b/rpcs3/Emu/RSX/gcm_enums.h @@ -61,6 +61,7 @@ namespace rsx enum class surface_raster_type : u8 { + undefined = 0, linear = 1, swizzle = 2, };