From 451f503975c273a506e1954be9fbaee7cbcaff54 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Thu, 9 Jul 2026 22:28:20 +0300 Subject: [PATCH] rsx: Move blit_engine_utils nested group to protected section (refactor part10) --- rpcs3/Emu/RSX/Common/texture_cache.h | 754 +++++++++++++-------------- 1 file changed, 377 insertions(+), 377 deletions(-) diff --git a/rpcs3/Emu/RSX/Common/texture_cache.h b/rpcs3/Emu/RSX/Common/texture_cache.h index 7f98ab487c..457baf3362 100644 --- a/rpcs3/Emu/RSX/Common/texture_cache.h +++ b/rpcs3/Emu/RSX/Common/texture_cache.h @@ -1225,6 +1225,377 @@ namespace rsx #endif // TEXTURE_CACHE_DEBUG } + // Pseudo-manespace wrapper. Functions extracted from upload_scaled_image + struct blit_engine_internals + { + // Confirms that an FBO-backed section is still locked/consistent before we treat it as a valid GPU source or target. + static bool validate_fbo_integrity(texture_cache* cache, const utils::address_range32& range, bool is_depth_texture) + { + const bool will_upload = is_depth_texture ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers; + if (!will_upload) + { + // Give a pass. The data is lost anyway. + return true; + } + + const bool should_be_locked = is_depth_texture ? !!g_cfg.video.write_depth_buffer : !!g_cfg.video.write_color_buffers; + if (!should_be_locked) + { + // Data is lost anyway. + return true; + } + + // Optimal setup. We have ideal conditions presented so we can correctly decide what to do here. + const auto section = cache->find_cached_texture(range, { .gcm_format = RSX_GCM_FORMAT_IGNORED }, false, false, false); + return section && section->is_locked(); + } + + // Finds a render target in the surface store that overlaps the requested region (extracted from upload_scaled_image). + template + static + typename surface_store_type::surface_overlap_info rtt_lookup( + surface_store_type& m_rtts, + commandbuffer_type& cmd, + u32 address, + u32 width, + u32 height, + u32 pitch, + u8 bpp, + rsx::flags32_t access, + bool allow_clipped, + f32 scale_x, + f32 scale_y) + { + const auto list = m_rtts.get_merged_texture_memory_region(cmd, address, width, height, pitch, bpp, access); + if (list.empty()) + { + return {}; + } + + for (auto It = list.rbegin(); It != list.rend(); ++It) + { + if (!(It->surface->memory_usage_flags & rsx::surface_usage_flags::attachment)) + { + // HACK + // TODO: Properly analyse the input here to determine if it can properly fit what we need + // This is a problem due to chunked transfer + // First 2 512x720 blocks go into a cpu-side buffer but suddenly when its time to render the final 256x720 + // it falls onto some storage buffer in surface cache that has bad dimensions + // Proper solution is to always merge when a cpu resource is created (it should absorb the render targets in range) + // We then should not have any 'dst-is-rendertarget' surfaces in use + // Option 2: Make surfaces here part of surface cache and do not pad them for optimization + // Surface cache is good at merging for resolve operations. This keeps integrity even when drawing to the rendertgargets + // This option needs a lot more work + continue; + } + + if (!It->is_clipped || allow_clipped) + { + return *It; + } + + const auto _w = It->dst_area.width; + const auto _h = It->dst_area.height; + + if (_w < width) + { + if ((_w * scale_x) <= 1.f) + continue; + } + + if (_h < height) + { + if ((_h * scale_y) <= 1.f) + continue; + } + + // Some surface exists, but its size is questionable + // Opt to re-upload (needs WCB/WDB to work properly) + break; + } + + return {}; + } + + // Resolves the blit source when it is not already a render target: reuses an overlapping cached texture if one matches, otherwise uploads the source image from CPU. + // Out parameters: cached_src, vram_texture, the src side of typeless_info and adjusts src_area. + template + static void get_or_create_blit_src( + texture_cache* cache, + commandbuffer_type& cmd, + const rsx::blit_src_info& src, + const rsx::blit_dst_info& dst, + u32 src_address, + u32 src_payload_length, + u8 src_bpp, + u16 src_h, + bool src_is_argb8, + bool dst_is_render_target, + bool dst_is_depth_surface, + bool is_copy_op, + bool is_format_convert, + areai& src_area, + /*out*/ section_storage_type*& cached_src, + /*out*/ image_resource_type& vram_texture, + /*out*/ typeless_xfer& typeless_info, + reader_lock& lock, + Args&&... extras) + { + // NOTE: Src address already takes into account the flipped nature of the overlap! + const u32 lookup_mask = rsx::texture_upload_context::blit_engine_src | rsx::texture_upload_context::shader_read; + auto overlapping_surfaces = cache->find_texture_from_range(address_range32::start_length(src_address, src_payload_length), src.pitch, lookup_mask); + auto old_src_area = src_area; + + for (const auto& surface : overlapping_surfaces) + { + if (!surface->is_locked()) + { + // TODO: Rejecting unlocked blit_engine dst causes stutter in SCV + // Surfaces marked as dirty have already been removed, leaving only flushed blit_dst data + continue; + } + + // Force format matching; only accept 16-bit data for 16-bit transfers, 32-bit for 32-bit transfers + if (!blit_engine_helpers::is_blit_source_format_compatible(surface->get_gcm_format(), src_is_argb8, is_copy_op, dst_is_render_target)) + { + continue; + } + + const auto this_address = surface->get_section_base(); + if (this_address > src_address) + { + continue; + } + + if (const u32 address_offset = src_address - this_address) + { + const u32 offset_y = address_offset / src.pitch; + const u32 offset_x = address_offset % src.pitch; + const u32 offset_x_in_block = offset_x / src_bpp; + + src_area.x1 += offset_x_in_block; + src_area.x2 += offset_x_in_block; + src_area.y1 += offset_y; + src_area.y2 += offset_y; + } + + if (src_area.x2 <= surface->get_width() && + src_area.y2 <= surface->get_height()) + { + cached_src = surface; + break; + } + + src_area = old_src_area; + } + + if (!cached_src) + { + const u16 full_width = src.pitch / src_bpp; + u32 image_base = src.rsx_address; + u16 image_width = full_width; + u16 image_height = src.height; + + // Check if memory is valid + const bool use_full_range = blit_engine_helpers::validate_memory_range( + image_base, + (src_address + src_payload_length), + image_base + (image_height * src.pitch)); + + if (use_full_range && dst.scale_x > 0.f && dst.scale_y > 0.f) [[likely]] + { + // Loading full image from the corner address + // Translate src_area into the declared block + src_area.x1 += src.offset_x; + src_area.x2 += src.offset_x; + src_area.y1 += src.offset_y; + src_area.y2 += src.offset_y; + } + else + { + image_base = src_address; + image_height = src_h; + } + + std::vector subresource_layout; + rsx::subresource_layout subres = {}; + subres.width_in_block = subres.width_in_texel = image_width; + subres.height_in_block = subres.height_in_texel = image_height; + subres.pitch_in_block = full_width; + subres.depth = 1; + subres.data = { vm::_ptr(image_base), static_cast::size_type>(src.pitch * image_height) }; + subresource_layout.push_back(std::move(subres)); + + const u32 gcm_format = helpers::get_sized_blit_format(src_is_argb8, dst_is_depth_surface, is_format_convert); + const auto rsx_range = address_range32::start_length(image_base, src.pitch * image_height); + + lock.upgrade(); + + cache->invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::read, {}, std::forward(extras)...); + + cached_src = cache->upload_image_from_cpu(cmd, rsx_range, image_width, image_height, 1, 1, src.pitch, gcm_format, texture_upload_context::blit_engine_src, + subresource_layout, rsx::texture_dimension_extended::texture_dimension_2d, dst.swizzled); + + typeless_info.src_gcm_format = gcm_format; + } + else + { + typeless_info.src_gcm_format = cached_src->get_gcm_format(); + } + + cached_src->add_ref(); + vram_texture = cached_src->get_raw_texture(); + typeless_info.src_context = cached_src->get_context(); + } + + // Creates the blit destination when it is neither an existing render target nor an existing DMA section. + // Out params: cached_dest, or promotes dst to a render target (dst_subres/dst_is_render_target/dest_texture and the dst side of typeless_info) and adjusts dst_dimensions/dst_area. + template + static void create_blit_dst( + texture_cache* cache, + commandbuffer_type& cmd, + surface_store_type& m_rtts, + const rsx::blit_dst_info& dst, + u32 dst_address, + u32 dst_payload_length, + u32 dst_base_address, + u16 dst_w, + u8 dst_bpp, + const address_range32& dst_range, + const GCM_tile_reference& dst_tile, + const position2i& dst_offset, + u32 preferred_dst_format, + bool src_is_render_target, + bool dst_is_argb8, + bool use_null_region, + /*out*/ size2i& dst_dimensions, + /*out*/ areai& dst_area, + /*out*/ section_storage_type*& cached_dest, + /*out*/ typename surface_store_type::surface_overlap_info& dst_subres, + /*out*/ bool& dst_is_render_target, + /*out*/ image_resource_type& dest_texture, + /*out*/ typeless_xfer& typeless_info, + reader_lock& lock, + Args&&... extras) + { + ensure(!dest_texture); + + // Need to calculate the minimum required size that will fit the data, anchored on the rsx_address + // If the application starts off with an 'inseted' section, the guessed dimensions may not fit! + const u32 write_end = dst_address + dst_payload_length; + u32 block_end = dst_base_address + (dst.pitch * dst_dimensions.height); + + // Confirm if the pages actually exist in vm + if (!blit_engine_helpers::validate_memory_range(dst_base_address, write_end, block_end)) + { + block_end = write_end; + } + + const u32 usable_section_length = std::max(write_end, block_end) - dst_base_address; + dst_dimensions.height = align2(usable_section_length, dst.pitch) / dst.pitch; + + const u32 full_section_length = ((dst_dimensions.height - 1) * dst.pitch) + (dst_dimensions.width * dst_bpp); + const auto rsx_range = address_range32::start_length(dst_base_address, full_section_length); + + lock.upgrade(); + + // NOTE: Write flag set to remove all other overlapping regions (e.g shader_read or blit_src) + // NOTE: This step can potentially invalidate the newly created src image as well. + cache->invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::cause_is_write | invalidation_cause::cause_uses_strict_data_bounds, {}, std::forward(extras)...); + + if (use_null_region) [[likely]] + { + bool force_dma_load = false; + if ((dst_w * dst_bpp) != dst.pitch) + { + // Keep Cell from touching the range we need + const auto prot_range = dst_range.to_page_range(); + utils::memory_protect(vm::base(prot_range.start), prot_range.length(), utils::protection::no); + + force_dma_load = true; + } + + const image_section_attributes_t attrs = + { + .pitch = dst.pitch, + .width = static_cast(dst_dimensions.width), + .height = static_cast(dst_dimensions.height), + .bpp = dst_bpp + }; + cached_dest = cache->create_nul_section(cmd, rsx_range, attrs, dst_tile, force_dma_load); + } + else + { + // render target data is already in correct swizzle layout + [[maybe_unused]] auto channel_order = src_is_render_target ? rsx::component_order::native : + dst_is_argb8 ? rsx::component_order::default_ : + rsx::component_order::swapped_native; + + // Translate dst_area into the 'full' dst block based on dst.rsx_address as (0, 0) + dst_area.x1 += dst_offset.x; + dst_area.x2 += dst_offset.x; + dst_area.y1 += dst_offset.y; + dst_area.y2 += dst_offset.y; + + // We have to create the surface in the surface cache + rsx::image_section_attributes_t section_attr + { + .address = rsx_range.start, + .gcm_format = preferred_dst_format, + .pitch = dst.pitch, + .width = static_cast(dst_dimensions.width), + .height = static_cast(dst_dimensions.height), + .depth = 1, + .mipmaps = 1, + .slice_h = static_cast(dst_dimensions.height), + .bpp = dst_bpp, + .swizzled = false, + .edge_clamped = false + }; + + auto dst_surface = m_rtts.create_surface_from_rsx_section( + cmd, + section_attr, + std::forward(extras)...); + + ensure(dst_surface, "Failed to create target surface"); + //dst_surface->set_name(fmt::format("Blit target @0x%x", section_attr.address)); + + if (!dst_area.x1 && !dst_area.y1 && dst_area.x2 == dst_dimensions.width && dst_area.y2 == dst_dimensions.height) + { + // Nothing to do, not even a background erase is needed here + dst_surface->state_flags &= ~rsx::surface_state_flags::erase_bkgnd; + } + else + { + // HACK: workaround for data race with Cell + // Pre-lock the memory range we'll be touching, then load with super_ptr + const auto prot_range = dst_range.to_page_range(); + utils::memory_protect(vm::base(prot_range.start), prot_range.length(), utils::protection::no); + + dst_surface->state_flags |= rsx::surface_state_flags::force_data_load | rsx::surface_state_flags::erase_bkgnd; + // set_component_order(*cached_dest, preferred_dst_format, channel_order); + } + + // Lock this for readback. That also creates a matching section + cache->lock_memory_region_impl( + cmd, dst_surface, dst_surface->get_memory_range(), false, + dst_surface->get_surface_width(), + dst_surface->get_surface_height(), + dst_surface->get_rsx_pitch(), + dst_surface); + + // Fake RTT cache hit + dst_subres.surface = dst_surface; + dst_is_render_target = true; + + dest_texture = dst_surface->get_surface(rsx::surface_access::transfer_write); + typeless_info.dst_context = texture_upload_context::framebuffer_storage; + typeless_info.dst_gcm_format = preferred_dst_format; + } + } + }; + public: texture_cache() : m_storage(this), m_predictor(this) {} @@ -2532,377 +2903,6 @@ namespace rsx texture_upload_context::shader_read, format_class, scale, extended_dimension }; } - // Pseudo-manespace wrapper. Functions extracted from upload_scaled_image - struct blit_engine_utils - { - // Confirms that an FBO-backed section is still locked/consistent before we treat it as a valid GPU source or target. - static bool validate_fbo_integrity(texture_cache* cache, const utils::address_range32& range, bool is_depth_texture) - { - const bool will_upload = is_depth_texture ? !!g_cfg.video.read_depth_buffer : !!g_cfg.video.read_color_buffers; - if (!will_upload) - { - // Give a pass. The data is lost anyway. - return true; - } - - const bool should_be_locked = is_depth_texture ? !!g_cfg.video.write_depth_buffer : !!g_cfg.video.write_color_buffers; - if (!should_be_locked) - { - // Data is lost anyway. - return true; - } - - // Optimal setup. We have ideal conditions presented so we can correctly decide what to do here. - const auto section = cache->find_cached_texture(range, { .gcm_format = RSX_GCM_FORMAT_IGNORED }, false, false, false); - return section && section->is_locked(); - } - - // Finds a render target in the surface store that overlaps the requested region (extracted from upload_scaled_image). - template - static - typename surface_store_type::surface_overlap_info rtt_lookup( - surface_store_type& m_rtts, - commandbuffer_type& cmd, - u32 address, - u32 width, - u32 height, - u32 pitch, - u8 bpp, - rsx::flags32_t access, - bool allow_clipped, - f32 scale_x, - f32 scale_y) - { - const auto list = m_rtts.get_merged_texture_memory_region(cmd, address, width, height, pitch, bpp, access); - if (list.empty()) - { - return {}; - } - - for (auto It = list.rbegin(); It != list.rend(); ++It) - { - if (!(It->surface->memory_usage_flags & rsx::surface_usage_flags::attachment)) - { - // HACK - // TODO: Properly analyse the input here to determine if it can properly fit what we need - // This is a problem due to chunked transfer - // First 2 512x720 blocks go into a cpu-side buffer but suddenly when its time to render the final 256x720 - // it falls onto some storage buffer in surface cache that has bad dimensions - // Proper solution is to always merge when a cpu resource is created (it should absorb the render targets in range) - // We then should not have any 'dst-is-rendertarget' surfaces in use - // Option 2: Make surfaces here part of surface cache and do not pad them for optimization - // Surface cache is good at merging for resolve operations. This keeps integrity even when drawing to the rendertgargets - // This option needs a lot more work - continue; - } - - if (!It->is_clipped || allow_clipped) - { - return *It; - } - - const auto _w = It->dst_area.width; - const auto _h = It->dst_area.height; - - if (_w < width) - { - if ((_w * scale_x) <= 1.f) - continue; - } - - if (_h < height) - { - if ((_h * scale_y) <= 1.f) - continue; - } - - // Some surface exists, but its size is questionable - // Opt to re-upload (needs WCB/WDB to work properly) - break; - } - - return {}; - } - - // Resolves the blit source when it is not already a render target: reuses an overlapping cached texture if one matches, otherwise uploads the source image from CPU. - // Out parameters: cached_src, vram_texture, the src side of typeless_info and adjusts src_area. - template - static void get_or_create_blit_src( - texture_cache* cache, - commandbuffer_type& cmd, - const rsx::blit_src_info& src, - const rsx::blit_dst_info& dst, - u32 src_address, - u32 src_payload_length, - u8 src_bpp, - u16 src_h, - bool src_is_argb8, - bool dst_is_render_target, - bool dst_is_depth_surface, - bool is_copy_op, - bool is_format_convert, - areai& src_area, - /*out*/ section_storage_type*& cached_src, - /*out*/ image_resource_type& vram_texture, - /*out*/ typeless_xfer& typeless_info, - reader_lock& lock, - Args&&... extras) - { - // NOTE: Src address already takes into account the flipped nature of the overlap! - const u32 lookup_mask = rsx::texture_upload_context::blit_engine_src | rsx::texture_upload_context::shader_read; - auto overlapping_surfaces = cache->find_texture_from_range(address_range32::start_length(src_address, src_payload_length), src.pitch, lookup_mask); - auto old_src_area = src_area; - - for (const auto& surface : overlapping_surfaces) - { - if (!surface->is_locked()) - { - // TODO: Rejecting unlocked blit_engine dst causes stutter in SCV - // Surfaces marked as dirty have already been removed, leaving only flushed blit_dst data - continue; - } - - // Force format matching; only accept 16-bit data for 16-bit transfers, 32-bit for 32-bit transfers - if (!blit_engine_helpers::is_blit_source_format_compatible(surface->get_gcm_format(), src_is_argb8, is_copy_op, dst_is_render_target)) - { - continue; - } - - const auto this_address = surface->get_section_base(); - if (this_address > src_address) - { - continue; - } - - if (const u32 address_offset = src_address - this_address) - { - const u32 offset_y = address_offset / src.pitch; - const u32 offset_x = address_offset % src.pitch; - const u32 offset_x_in_block = offset_x / src_bpp; - - src_area.x1 += offset_x_in_block; - src_area.x2 += offset_x_in_block; - src_area.y1 += offset_y; - src_area.y2 += offset_y; - } - - if (src_area.x2 <= surface->get_width() && - src_area.y2 <= surface->get_height()) - { - cached_src = surface; - break; - } - - src_area = old_src_area; - } - - if (!cached_src) - { - const u16 full_width = src.pitch / src_bpp; - u32 image_base = src.rsx_address; - u16 image_width = full_width; - u16 image_height = src.height; - - // Check if memory is valid - const bool use_full_range = blit_engine_helpers::validate_memory_range( - image_base, - (src_address + src_payload_length), - image_base + (image_height * src.pitch)); - - if (use_full_range && dst.scale_x > 0.f && dst.scale_y > 0.f) [[likely]] - { - // Loading full image from the corner address - // Translate src_area into the declared block - src_area.x1 += src.offset_x; - src_area.x2 += src.offset_x; - src_area.y1 += src.offset_y; - src_area.y2 += src.offset_y; - } - else - { - image_base = src_address; - image_height = src_h; - } - - std::vector subresource_layout; - rsx::subresource_layout subres = {}; - subres.width_in_block = subres.width_in_texel = image_width; - subres.height_in_block = subres.height_in_texel = image_height; - subres.pitch_in_block = full_width; - subres.depth = 1; - subres.data = { vm::_ptr(image_base), static_cast::size_type>(src.pitch * image_height) }; - subresource_layout.push_back(std::move(subres)); - - const u32 gcm_format = helpers::get_sized_blit_format(src_is_argb8, dst_is_depth_surface, is_format_convert); - const auto rsx_range = address_range32::start_length(image_base, src.pitch * image_height); - - lock.upgrade(); - - cache->invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::read, {}, std::forward(extras)...); - - cached_src = cache->upload_image_from_cpu(cmd, rsx_range, image_width, image_height, 1, 1, src.pitch, gcm_format, texture_upload_context::blit_engine_src, - subresource_layout, rsx::texture_dimension_extended::texture_dimension_2d, dst.swizzled); - - typeless_info.src_gcm_format = gcm_format; - } - else - { - typeless_info.src_gcm_format = cached_src->get_gcm_format(); - } - - cached_src->add_ref(); - vram_texture = cached_src->get_raw_texture(); - typeless_info.src_context = cached_src->get_context(); - } - - // Creates the blit destination when it is neither an existing render target nor an existing DMA section. - // Out params: cached_dest, or promotes dst to a render target (dst_subres/dst_is_render_target/dest_texture and the dst side of typeless_info) and adjusts dst_dimensions/dst_area. - template - static void create_blit_dst( - texture_cache* cache, - commandbuffer_type& cmd, - surface_store_type& m_rtts, - const rsx::blit_dst_info& dst, - u32 dst_address, - u32 dst_payload_length, - u32 dst_base_address, - u16 dst_w, - u8 dst_bpp, - const address_range32& dst_range, - const GCM_tile_reference& dst_tile, - const position2i& dst_offset, - u32 preferred_dst_format, - bool src_is_render_target, - bool dst_is_argb8, - bool use_null_region, - /*out*/ size2i& dst_dimensions, - /*out*/ areai& dst_area, - /*out*/ section_storage_type*& cached_dest, - /*out*/ typename surface_store_type::surface_overlap_info& dst_subres, - /*out*/ bool& dst_is_render_target, - /*out*/ image_resource_type& dest_texture, - /*out*/ typeless_xfer& typeless_info, - reader_lock& lock, - Args&&... extras) - { - ensure(!dest_texture); - - // Need to calculate the minimum required size that will fit the data, anchored on the rsx_address - // If the application starts off with an 'inseted' section, the guessed dimensions may not fit! - const u32 write_end = dst_address + dst_payload_length; - u32 block_end = dst_base_address + (dst.pitch * dst_dimensions.height); - - // Confirm if the pages actually exist in vm - if (!blit_engine_helpers::validate_memory_range(dst_base_address, write_end, block_end)) - { - block_end = write_end; - } - - const u32 usable_section_length = std::max(write_end, block_end) - dst_base_address; - dst_dimensions.height = align2(usable_section_length, dst.pitch) / dst.pitch; - - const u32 full_section_length = ((dst_dimensions.height - 1) * dst.pitch) + (dst_dimensions.width * dst_bpp); - const auto rsx_range = address_range32::start_length(dst_base_address, full_section_length); - - lock.upgrade(); - - // NOTE: Write flag set to remove all other overlapping regions (e.g shader_read or blit_src) - // NOTE: This step can potentially invalidate the newly created src image as well. - cache->invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::cause_is_write | invalidation_cause::cause_uses_strict_data_bounds, {}, std::forward(extras)...); - - if (use_null_region) [[likely]] - { - bool force_dma_load = false; - if ((dst_w * dst_bpp) != dst.pitch) - { - // Keep Cell from touching the range we need - const auto prot_range = dst_range.to_page_range(); - utils::memory_protect(vm::base(prot_range.start), prot_range.length(), utils::protection::no); - - force_dma_load = true; - } - - const image_section_attributes_t attrs = - { - .pitch = dst.pitch, - .width = static_cast(dst_dimensions.width), - .height = static_cast(dst_dimensions.height), - .bpp = dst_bpp - }; - cached_dest = cache->create_nul_section(cmd, rsx_range, attrs, dst_tile, force_dma_load); - } - else - { - // render target data is already in correct swizzle layout - [[maybe_unused]] auto channel_order = src_is_render_target ? rsx::component_order::native : - dst_is_argb8 ? rsx::component_order::default_ : - rsx::component_order::swapped_native; - - // Translate dst_area into the 'full' dst block based on dst.rsx_address as (0, 0) - dst_area.x1 += dst_offset.x; - dst_area.x2 += dst_offset.x; - dst_area.y1 += dst_offset.y; - dst_area.y2 += dst_offset.y; - - // We have to create the surface in the surface cache - rsx::image_section_attributes_t section_attr - { - .address = rsx_range.start, - .gcm_format = preferred_dst_format, - .pitch = dst.pitch, - .width = static_cast(dst_dimensions.width), - .height = static_cast(dst_dimensions.height), - .depth = 1, - .mipmaps = 1, - .slice_h = static_cast(dst_dimensions.height), - .bpp = dst_bpp, - .swizzled = false, - .edge_clamped = false - }; - - auto dst_surface = m_rtts.create_surface_from_rsx_section( - cmd, - section_attr, - std::forward(extras)...); - - ensure(dst_surface, "Failed to create target surface"); - //dst_surface->set_name(fmt::format("Blit target @0x%x", section_attr.address)); - - if (!dst_area.x1 && !dst_area.y1 && dst_area.x2 == dst_dimensions.width && dst_area.y2 == dst_dimensions.height) - { - // Nothing to do, not even a background erase is needed here - dst_surface->state_flags &= ~rsx::surface_state_flags::erase_bkgnd; - } - else - { - // HACK: workaround for data race with Cell - // Pre-lock the memory range we'll be touching, then load with super_ptr - const auto prot_range = dst_range.to_page_range(); - utils::memory_protect(vm::base(prot_range.start), prot_range.length(), utils::protection::no); - - dst_surface->state_flags |= rsx::surface_state_flags::force_data_load | rsx::surface_state_flags::erase_bkgnd; - // set_component_order(*cached_dest, preferred_dst_format, channel_order); - } - - // Lock this for readback. That also creates a matching section - cache->lock_memory_region_impl( - cmd, dst_surface, dst_surface->get_memory_range(), false, - dst_surface->get_surface_width(), - dst_surface->get_surface_height(), - dst_surface->get_rsx_pitch(), - dst_surface); - - // Fake RTT cache hit - dst_subres.surface = dst_surface; - dst_is_render_target = true; - - dest_texture = dst_surface->get_surface(rsx::surface_access::transfer_write); - typeless_info.dst_context = texture_upload_context::framebuffer_storage; - typeless_info.dst_gcm_format = preferred_dst_format; - } - } - }; - // FIXME: This function is way too large and needs an urgent refactor. template blit_op_result upload_scaled_image(const rsx::blit_src_info& src_info, const rsx::blit_dst_info& dst_info, bool interpolate, commandbuffer_type& cmd, surface_store_type& m_rtts, blitter_type& blitter, Args&&... extras) @@ -2959,14 +2959,14 @@ namespace rsx // TODO: Handle cases where src or dst can be a depth texture while the other is a color texture - requires a render pass to emulate // NOTE: Grab the src first as requirements for reading are more strict than requirements for writing - auto src_subres = blit_engine_utils::rtt_lookup(m_rtts, cmd, src_address, src_w, src_h, src.pitch, src_bpp, surface_access::transfer_read, false, scale_x, scale_y); + auto src_subres = blit_engine_internals::rtt_lookup(m_rtts, cmd, src_address, src_w, src_h, src.pitch, src_bpp, surface_access::transfer_read, false, scale_x, scale_y); src_is_render_target = src_subres.surface != nullptr; if (get_location(dst_address) == CELL_GCM_LOCATION_LOCAL) { // TODO: HACK // After writing, it is required to lock the memory range from access! - dst_subres = blit_engine_utils::rtt_lookup(m_rtts, cmd, dst_address, dst_w, dst_h, dst.pitch, dst_bpp, surface_access::transfer_write, false, scale_x, scale_y); + dst_subres = blit_engine_internals::rtt_lookup(m_rtts, cmd, dst_address, dst_w, dst_h, dst.pitch, dst_bpp, surface_access::transfer_write, false, scale_x, scale_y); dst_is_render_target = dst_subres.surface != nullptr; } else @@ -2983,13 +2983,13 @@ namespace rsx // FBO re-validation. It is common for GPU and CPU data to desync as we do not have a way to share memory pages directly between the two (in most setups) // To avoid losing data, we need to do some gymnastics - if (src_is_render_target && !blit_engine_utils::validate_fbo_integrity(this, src_subres.surface->get_memory_range(), src_subres.is_depth)) + if (src_is_render_target && !blit_engine_internals::validate_fbo_integrity(this, src_subres.surface->get_memory_range(), src_subres.is_depth)) { src_is_render_target = false; src_subres.surface = nullptr; } - if (dst_is_render_target && !blit_engine_utils::validate_fbo_integrity(this, dst_subres.surface->get_memory_range(), dst_subres.is_depth)) + if (dst_is_render_target && !blit_engine_internals::validate_fbo_integrity(this, dst_subres.surface->get_memory_range(), dst_subres.is_depth)) { // This is a lot more serious that the src case. We have to signal surface cache to reload the memory and discard what we have GPU-side. // Do the transfer CPU side and we should eventually "read" the data on RCB/RDB barrier. @@ -3142,7 +3142,7 @@ namespace rsx // TODO: This can be greatly improved with DMA optimizations. Most transfer operations here are actually non-graphical (no transforms applied) if (!src_is_render_target) { - blit_engine_utils::get_or_create_blit_src( + blit_engine_internals::get_or_create_blit_src( this, cmd, src, @@ -3178,7 +3178,7 @@ namespace rsx if (!cached_dest && !dst_is_render_target) { - blit_engine_utils::create_blit_dst( + blit_engine_internals::create_blit_dst( this, cmd, m_rtts,