mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-14 01:27:00 +00:00
rsx: Improve format validation for blit engine
- Check all possible cases where format mismatch is possible. - Warn if a slow path is going to be taken. Should help with future optimizations.
This commit is contained in:
parent
c415578e79
commit
4a0e1c79ed
@ -15,7 +15,6 @@ namespace rsx
|
||||
{
|
||||
if (fcmp(src_scaling_hint, dst_scaling_hint) && !fcmp(src_scaling_hint, 1.f))
|
||||
{
|
||||
verify(HERE), src_is_depth == dst_is_depth;
|
||||
src_is_typeless = dst_is_typeless = false;
|
||||
src_scaling_hint = dst_scaling_hint = 1.f;
|
||||
}
|
||||
|
@ -68,8 +68,6 @@ namespace rsx
|
||||
{
|
||||
bool src_is_typeless = false;
|
||||
bool dst_is_typeless = false;
|
||||
bool src_is_depth = false;
|
||||
bool dst_is_depth = false;
|
||||
bool flip_vertical = false;
|
||||
bool flip_horizontal = false;
|
||||
|
||||
|
@ -12,6 +12,8 @@ extern u64 get_system_time();
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace helpers = rsx::texture_cache_helpers;
|
||||
|
||||
template <typename derived_type, typename _traits>
|
||||
class texture_cache
|
||||
{
|
||||
@ -1487,11 +1489,11 @@ namespace rsx
|
||||
if (UNLIKELY(m_rtts.address_is_bound(attr.address)))
|
||||
{
|
||||
if (auto texptr = m_rtts.get_surface_at(attr.address);
|
||||
texture_cache_helpers::check_framebuffer_resource(texptr, attr, extended_dimension))
|
||||
helpers::check_framebuffer_resource(texptr, attr, extended_dimension))
|
||||
{
|
||||
const bool force_convert = !render_target_format_is_compatible(texptr, attr.gcm_format);
|
||||
|
||||
auto result = texture_cache_helpers::process_framebuffer_resource_fast<sampled_image_descriptor>(
|
||||
auto result = helpers::process_framebuffer_resource_fast<sampled_image_descriptor>(
|
||||
cmd, texptr, attr, scale, extended_dimension, encoded_remap, remap, true, force_convert);
|
||||
|
||||
if (!options.skip_texture_barriers && result.is_cyclic_reference)
|
||||
@ -1515,7 +1517,7 @@ namespace rsx
|
||||
{
|
||||
const bool force_convert = !render_target_format_is_compatible(last.surface, attr.gcm_format);
|
||||
|
||||
return texture_cache_helpers::process_framebuffer_resource_fast<sampled_image_descriptor>(
|
||||
return helpers::process_framebuffer_resource_fast<sampled_image_descriptor>(
|
||||
cmd, last.surface, attr, scale, extended_dimension, encoded_remap, remap, false, force_convert);
|
||||
}
|
||||
|
||||
@ -1611,23 +1613,23 @@ namespace rsx
|
||||
normalized_width >= attr.width && last->get_height() >= attr.height)
|
||||
{
|
||||
u32 gcm_format = attr.gcm_format;
|
||||
const bool gcm_format_is_depth = texture_cache_helpers::is_gcm_depth_format(attr.gcm_format);
|
||||
const bool gcm_format_is_depth = helpers::is_gcm_depth_format(attr.gcm_format);
|
||||
|
||||
if (!gcm_format_is_depth && last->is_depth_texture())
|
||||
{
|
||||
// While the copy routines can perform a typeless cast, prefer to not cross the aspect barrier if possible
|
||||
gcm_format = texture_cache_helpers::get_compatible_depth_format(attr.gcm_format);
|
||||
gcm_format = helpers::get_compatible_depth_format(attr.gcm_format);
|
||||
}
|
||||
|
||||
auto new_attr = attr;
|
||||
new_attr.gcm_format = gcm_format;
|
||||
|
||||
return { last->get_raw_texture(), deferred_request_command::copy_image_static, new_attr, {},
|
||||
last->get_context(), texture_cache_helpers::get_format_class(gcm_format), scale, extended_dimension, remap };
|
||||
last->get_context(), helpers::get_format_class(gcm_format), scale, extended_dimension, remap };
|
||||
}
|
||||
}
|
||||
|
||||
auto result = texture_cache_helpers::merge_cache_resources<sampled_image_descriptor>(
|
||||
auto result = helpers::merge_cache_resources<sampled_image_descriptor>(
|
||||
overlapping_fbos, overlapping_locals, attr, scale, extended_dimension, encoded_remap, remap, _pool);
|
||||
|
||||
if (options.skip_texture_merge)
|
||||
@ -1692,7 +1694,7 @@ namespace rsx
|
||||
const bool is_swizzled = !(tex.format() & CELL_GCM_TEXTURE_LN);
|
||||
auto extended_dimension = tex.get_extended_texture_dimension();
|
||||
|
||||
options.is_compressed_format = texture_cache_helpers::is_compressed_gcm_format(attributes.gcm_format);
|
||||
options.is_compressed_format = helpers::is_compressed_gcm_format(attributes.gcm_format);
|
||||
|
||||
u32 tex_size = 0, required_surface_height;
|
||||
u8 subsurface_count;
|
||||
@ -1801,7 +1803,7 @@ namespace rsx
|
||||
std::vector<copy_region_descriptor> sections;
|
||||
const bool use_upscaling = (result.upload_context == rsx::texture_upload_context::framebuffer_storage && g_cfg.video.resolution_scale_percent != 100);
|
||||
|
||||
if (UNLIKELY(!texture_cache_helpers::append_mipmap_level(sections, result, attributes, 0, use_upscaling, attributes)))
|
||||
if (UNLIKELY(!helpers::append_mipmap_level(sections, result, attributes, 0, use_upscaling, attributes)))
|
||||
{
|
||||
// Abort if mip0 is not compatible
|
||||
return result;
|
||||
@ -1831,7 +1833,7 @@ namespace rsx
|
||||
options, range, extended_dimension, m_rtts, std::forward<Args>(extras)...);
|
||||
|
||||
if (!ret.validate() ||
|
||||
!texture_cache_helpers::append_mipmap_level(sections, ret, attr2, subsurface, use_upscaling, attributes))
|
||||
!helpers::append_mipmap_level(sections, ret, attr2, subsurface, use_upscaling, attributes))
|
||||
{
|
||||
// Abort
|
||||
break;
|
||||
@ -1866,7 +1868,7 @@ namespace rsx
|
||||
|
||||
// Do direct upload from CPU as the last resort
|
||||
const auto subresources_layout = get_subresources_layout(tex);
|
||||
const auto format_class = texture_cache_helpers::get_format_class(attributes.gcm_format);
|
||||
const auto format_class = helpers::get_format_class(attributes.gcm_format);
|
||||
|
||||
if (!tex_size)
|
||||
{
|
||||
@ -2083,28 +2085,23 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
// Sanity and format compatibility checks
|
||||
if (dst_is_render_target)
|
||||
{
|
||||
if (src_subres.is_depth != dst_subres.is_depth)
|
||||
{
|
||||
// Create a cache-local resource to resolve later
|
||||
// TODO: Support depth->RGBA typeless transfer for vulkan
|
||||
dst_is_render_target = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (src_is_render_target)
|
||||
{
|
||||
const auto surf = src_subres.surface;
|
||||
const auto bpp = surf->get_bpp();
|
||||
if (bpp != src_bpp)
|
||||
const bool typeless = (bpp != src_bpp || is_format_convert);
|
||||
|
||||
if (LIKELY(!typeless))
|
||||
{
|
||||
//Enable type scaling in src
|
||||
// Use format as-is
|
||||
typeless_info.src_gcm_format = helpers::get_sized_blit_format(src_is_argb8, src_subres.is_depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable type scaling in src
|
||||
typeless_info.src_is_typeless = true;
|
||||
typeless_info.src_is_depth = src_subres.is_depth;
|
||||
typeless_info.src_scaling_hint = (f32)bpp / src_bpp;
|
||||
typeless_info.src_gcm_format = src_is_argb8 ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_R5G6B5;
|
||||
typeless_info.src_gcm_format = helpers::get_sized_blit_format(src_is_argb8, false);
|
||||
}
|
||||
|
||||
if (surf->get_surface_width(rsx::surface_metrics::pixels) != surf->width() ||
|
||||
@ -2118,18 +2115,24 @@ namespace rsx
|
||||
|
||||
if (dst_is_render_target)
|
||||
{
|
||||
auto bpp = dst_subres.surface->get_bpp();
|
||||
if (bpp != dst_bpp)
|
||||
const auto bpp = dst_subres.surface->get_bpp();
|
||||
const bool typeless = (bpp != dst_bpp || is_format_convert);
|
||||
|
||||
if (LIKELY(!typeless))
|
||||
{
|
||||
//Enable type scaling in dst
|
||||
typeless_info.dst_gcm_format = helpers::get_sized_blit_format(dst_is_argb8, dst_subres.is_depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Enable type scaling in dst
|
||||
typeless_info.dst_is_typeless = true;
|
||||
typeless_info.dst_is_depth = dst_subres.is_depth;
|
||||
typeless_info.dst_scaling_hint = (f32)bpp / dst_bpp;
|
||||
typeless_info.dst_gcm_format = dst_is_argb8 ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_R5G6B5;
|
||||
typeless_info.dst_gcm_format = helpers::get_sized_blit_format(dst_is_argb8, false);
|
||||
}
|
||||
}
|
||||
|
||||
section_storage_type* cached_dest = nullptr;
|
||||
bool dst_is_depth_surface = false;
|
||||
u16 max_dst_width = dst.width;
|
||||
u16 max_dst_height = dst.height;
|
||||
areai src_area = { 0, 0, src_w, src_h };
|
||||
@ -2202,6 +2205,20 @@ namespace rsx
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (surface->get_gcm_format())
|
||||
{
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
if (!dst_is_argb8) continue;
|
||||
break;
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
case CELL_GCM_TEXTURE_DEPTH16:
|
||||
if (dst_is_argb8) continue;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (const u32 address_offset = dst_address - this_address)
|
||||
{
|
||||
const u16 offset_y = address_offset / dst.pitch;
|
||||
@ -2229,6 +2246,38 @@ namespace rsx
|
||||
|
||||
dst_area = old_dst_area;
|
||||
}
|
||||
|
||||
const bool format_check = (src_is_render_target || is_format_convert);
|
||||
if (!use_null_region && cached_dest && format_check)
|
||||
{
|
||||
bool src_is_depth;
|
||||
if (is_format_convert)
|
||||
{
|
||||
src_is_depth = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
verify(HERE), src_is_render_target;
|
||||
src_is_depth = (typeless_info.src_is_typeless)? false : src_subres.is_depth;
|
||||
}
|
||||
|
||||
if (cached_dest->is_depth_texture() != src_is_depth)
|
||||
{
|
||||
// Opt to cancel the destination. Can also use typeless convert
|
||||
LOG_WARNING(RSX, "Format mismatch on blit destination block. Performance warning.");
|
||||
|
||||
// The invalidate call before creating a new target will remove this section
|
||||
cached_dest = nullptr;
|
||||
dest_texture = 0;
|
||||
dst_area = old_dst_area;
|
||||
}
|
||||
}
|
||||
|
||||
if (LIKELY(cached_dest))
|
||||
{
|
||||
typeless_info.dst_gcm_format = cached_dest->get_gcm_format();
|
||||
dst_is_depth_surface = cached_dest->is_depth_texture();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2237,59 +2286,26 @@ namespace rsx
|
||||
|
||||
dest_texture = dst_subres.surface->get_surface(rsx::surface_access::transfer);
|
||||
typeless_info.dst_context = texture_upload_context::framebuffer_storage;
|
||||
dst_is_depth_surface = typeless_info.dst_is_typeless ? false : dst_subres.is_depth;
|
||||
|
||||
max_dst_width = (u16)(dst_subres.surface->get_surface_width(rsx::surface_metrics::samples) * typeless_info.dst_scaling_hint);
|
||||
max_dst_height = dst_subres.surface->get_surface_height(rsx::surface_metrics::samples);
|
||||
}
|
||||
|
||||
// Check if available target is acceptable
|
||||
// TODO: Check for other types of format mismatch
|
||||
if (cached_dest && !use_null_region)
|
||||
{
|
||||
bool format_mismatch = false;
|
||||
if (cached_dest->is_depth_texture() != src_subres.is_depth)
|
||||
{
|
||||
// Dest surface has the wrong 'aspect'
|
||||
format_mismatch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if it matches the transfer declaration
|
||||
switch (cached_dest->get_gcm_format())
|
||||
{
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
format_mismatch = !dst_is_argb8;
|
||||
break;
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
case CELL_GCM_TEXTURE_DEPTH16:
|
||||
format_mismatch = dst_is_argb8;
|
||||
break;
|
||||
default:
|
||||
format_mismatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (format_mismatch)
|
||||
{
|
||||
// The invalidate call before creating a new target will remove this section
|
||||
cached_dest = nullptr;
|
||||
dest_texture = 0;
|
||||
dst_area = old_dst_area;
|
||||
}
|
||||
}
|
||||
|
||||
// Create source texture if does not exist
|
||||
// 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)
|
||||
{
|
||||
// NOTE: Src address already takes into account the flipped nature of the overlap!
|
||||
const u32 gcm_format = src_is_argb8 ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_R5G6B5;
|
||||
const u32 lookup_mask = rsx::texture_upload_context::blit_engine_src | rsx::texture_upload_context::blit_engine_dst | rsx::texture_upload_context::shader_read;
|
||||
auto overlapping_surfaces = find_texture_from_range<false>(address_range::start_length(src_address, src_payload_length), src.pitch, lookup_mask);
|
||||
|
||||
auto old_src_area = src_area;
|
||||
section_storage_type *cached_src = nullptr;
|
||||
|
||||
// If no source exists, a dest texture must exist since format matching should always pass
|
||||
verify(HERE), dest_texture;
|
||||
|
||||
for (const auto &surface : overlapping_surfaces)
|
||||
{
|
||||
if (!surface->is_locked())
|
||||
@ -2352,27 +2368,14 @@ namespace rsx
|
||||
if (src_area.x2 <= surface->get_width() &&
|
||||
src_area.y2 <= surface->get_height())
|
||||
{
|
||||
vram_texture = surface->get_raw_texture();
|
||||
typeless_info.src_context = surface->get_context();
|
||||
typeless_info.src_is_depth = surface->is_depth_texture();
|
||||
|
||||
const bool dst_is_depth = cached_dest ? cached_dest->is_depth_texture() : dst_subres.is_depth;
|
||||
if (dst_is_depth != typeless_info.src_is_depth && !typeless_info.dst_is_typeless)
|
||||
{
|
||||
// Transfer crosses the dreaded DEPTH_STENCIL<->COLOR barrier
|
||||
// Transfer in a typeless context using this surface as the reference
|
||||
typeless_info.dst_is_depth = dst_is_depth;
|
||||
typeless_info.dst_is_typeless = true;
|
||||
typeless_info.dst_gcm_format = surface->get_gcm_format();
|
||||
}
|
||||
|
||||
cached_src = surface;
|
||||
break;
|
||||
}
|
||||
|
||||
src_area = old_src_area;
|
||||
}
|
||||
|
||||
if (!vram_texture)
|
||||
if (!cached_src)
|
||||
{
|
||||
const u16 full_width = src.pitch / src_bpp;
|
||||
u32 image_base = src.rsx_address;
|
||||
@ -2394,11 +2397,6 @@ namespace rsx
|
||||
image_height = src_h;
|
||||
}
|
||||
|
||||
lock.upgrade();
|
||||
|
||||
const auto rsx_range = address_range::start_length(image_base, src.pitch * image_height);
|
||||
invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::read, std::forward<Args>(extras)...);
|
||||
|
||||
std::vector<rsx_subresource_layout> subresource_layout;
|
||||
rsx_subresource_layout subres = {};
|
||||
subres.width_in_block = subres.width_in_texel = image_width;
|
||||
@ -2408,11 +2406,30 @@ namespace rsx
|
||||
subres.data = { vm::_ptr<const std::byte>(image_base), static_cast<gsl::span<const std::byte>::index_type>(src.pitch * image_height) };
|
||||
subresource_layout.push_back(subres);
|
||||
|
||||
vram_texture = 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)->get_raw_texture();
|
||||
const u32 gcm_format = helpers::get_sized_blit_format(src_is_argb8, dst_is_depth_surface);
|
||||
const auto rsx_range = address_range::start_length(image_base, src.pitch * image_height);
|
||||
|
||||
typeless_info.src_context = texture_upload_context::blit_engine_src;
|
||||
lock.upgrade();
|
||||
|
||||
invalidate_range_impl_base(cmd, rsx_range, invalidation_cause::read, std::forward<Args>(extras)...);
|
||||
|
||||
cached_src = 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 if (cached_src->is_depth_texture() != dst_is_depth_surface)
|
||||
{
|
||||
typeless_info.src_is_typeless = true;
|
||||
typeless_info.src_gcm_format = helpers::get_sized_blit_format(src_is_argb8, dst_is_depth_surface);
|
||||
}
|
||||
else
|
||||
{
|
||||
typeless_info.src_gcm_format = cached_src->get_gcm_format();
|
||||
}
|
||||
|
||||
vram_texture = cached_src->get_raw_texture();
|
||||
typeless_info.src_context = cached_src->get_context();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2421,15 +2438,7 @@ namespace rsx
|
||||
typeless_info.src_context = texture_upload_context::framebuffer_storage;
|
||||
}
|
||||
|
||||
// Type of blit decided by the source, destination use should adapt on the fly
|
||||
const bool is_depth_blit = src_subres.is_depth;
|
||||
u32 gcm_format;
|
||||
|
||||
if (is_depth_blit)
|
||||
gcm_format = (dst_is_argb8) ? CELL_GCM_TEXTURE_DEPTH24_D8 : CELL_GCM_TEXTURE_DEPTH16;
|
||||
else
|
||||
gcm_format = (dst_is_argb8) ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_R5G6B5;
|
||||
|
||||
const auto preferred_dst_format = helpers::get_sized_blit_format(dst_is_argb8, dst_is_depth_surface);
|
||||
if (cached_dest && !use_null_region)
|
||||
{
|
||||
// Prep surface
|
||||
@ -2437,7 +2446,7 @@ namespace rsx
|
||||
dst_is_argb8 ? rsx::texture_create_flags::default_component_order :
|
||||
rsx::texture_create_flags::swapped_native_component_order;
|
||||
|
||||
enforce_surface_creation_type(*cached_dest, gcm_format, channel_order);
|
||||
enforce_surface_creation_type(*cached_dest, preferred_dst_format, channel_order);
|
||||
}
|
||||
|
||||
// Validate clipping region
|
||||
@ -2520,7 +2529,7 @@ namespace rsx
|
||||
if (!dst_area.x1 && !dst_area.y1 && dst_area.x2 == dst_dimensions.width && dst_area.y2 == dst_dimensions.height)
|
||||
{
|
||||
cached_dest = create_new_texture(cmd, rsx_range, dst_dimensions.width, dst_dimensions.height, 1, 1, dst.pitch,
|
||||
gcm_format, rsx::texture_upload_context::blit_engine_dst, rsx::texture_dimension_extended::texture_dimension_2d,
|
||||
preferred_dst_format, rsx::texture_upload_context::blit_engine_dst, rsx::texture_dimension_extended::texture_dimension_2d,
|
||||
channel_order);
|
||||
}
|
||||
else
|
||||
@ -2541,10 +2550,12 @@ namespace rsx
|
||||
subresource_layout.push_back(subres);
|
||||
|
||||
cached_dest = upload_image_from_cpu(cmd, rsx_range, dst_dimensions.width, dst_dimensions.height, 1, 1, dst.pitch,
|
||||
gcm_format, rsx::texture_upload_context::blit_engine_dst, subresource_layout,
|
||||
preferred_dst_format, rsx::texture_upload_context::blit_engine_dst, subresource_layout,
|
||||
rsx::texture_dimension_extended::texture_dimension_2d, false);
|
||||
|
||||
enforce_surface_creation_type(*cached_dest, gcm_format, channel_order);
|
||||
enforce_surface_creation_type(*cached_dest, preferred_dst_format, channel_order);
|
||||
|
||||
typeless_info.dst_gcm_format = preferred_dst_format;
|
||||
}
|
||||
|
||||
dest_texture = cached_dest->get_raw_texture();
|
||||
@ -2626,7 +2637,7 @@ namespace rsx
|
||||
if (!use_null_region)
|
||||
{
|
||||
typeless_info.analyse();
|
||||
blitter.scale_image(cmd, vram_texture, dest_texture, src_area, dst_area, interpolate, is_depth_blit, typeless_info);
|
||||
blitter.scale_image(cmd, vram_texture, dest_texture, src_area, dst_area, interpolate, typeless_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2634,7 +2645,6 @@ namespace rsx
|
||||
}
|
||||
|
||||
blit_op_result result = true;
|
||||
result.is_depth = is_depth_blit;
|
||||
|
||||
if (cached_dest)
|
||||
{
|
||||
|
@ -61,7 +61,6 @@ namespace rsx
|
||||
struct blit_op_result
|
||||
{
|
||||
bool succeeded = false;
|
||||
bool is_depth = false;
|
||||
u32 real_dst_address = 0;
|
||||
u32 real_dst_size = 0;
|
||||
|
||||
@ -123,6 +122,18 @@ namespace rsx
|
||||
return gcm_format;
|
||||
}
|
||||
|
||||
static inline u32 get_sized_blit_format(bool _32_bit, bool depth_format)
|
||||
{
|
||||
if (LIKELY(_32_bit))
|
||||
{
|
||||
return (!depth_format) ? CELL_GCM_TEXTURE_A8R8G8B8 : CELL_GCM_TEXTURE_DEPTH24_D8;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (!depth_format) ? CELL_GCM_TEXTURE_R5G6B5 : CELL_GCM_TEXTURE_DEPTH16;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_compressed_gcm_format(u32 format)
|
||||
{
|
||||
switch (format)
|
||||
|
@ -374,8 +374,8 @@ namespace gl
|
||||
return attrib_t(index);
|
||||
}
|
||||
|
||||
void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
|
||||
bool is_depth_copy, const rsx::typeless_xfer& xfer_info)
|
||||
void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect,
|
||||
bool linear_interpolation, const rsx::typeless_xfer& xfer_info)
|
||||
{
|
||||
std::unique_ptr<texture> typeless_src;
|
||||
std::unique_ptr<texture> typeless_dst;
|
||||
@ -384,41 +384,49 @@ namespace gl
|
||||
|
||||
if (xfer_info.src_is_typeless)
|
||||
{
|
||||
const auto internal_width = (u16)(src->width() * xfer_info.src_scaling_hint);
|
||||
const auto internal_fmt = xfer_info.src_native_format_override ?
|
||||
GLenum(xfer_info.src_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.src_gcm_format);
|
||||
|
||||
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(typeless_src.get(), src);
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != src->get_internal_format())
|
||||
{
|
||||
const auto internal_width = (u16)(src->width() * xfer_info.src_scaling_hint);
|
||||
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(typeless_src.get(), src);
|
||||
|
||||
real_src = typeless_src.get();
|
||||
src_rect.x1 = (u16)(src_rect.x1 * xfer_info.src_scaling_hint);
|
||||
src_rect.x2 = (u16)(src_rect.x2 * xfer_info.src_scaling_hint);
|
||||
real_src = typeless_src.get();
|
||||
src_rect.x1 = (u16)(src_rect.x1 * xfer_info.src_scaling_hint);
|
||||
src_rect.x2 = (u16)(src_rect.x2 * xfer_info.src_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
const auto internal_width = (u16)(dst->width() * xfer_info.dst_scaling_hint);
|
||||
const auto internal_fmt = xfer_info.dst_native_format_override ?
|
||||
GLenum(xfer_info.dst_native_format_override) :
|
||||
get_sized_internal_format(xfer_info.dst_gcm_format);
|
||||
|
||||
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(typeless_dst.get(), dst);
|
||||
if (static_cast<gl::texture::internal_format>(internal_fmt) != dst->get_internal_format())
|
||||
{
|
||||
const auto internal_width = (u16)(dst->width() * xfer_info.dst_scaling_hint);
|
||||
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
||||
copy_typeless(typeless_dst.get(), dst);
|
||||
|
||||
real_dst = typeless_dst.get();
|
||||
dst_rect.x1 = (u16)(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_rect.x2 = (u16)(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
||||
real_dst = typeless_dst.get();
|
||||
dst_rect.x1 = (u16)(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_rect.x2 = (u16)(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
||||
verify(HERE), real_src->aspect() == real_dst->aspect();
|
||||
|
||||
const bool is_depth_copy = (real_src->aspect() != image_aspect::color);
|
||||
const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
||||
GLenum attachment;
|
||||
gl::buffers target;
|
||||
|
||||
if (is_depth_copy)
|
||||
{
|
||||
verify(HERE), real_src->aspect() == real_dst->aspect();
|
||||
if (real_dst->aspect() & gl::image_aspect::stencil)
|
||||
{
|
||||
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
|
@ -2926,7 +2926,7 @@ public:
|
||||
}
|
||||
|
||||
void scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
|
||||
bool is_depth_copy, const rsx::typeless_xfer& xfer_info);
|
||||
const rsx::typeless_xfer& xfer_info);
|
||||
|
||||
void fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color);
|
||||
void fast_clear_image(gl::command_context& cmd, const texture* dst, float depth, u8 stencil);
|
||||
|
@ -485,7 +485,6 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, bool force_init
|
||||
typeless_info.src_is_typeless = true;
|
||||
typeless_info.src_context = rsx::texture_upload_context::framebuffer_storage;
|
||||
typeless_info.src_native_format_override = (u32)get_internal_format();
|
||||
typeless_info.src_is_depth = !!(src_texture->aspect() & gl::image_aspect::depth);
|
||||
typeless_info.src_scaling_hint = f32(src_bpp) / dst_bpp;
|
||||
}
|
||||
}
|
||||
@ -508,7 +507,7 @@ void gl::render_target::memory_barrier(gl::command_context& cmd, bool force_init
|
||||
gl::g_hw_blitter->scale_image(cmd, section.source, this,
|
||||
section.src_rect(),
|
||||
section.dst_rect(),
|
||||
!dst_is_depth, dst_is_depth, typeless_info);
|
||||
!dst_is_depth, typeless_info);
|
||||
|
||||
newest_tag = src_texture->last_use_tag;
|
||||
}
|
||||
|
@ -258,9 +258,8 @@ namespace gl
|
||||
scaled_texture = std::make_unique<gl::texture>(GL_TEXTURE_2D, real_width, real_height, 1, 1, (GLenum)ifmt);
|
||||
}
|
||||
|
||||
const bool is_depth = is_depth_texture();
|
||||
const bool linear_interp = is_depth? false : true;
|
||||
g_hw_blitter->scale_image(cmd, vram_texture, scaled_texture.get(), src_area, dst_area, linear_interp, is_depth, {});
|
||||
const bool linear_interp = is_depth_texture() ? false : true;
|
||||
g_hw_blitter->scale_image(cmd, vram_texture, scaled_texture.get(), src_area, dst_area, linear_interp, {});
|
||||
target_texture = scaled_texture.get();
|
||||
}
|
||||
}
|
||||
@ -643,7 +642,7 @@ namespace gl
|
||||
}
|
||||
|
||||
_blitter->scale_image(cmd, src_image, _dst,
|
||||
src_rect, dst_rect, false, false, {});
|
||||
src_rect, dst_rect, false, {});
|
||||
|
||||
if (_dst != dst_image)
|
||||
{
|
||||
|
@ -3534,6 +3534,6 @@ public:
|
||||
|
||||
struct blitter
|
||||
{
|
||||
void scale_image(vk::command_buffer& cmd, vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, bool /*is_depth*/, const rsx::typeless_xfer& xfer_info);
|
||||
void scale_image(vk::command_buffer& cmd, vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, const rsx::typeless_xfer& xfer_info);
|
||||
};
|
||||
}
|
||||
|
@ -457,7 +457,6 @@ namespace vk
|
||||
typeless_info.src_is_typeless = true;
|
||||
typeless_info.src_context = rsx::texture_upload_context::framebuffer_storage;
|
||||
typeless_info.src_native_format_override = (u32)info.format;
|
||||
typeless_info.src_is_depth = is_depth;
|
||||
typeless_info.src_scaling_hint = f32(src_bpp) / dst_bpp;
|
||||
}
|
||||
}
|
||||
@ -502,7 +501,7 @@ namespace vk
|
||||
this->get_surface(rsx::surface_access::transfer),
|
||||
src_area,
|
||||
dst_area,
|
||||
/*linear?*/false, /*depth?(unused)*/false, typeless_info);
|
||||
/*linear?*/false, typeless_info);
|
||||
|
||||
optimize_copy = optimize_copy && !memory_load;
|
||||
newest_tag = src_texture->last_use_tag;
|
||||
|
@ -847,7 +847,7 @@ namespace vk
|
||||
return{ final_mapping[1], final_mapping[2], final_mapping[3], final_mapping[0] };
|
||||
}
|
||||
|
||||
void blitter::scale_image(vk::command_buffer& cmd, vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, bool /*is_depth*/, const rsx::typeless_xfer& xfer_info)
|
||||
void blitter::scale_image(vk::command_buffer& cmd, vk::image* src, vk::image* dst, areai src_area, areai dst_area, bool interpolate, const rsx::typeless_xfer& xfer_info)
|
||||
{
|
||||
const auto src_aspect = vk::get_aspect_flags(src->info.format);
|
||||
const auto dst_aspect = vk::get_aspect_flags(dst->info.format);
|
||||
@ -857,40 +857,48 @@ namespace vk
|
||||
|
||||
if (xfer_info.src_is_typeless)
|
||||
{
|
||||
const auto internal_width = src->width() * xfer_info.src_scaling_hint;
|
||||
const auto format = xfer_info.src_native_format_override ?
|
||||
VkFormat(xfer_info.src_native_format_override) :
|
||||
vk::get_compatible_sampler_format(vk::get_current_renderer()->get_formats_support(), xfer_info.src_gcm_format);
|
||||
const auto aspect = vk::get_aspect_flags(format);
|
||||
|
||||
// Transfer bits from src to typeless src
|
||||
real_src = vk::get_typeless_helper(format, (u32)internal_width, src->height());
|
||||
vk::change_image_layout(cmd, real_src, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 });
|
||||
if (format != src->format())
|
||||
{
|
||||
const auto internal_width = src->width() * xfer_info.src_scaling_hint;
|
||||
const auto aspect = vk::get_aspect_flags(format);
|
||||
|
||||
vk::copy_image_typeless(cmd, src, real_src, { 0, 0, (s32)src->width(), (s32)src->height() }, { 0, 0, (s32)internal_width, (s32)src->height() }, 1,
|
||||
vk::get_aspect_flags(src->info.format), aspect);
|
||||
// Transfer bits from src to typeless src
|
||||
real_src = vk::get_typeless_helper(format, (u32)internal_width, src->height());
|
||||
vk::change_image_layout(cmd, real_src, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 });
|
||||
|
||||
src_area.x1 = (u16)(src_area.x1 * xfer_info.src_scaling_hint);
|
||||
src_area.x2 = (u16)(src_area.x2 * xfer_info.src_scaling_hint);
|
||||
vk::copy_image_typeless(cmd, src, real_src, { 0, 0, (s32)src->width(), (s32)src->height() }, { 0, 0, (s32)internal_width, (s32)src->height() }, 1,
|
||||
vk::get_aspect_flags(src->info.format), aspect);
|
||||
|
||||
src_area.x1 = (u16)(src_area.x1 * xfer_info.src_scaling_hint);
|
||||
src_area.x2 = (u16)(src_area.x2 * xfer_info.src_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
if (xfer_info.dst_is_typeless)
|
||||
{
|
||||
const auto internal_width = dst->width() * xfer_info.dst_scaling_hint;
|
||||
const auto format = xfer_info.dst_native_format_override ?
|
||||
VkFormat(xfer_info.dst_native_format_override) :
|
||||
vk::get_compatible_sampler_format(vk::get_current_renderer()->get_formats_support(), xfer_info.dst_gcm_format);
|
||||
const auto aspect = vk::get_aspect_flags(format);
|
||||
|
||||
// Transfer bits from dst to typeless dst
|
||||
real_dst = vk::get_typeless_helper(format, (u32)internal_width, dst->height());
|
||||
vk::change_image_layout(cmd, real_dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 });
|
||||
if (format != dst->format())
|
||||
{
|
||||
const auto internal_width = dst->width() * xfer_info.dst_scaling_hint;
|
||||
const auto aspect = vk::get_aspect_flags(format);
|
||||
|
||||
vk::copy_image_typeless(cmd, dst, real_dst, { 0, 0, (s32)dst->width(), (s32)dst->height() }, { 0, 0, (s32)internal_width, (s32)dst->height() }, 1,
|
||||
vk::get_aspect_flags(dst->info.format), aspect);
|
||||
// Transfer bits from dst to typeless dst
|
||||
real_dst = vk::get_typeless_helper(format, (u32)internal_width, dst->height());
|
||||
vk::change_image_layout(cmd, real_dst, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { aspect, 0, 1, 0, 1 });
|
||||
|
||||
dst_area.x1 = (u16)(dst_area.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_area.x2 = (u16)(dst_area.x2 * xfer_info.dst_scaling_hint);
|
||||
vk::copy_image_typeless(cmd, dst, real_dst, { 0, 0, (s32)dst->width(), (s32)dst->height() }, { 0, 0, (s32)internal_width, (s32)dst->height() }, 1,
|
||||
vk::get_aspect_flags(dst->info.format), aspect);
|
||||
|
||||
dst_area.x1 = (u16)(dst_area.x1 * xfer_info.dst_scaling_hint);
|
||||
dst_area.x2 = (u16)(dst_area.x2 * xfer_info.dst_scaling_hint);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks
|
||||
|
Loading…
x
Reference in New Issue
Block a user