Merge branch 'RPCS3:master' into master

This commit is contained in:
Kravickas 2026-03-28 19:25:39 +01:00 committed by GitHub
commit b3b2225131
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 202 additions and 26 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,113 @@ 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<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;
}
// Perform a test scaling and check if anything is different after scaling
// There are many cases where this will avoid creating new surfaces
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(
active_config,
surface->template get_surface_width<>(),
surface->template get_surface_height<>());
if (new_w == surface->width() && new_h == surface->height())
{
// Not affected by resolution scale. Just update the details and move on.
surface->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
auto new_surface = Traits::get(sink);
ensure(copy.target == new_surface);
data.emplace(surface->get_memory_range(), std::move(sink));
// Force barrier to reduce VRAM pressure
new_surface->memory_barrier(cmd, rsx::surface_access::memory_read);
}
};
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,16 @@ 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;
const auto src_surface = ensure(dynamic_cast<const render_target_descriptor*>(slice.source));
const auto dst_surface = ensure(dynamic_cast<const render_target_descriptor*>(slice.target));
auto [src_width, src_height] = rsx::apply_resolution_scale<true>(src_res_scale, slice.width, slice.height, src_surface->get_surface_width(), src_surface->get_surface_height());
auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(dst_res_scale, slice.width, slice.height, dst_surface->get_surface_width(), dst_surface->get_surface_height());
slice.transfer_scale_x *= f32(dst_width) / src_width;
slice.transfer_scale_y *= f32(dst_height) / src_height;
@ -565,8 +571,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, src_surface->get_surface_width(), src_surface->get_surface_height());
std::tie(slice.dst_x, slice.dst_y) = rsx::apply_resolution_scale<false>(dst_res_scale, slice.dst_x, slice.dst_y, dst_surface->get_surface_width(), dst_surface->get_surface_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

@ -152,16 +152,16 @@ namespace rsx
home_menu_settings_video::home_menu_settings_video(s16 x, s16 y, u16 width, u16 height, bool use_separators, home_menu_page* parent)
: home_menu_settings_page(x, y, width, height, use_separators, parent, get_localized_string(localized_string_id::HOME_MENU_SETTINGS_VIDEO))
{
add_unsigned_slider(&g_cfg.video.resolution_scale_percent, localized_string_id::HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_PERCENT, "%", 25);
add_unsigned_slider(&g_cfg.video.min_scalable_dimension, localized_string_id::HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_THRESHOLD, "px", 1);
add_dropdown(&g_cfg.video.vsync, localized_string_id::HOME_MENU_SETTINGS_VIDEO_VSYNC);
add_dropdown(&g_cfg.video.frame_limit, localized_string_id::HOME_MENU_SETTINGS_VIDEO_FRAME_LIMIT);
add_unsigned_slider(&g_cfg.video.anisotropic_level_override, localized_string_id::HOME_MENU_SETTINGS_VIDEO_ANISOTROPIC_OVERRIDE, "x", 2, {{0, "Auto"}}, {14});
add_dropdown(&g_cfg.video.output_scaling, localized_string_id::HOME_MENU_SETTINGS_VIDEO_OUTPUT_SCALING);
if (g_cfg.video.renderer == video_renderer::vulkan && g_cfg.video.output_scaling == output_scaling_mode::fsr)
{
add_unsigned_slider(&g_cfg.video.rcas_sharpening_intensity, localized_string_id::HOME_MENU_SETTINGS_VIDEO_RCAS_SHARPENING, " %", 1);
}
add_unsigned_slider(&g_cfg.video.rcas_sharpening_intensity, localized_string_id::HOME_MENU_SETTINGS_VIDEO_RCAS_SHARPENING, " %", 1);
add_checkbox(&g_cfg.video.stretch_to_display_area, localized_string_id::HOME_MENU_SETTINGS_VIDEO_STRETCH_TO_DISPLAY);

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "VKGSRender.h"
#include "vkutils/buffer_object.h"
#include "vkutils/memory.h"
#include "Emu/RSX/Overlays/overlay_manager.h"
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
#include "Emu/Cell/Modules/cellVideoOut.h"
@ -963,4 +964,32 @@ 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)
{
// First, try to reclaim any memory since the res scale upgrade is so memory intensive
if (const auto severity = vk::vmm_determine_memory_load_severity();
severity > rsx::problem_severity::low && m_rtts.handle_memory_pressure(*m_current_command_buffer, severity))
{
flush_command_queue(true);
}
// Then apply the change
m_rtts.sync_scaling_config(*m_current_command_buffer, active_res_scaling_config);
this->resolution_scaling_config = active_res_scaling_config;
// Finally reclaim any unused resources
if (const auto severity = vk::vmm_determine_memory_load_severity();
severity > rsx::problem_severity::low && m_rtts.handle_memory_pressure(*m_current_command_buffer, severity))
{
flush_command_queue(true);
}
}
}

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>

View File

@ -222,6 +222,8 @@ enum class localized_string_id
HOME_MENU_SETTINGS_VIDEO_ANISOTROPIC_OVERRIDE,
HOME_MENU_SETTINGS_VIDEO_OUTPUT_SCALING,
HOME_MENU_SETTINGS_VIDEO_RCAS_SHARPENING,
HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_PERCENT,
HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_THRESHOLD,
HOME_MENU_SETTINGS_VIDEO_STRETCH_TO_DISPLAY,
HOME_MENU_SETTINGS_VIDEO_STEREO_MODE,
HOME_MENU_SETTINGS_INPUT,

View File

@ -161,10 +161,10 @@ struct cfg_root : cfg::node
cfg::_bool precise_zpass_count{ this, "Accurate ZCULL stats", true };
cfg::_int<1, 8> consecutive_frames_to_draw{ this, "Consecutive Frames To Draw", 1, true};
cfg::_int<1, 8> consecutive_frames_to_skip{ this, "Consecutive Frames To Skip", 1, true};
cfg::_int<25, 800> resolution_scale_percent{ this, "Resolution Scale", 100 };
cfg::uint<25, 800> resolution_scale_percent{ this, "Resolution Scale", 100, true };
cfg::uint<0, 16> anisotropic_level_override{ this, "Anisotropic Filter Override", 0, true };
cfg::_float<-32, 32> texture_lod_bias{ this, "Texture LOD Bias Addend", 0, true };
cfg::_int<1, 1024> min_scalable_dimension{ this, "Minimum Scalable Dimension", 16 };
cfg::uint<1, 1024> min_scalable_dimension{ this, "Minimum Scalable Dimension", 16, true };
cfg::_int<0, 16> shader_compiler_threads_count{ this, "Shader Compiler Threads", 0 };
cfg::_int<0, 30000000> driver_recovery_timeout{ this, "Driver Recovery Timeout", 1000000, true };
cfg::uint<0, 16667> driver_wakeup_delay{ this, "Driver Wake-Up Delay", 0, true };

View File

@ -242,6 +242,8 @@ private:
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_ANISOTROPIC_OVERRIDE: return tr("Anisotropic Filter Override", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_OUTPUT_SCALING: return tr("Output Scaling", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_RCAS_SHARPENING: return tr("FidelityFX CAS Sharpening Intensity", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_PERCENT: return tr("Resolution Scale", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_RESOLUTION_SCALE_THRESHOLD: return tr("Resolution Scale Threshold", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_STRETCH_TO_DISPLAY: return tr("Stretch To Display Area", "Video");
case localized_string_id::HOME_MENU_SETTINGS_VIDEO_STEREO_MODE: return tr("Stereo Mode", "Video");
case localized_string_id::HOME_MENU_SETTINGS_INPUT: return tr("Input");