rsx: Implement resolution scale change handling in surface cache

This commit is contained in:
kd-11 2026-03-28 03:05:46 +03:00 committed by kd-11
parent 976cd1ce66
commit e2dff6bbf8
7 changed files with 155 additions and 20 deletions

View File

@ -132,7 +132,7 @@ namespace rsx
free_rsx_memory(Traits::get(sink));
}
Traits::clone_surface(cmd, sink, region.source, new_address, region);
Traits::clone_surface(cmd, sink, region.source, new_address, region, region.source->resolution_scaling_config);
allocate_rsx_memory(Traits::get(sink));
if (invalidated) [[unlikely]]
@ -449,7 +449,7 @@ namespace rsx
}
}
if (Traits::surface_matches_properties(surface, format, width, height, antialias))
if (Traits::surface_matches_properties(surface, format, width, height, antialias, scaling_config))
{
if (!pitch_compatible)
{
@ -496,7 +496,7 @@ namespace rsx
for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++)
{
auto &surface = *It;
if (Traits::surface_matches_properties(surface, format, width, height, antialias, true))
if (Traits::surface_matches_properties(surface, format, width, height, antialias, scaling_config, true))
{
new_surface_storage = std::move(surface);
Traits::notify_surface_reused(new_surface_storage);
@ -1469,5 +1469,94 @@ namespace rsx
}
}
}
void sync_scaling_config(command_list_type cmd, const rsx::surface_scaling_config_t& active_config)
{
auto process_list_function = [&](surface_ranged_map& data, const utils::address_range32& range)
{
std::vector<Traits::surface_type> surfaces_to_clone;
for (auto It = data.begin_range(range); It != data.end();)
{
auto surface = Traits::get(It->second);
if (surface->get_resolution_scaling_config() == active_config)
{
++It;
continue;
}
surfaces_to_clone.push_back(surface);
// Invalidate the previous surface
invalidate(It->second);
It = data.erase(It);
}
for (auto& surface : surfaces_to_clone)
{
// Enqueue the memory transfer
surface_storage_type sink{};
deferred_clipped_region<surface_type> copy{};
copy.width = surface->template get_surface_width<>();
copy.height = surface->template get_surface_height<>();
copy.transfer_scale_x = 1.f;
copy.transfer_scale_y = 1.f;
copy.target = nullptr;
copy.source = surface;
Traits::clone_surface(cmd, sink, surface, surface->base_addr, copy, active_config);
allocate_rsx_memory(Traits::get(sink));
// Replace with the new one
ensure(copy.target == Traits::get(sink));
data.emplace(surface->get_memory_range(), std::move(sink));
}
};
const auto rtt_bind_backup = m_bound_render_targets;
const auto dsv_bind_backup = m_bound_depth_stencil;
// Unbind everything. We'll restore it later
for (auto& rtt_bind : m_bound_render_targets)
{
rtt_bind = {};
}
m_bound_depth_stencil = {};
process_list_function(m_render_targets_storage, m_render_targets_memory_range);
process_list_function(m_depth_stencil_storage, m_depth_stencil_memory_range);
// Restore bindings.
for (int i = 0; i < 4; ++i)
{
const auto address = rtt_bind_backup[i].first;
if (!address)
{
continue;
}
auto rtt = m_render_targets_storage.find(address);
ensure(rtt != m_render_targets_storage.end());
m_bound_render_targets[i] =
{
address,
Traits::get(rtt->second)
};
}
if (const auto ds_address = dsv_bind_backup.first)
{
auto ds = m_depth_stencil_storage.find(ds_address);
ensure(ds != m_depth_stencil_storage.end());
m_bound_depth_stencil =
{
ds_address,
Traits::get(ds->second)
};
}
}
};
}

View File

@ -554,10 +554,14 @@ namespace rsx
}
// Apply resolution scale if needed
if (resolution_scaling_config.scale_percent != 100)
if (resolution_scaling_config.scale_percent != 100 ||
region.source->resolution_scaling_config.scale_percent != 100)
{
auto [src_width, src_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, slice.width, slice.height, slice.source->width(), slice.source->height());
auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, slice.width, slice.height, slice.target->width(), slice.target->height());
const auto& src_res_scale = region.source->resolution_scaling_config;
const auto& dst_res_scale = resolution_scaling_config;
auto [src_width, src_height] = rsx::apply_resolution_scale<true>(src_res_scale, slice.width, slice.height, slice.source->width(), slice.source->height());
auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(dst_res_scale, slice.width, slice.height, slice.target->width(), slice.target->height());
slice.transfer_scale_x *= f32(dst_width) / src_width;
slice.transfer_scale_y *= f32(dst_height) / src_height;
@ -565,8 +569,8 @@ namespace rsx
slice.width = src_width;
slice.height = src_height;
std::tie(slice.src_x, slice.src_y) = rsx::apply_resolution_scale<false>(resolution_scaling_config, slice.src_x, slice.src_y, slice.source->width(), slice.source->height());
std::tie(slice.dst_x, slice.dst_y) = rsx::apply_resolution_scale<false>(resolution_scaling_config, slice.dst_x, slice.dst_y, slice.target->width(), slice.target->height());
std::tie(slice.src_x, slice.src_y) = rsx::apply_resolution_scale<false>(src_res_scale, slice.src_x, slice.src_y, slice.source->width(), slice.source->height());
std::tie(slice.dst_x, slice.dst_y) = rsx::apply_resolution_scale<false>(dst_res_scale, slice.dst_x, slice.dst_y, slice.target->width(), slice.target->height());
}
}

View File

@ -517,6 +517,19 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
m_frame->flip(m_context);
rsx::thread::flip(info);
// Data sync
const rsx::surface_scaling_config_t active_res_scaling_config =
{
.scale_percent = static_cast<u16>(g_cfg.video.resolution_scale_percent),
.min_scalable_dimension = static_cast<u16>(g_cfg.video.min_scalable_dimension),
};
if (active_res_scaling_config != this->resolution_scaling_config)
{
m_rtts.sync_scaling_config(cmd, active_res_scaling_config);
this->resolution_scaling_config = active_res_scaling_config;
}
// Cleanup
m_gl_texture_cache.on_frame_end();
m_vertex_cache->purge();

View File

@ -229,13 +229,14 @@ struct gl_render_target_traits
void clone_surface(
gl::command_context& cmd,
std::unique_ptr<gl::render_target>& sink, gl::render_target* ref,
u32 address, barrier_descriptor_t& prev)
u32 address, barrier_descriptor_t& prev,
const rsx::surface_scaling_config_t& scaling_config)
{
if (!sink)
{
auto internal_format = static_cast<GLenum>(ref->get_internal_format());
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(
ref->resolution_scaling_config,
scaling_config,
prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(),
ref->get_surface_height<rsx::surface_metrics::pixels>());
@ -248,7 +249,7 @@ struct gl_render_target_traits
sink->format_info = ref->format_info;
sink->sample_layout = ref->sample_layout;
sink->resolution_scaling_config = ref->resolution_scaling_config;
sink->resolution_scaling_config = scaling_config;
sink->set_name(fmt::format("SINK_%u@0x%x", sink->id(), address));
sink->set_spp(ref->get_spp());
@ -385,6 +386,7 @@ struct gl_render_target_traits
gl::texture::internal_format format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs = false)
{
if (check_refs && surface->has_refs())
@ -392,7 +394,8 @@ struct gl_render_target_traits
return surface->get_internal_format() == format &&
surface->get_spp() == get_format_sample_count(antialias) &&
surface->matches_dimensions(static_cast<u16>(width), static_cast<u16>(height));
surface->matches_dimensions(static_cast<u16>(width), static_cast<u16>(height)) &&
surface->resolution_scaling_config == scaling_config;
}
static
@ -401,10 +404,11 @@ struct gl_render_target_traits
rsx::surface_color_format format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs=false)
{
const auto internal_fmt = rsx::internals::surface_color_format_to_gl(format).internal_format;
return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, check_refs);
return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, scaling_config, check_refs);
}
static
@ -413,10 +417,11 @@ struct gl_render_target_traits
rsx::surface_depth_format2 format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs = false)
{
const auto internal_fmt = rsx::internals::surface_depth_format_to_gl(format).internal_format;
return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, check_refs);
return int_surface_matches_properties(surface, internal_fmt, width, height, antialias, scaling_config, check_refs);
}
static

View File

@ -963,4 +963,17 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
m_frame->flip(m_context);
rsx::thread::flip(info);
// Data sync
const rsx::surface_scaling_config_t active_res_scaling_config =
{
.scale_percent = static_cast<u16>(g_cfg.video.resolution_scale_percent),
.min_scalable_dimension = static_cast<u16>(g_cfg.video.min_scalable_dimension),
};
if (active_res_scaling_config != this->resolution_scaling_config)
{
m_rtts.sync_scaling_config(*m_current_command_buffer, active_res_scaling_config);
this->resolution_scaling_config = active_res_scaling_config;
}
}

View File

@ -337,12 +337,13 @@ namespace vk
static void clone_surface(
vk::command_buffer& cmd,
std::unique_ptr<vk::render_target>& sink, vk::render_target* ref,
u32 address, barrier_descriptor_t& prev)
u32 address, barrier_descriptor_t& prev,
const rsx::surface_scaling_config_t& scaling_config)
{
if (!sink)
{
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(
ref->resolution_scaling_config,
scaling_config,
prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(), ref->get_surface_height<rsx::surface_metrics::pixels>());
@ -363,7 +364,7 @@ namespace vk
sink->add_ref();
sink->sample_layout = ref->sample_layout;
sink->resolution_scaling_config = ref->resolution_scaling_config;
sink->resolution_scaling_config = scaling_config;
sink->set_spp(ref->get_spp());
sink->format_info = ref->format_info;
@ -521,6 +522,7 @@ namespace vk
VkFormat format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs)
{
if (check_refs && surface->has_refs())
@ -531,7 +533,8 @@ namespace vk
return (surface->info.format == format &&
surface->get_spp() == get_format_sample_count(antialias) &&
surface->matches_dimensions(static_cast<u16>(width), static_cast<u16>(height)));
surface->matches_dimensions(static_cast<u16>(width), static_cast<u16>(height))) &&
surface->resolution_scaling_config == scaling_config;
}
static bool surface_matches_properties(
@ -539,10 +542,11 @@ namespace vk
rsx::surface_color_format format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs = false)
{
VkFormat vk_format = vk::get_compatible_surface_format(format).first;
return int_surface_matches_properties(surface, vk_format, width, height, antialias, check_refs);
return int_surface_matches_properties(surface, vk_format, width, height, antialias, scaling_config, check_refs);
}
static bool surface_matches_properties(
@ -550,11 +554,12 @@ namespace vk
rsx::surface_depth_format2 format,
usz width, usz height,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& scaling_config,
bool check_refs = false)
{
auto device = vk::get_current_renderer();
VkFormat vk_format = vk::get_compatible_depth_surface_format(device->get_formats_support(), format);
return int_surface_matches_properties(surface, vk_format, width, height, antialias, check_refs);
return int_surface_matches_properties(surface, vk_format, width, height, antialias, scaling_config, check_refs);
}
static void spill_buffer(std::unique_ptr<vk::buffer>& /*bo*/)

View File

@ -220,6 +220,12 @@ namespace rsx
u16 min_scalable_dimension = 0;
f32 scale_factor() const { return scale_percent * 0.01f; }
bool operator == (const surface_scaling_config_t& that) const
{
return this->scale_percent == that.scale_percent &&
this->min_scalable_dimension == that.min_scalable_dimension;
}
};
template <typename T>