rsx: Make resolution scaling configuration non-global

- Paves the way for other changes.
- The main goal is to be able to switch the resolution scale and MSAA level at runtime.
This commit is contained in:
kd-11 2026-03-25 01:40:09 +03:00
parent 1b11f38364
commit 9f62ea9937
24 changed files with 207 additions and 130 deletions

View File

@ -398,6 +398,7 @@ namespace rsx
surface_antialiasing antialias,
usz width, usz height, usz pitch,
u8 bpp,
const rsx::surface_scaling_config_t& scaling_config,
Args&&... extra_params)
{
surface_storage_type old_surface_storage;
@ -531,7 +532,7 @@ namespace rsx
if (!new_surface)
{
ensure(store);
new_surface_storage = Traits::create_new_surface(address, format, width, height, pitch, antialias, std::forward<Args>(extra_params)...);
new_surface_storage = Traits::create_new_surface(address, format, width, height, pitch, antialias, scaling_config, std::forward<Args>(extra_params)...);
new_surface = Traits::get(new_surface_storage);
Traits::prepare_surface_for_drawing(command_list, new_surface);
allocate_rsx_memory(new_surface);
@ -842,11 +843,13 @@ namespace rsx
surface_color_format color_format,
surface_antialiasing antialias,
usz width, usz height, usz pitch,
const rsx::surface_scaling_config_t& scaling_config,
Args&&... extra_params)
{
return bind_surface_address<false>(
command_list, address, color_format, antialias,
width, height, pitch, get_format_block_size_in_bytes(color_format),
scaling_config,
std::forward<Args>(extra_params)...);
}
@ -857,12 +860,14 @@ namespace rsx
surface_depth_format2 depth_format,
surface_antialiasing antialias,
usz width, usz height, usz pitch,
const rsx::surface_scaling_config_t& scaling_config,
Args&&... extra_params)
{
return bind_surface_address<true>(
command_list, address, depth_format, antialias,
width, height, pitch,
get_format_block_size_in_bytes(depth_format),
scaling_config,
std::forward<Args>(extra_params)...);
}
@ -969,6 +974,7 @@ namespace rsx
surface_raster_type raster_type,
const std::array<u32, 4> &surface_addresses, u32 address_z,
const std::array<u32, 4> &surface_pitch, u32 zeta_pitch,
const rsx::surface_scaling_config_t& scaling_config,
Args&&... extra_params)
{
u32 clip_width = clip_horizontal_reg;
@ -998,7 +1004,7 @@ namespace rsx
m_bound_render_targets[surface_index] = std::make_pair(surface_addresses[surface_index],
bind_address_as_render_targets(command_list, surface_addresses[surface_index], color_format, antialias,
clip_width, clip_height, surface_pitch[surface_index], std::forward<Args>(extra_params)...));
clip_width, clip_height, surface_pitch[surface_index], scaling_config, std::forward<Args>(extra_params)...));
m_bound_render_target_ids.push_back(surface_index);
}
@ -1014,7 +1020,7 @@ namespace rsx
{
m_bound_depth_stencil = std::make_pair(address_z,
bind_address_as_depth_stencil(command_list, address_z, depth_format, antialias,
clip_width, clip_height, zeta_pitch, std::forward<Args>(extra_params)...));
clip_width, clip_height, zeta_pitch, scaling_config, std::forward<Args>(extra_params)...));
}
else
{

View File

@ -88,18 +88,18 @@ namespace rsx
auto dst_h = std::get<3>(region);
// Apply resolution scale if needed
if (g_cfg.video.resolution_scale_percent != 100)
{
auto src = static_cast<T>(source);
auto src = static_cast<T>(source);
std::tie(src_w, src_h) = rsx::apply_resolution_scale<true>(
src->resolution_scaling_config,
src_w, src_h,
src->template get_surface_width<rsx::surface_metrics::pixels>(),
src->template get_surface_height<rsx::surface_metrics::pixels>());
std::tie(src_w, src_h) = rsx::apply_resolution_scale<true>(src_w, src_h,
src->template get_surface_width<rsx::surface_metrics::pixels>(),
src->template get_surface_height<rsx::surface_metrics::pixels>());
std::tie(dst_w, dst_h) = rsx::apply_resolution_scale<true>(dst_w, dst_h,
target_surface->template get_surface_width<rsx::surface_metrics::pixels>(),
target_surface->template get_surface_height<rsx::surface_metrics::pixels>());
}
std::tie(dst_w, dst_h) = rsx::apply_resolution_scale<true>(
target_surface->resolution_scaling_config,
dst_w, dst_h,
target_surface->template get_surface_width<rsx::surface_metrics::pixels>(),
target_surface->template get_surface_height<rsx::surface_metrics::pixels>());
width = src_w;
height = src_h;
@ -146,6 +146,9 @@ namespace rsx
u8 samples_x = 1;
u8 samples_y = 1;
// Scaling configuration
surface_scaling_config_t resolution_scaling_config;
rsx::address_range32 memory_range;
std::unique_ptr<typename std::remove_pointer_t<image_storage_type>> resolve_surface;
@ -303,6 +306,11 @@ namespace rsx
format_info.gcm_depth_format = format;
}
void set_resolution_scaling_config(const surface_scaling_config_t& config)
{
resolution_scaling_config = config;
}
inline rsx::surface_color_format get_surface_color_format() const
{
return format_info.gcm_color_format;
@ -323,6 +331,11 @@ namespace rsx
);
}
inline const rsx::surface_scaling_config_t& get_resolution_scaling_config() const
{
return resolution_scaling_config;
}
inline bool dirty() const
{
return (state_flags != rsx::surface_state_flags::ready) || !old_contents.empty();
@ -541,10 +554,10 @@ namespace rsx
}
// Apply resolution scale if needed
if (g_cfg.video.resolution_scale_percent != 100)
if (resolution_scaling_config.scale_percent != 100)
{
auto [src_width, src_height] = rsx::apply_resolution_scale<true>(slice.width, slice.height, slice.source->width(), slice.source->height());
auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(slice.width, slice.height, slice.target->width(), slice.target->height());
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());
slice.transfer_scale_x *= f32(dst_width) / src_width;
slice.transfer_scale_y *= f32(dst_height) / src_height;
@ -552,8 +565,8 @@ namespace rsx
slice.width = src_width;
slice.height = src_height;
std::tie(slice.src_x, slice.src_y) = rsx::apply_resolution_scale<false>(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>(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>(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());
}
}

View File

@ -2413,9 +2413,13 @@ namespace rsx
// 2. The image has to have been generated on the GPU (fbo or blit target only)
rsx::simple_array<copy_region_descriptor> sections;
const bool use_upscaling = (result.upload_context == rsx::texture_upload_context::framebuffer_storage && g_cfg.video.resolution_scale_percent != 100);
const bool use_upscaling = (result.upload_context == rsx::texture_upload_context::framebuffer_storage);
auto to_surface_type = [](const copy_region_descriptor& rgn) -> typename surface_store_type::surface_type
{
return static_cast<typename surface_store_type::surface_type>(rgn.src);
};
if (!helpers::append_mipmap_level(sections, result, attributes, 0, use_upscaling, attributes)) [[unlikely]]
if (!helpers::append_mipmap_level(to_surface_type, sections, result, attributes, 0, use_upscaling, attributes)) [[unlikely]]
{
// Abort if mip0 is not compatible
return result;
@ -2445,7 +2449,7 @@ namespace rsx
options, range, extended_dimension, m_rtts, std::forward<Args>(extras)...);
if (!ret.validate() ||
!helpers::append_mipmap_level(sections, ret, attr2, subsurface, use_upscaling, attributes))
!helpers::append_mipmap_level(to_surface_type, sections, ret, attr2, subsurface, use_upscaling, attributes))
{
// Abort
break;
@ -2778,7 +2782,7 @@ namespace rsx
surf->template get_surface_height<rsx::surface_metrics::pixels>() != surf->height())
{
// Must go through a scaling operation due to resolution scaling being present
ensure(g_cfg.video.resolution_scale_percent != 100);
ensure(src_subres.surface->resolution_scaling_config.scale_percent != 100);
use_null_region = false;
}
}
@ -3389,8 +3393,8 @@ namespace rsx
{
const auto surface_width = src_subres.surface->template get_surface_width<rsx::surface_metrics::pixels>();
const auto surface_height = src_subres.surface->template get_surface_height<rsx::surface_metrics::pixels>();
std::tie(src_area.x1, src_area.y1) = rsx::apply_resolution_scale<false>(src_area.x1, src_area.y1, surface_width, surface_height);
std::tie(src_area.x2, src_area.y2) = rsx::apply_resolution_scale<true>(src_area.x2, src_area.y2, surface_width, surface_height);
std::tie(src_area.x1, src_area.y1) = rsx::apply_resolution_scale<false>(src_subres.surface->resolution_scaling_config, src_area.x1, src_area.y1, surface_width, surface_height);
std::tie(src_area.x2, src_area.y2) = rsx::apply_resolution_scale<true>(src_subres.surface->resolution_scaling_config, src_area.x2, src_area.y2, surface_width, surface_height);
// The resource is of surface type; possibly disabled AA emulation
src_subres.surface->transform_blit_coordinates(rsx::surface_access::transfer_read, src_area);
@ -3400,8 +3404,8 @@ namespace rsx
{
const auto surface_width = dst_subres.surface->template get_surface_width<rsx::surface_metrics::pixels>();
const auto surface_height = dst_subres.surface->template get_surface_height<rsx::surface_metrics::pixels>();
std::tie(dst_area.x1, dst_area.y1) = rsx::apply_resolution_scale<false>(dst_area.x1, dst_area.y1, surface_width, surface_height);
std::tie(dst_area.x2, dst_area.y2) = rsx::apply_resolution_scale<true>(dst_area.x2, dst_area.y2, surface_width, surface_height);
std::tie(dst_area.x1, dst_area.y1) = rsx::apply_resolution_scale<false>(dst_subres.surface->resolution_scaling_config, dst_area.x1, dst_area.y1, surface_width, surface_height);
std::tie(dst_area.x2, dst_area.y2) = rsx::apply_resolution_scale<true>(dst_subres.surface->resolution_scaling_config, dst_area.x2, dst_area.y2, surface_width, surface_height);
// The resource is of surface type; possibly disabled AA emulation
dst_subres.surface->transform_blit_coordinates(rsx::surface_access::transfer_write, dst_area);

View File

@ -357,11 +357,11 @@ namespace rsx
const auto surface_width = section.surface->template get_surface_width<rsx::surface_metrics::pixels>();
const auto surface_height = section.surface->template get_surface_height<rsx::surface_metrics::pixels>();
const auto [src_width, src_height] = rsx::apply_resolution_scale<true>(section.src_area.width, h, surface_width, surface_height);
const auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(section.dst_area.width, h, attr.width, attr.height);
const auto [src_width, src_height] = rsx::apply_resolution_scale<true>(section.surface->resolution_scaling_config, section.src_area.width, h, surface_width, surface_height);
const auto [dst_width, dst_height] = rsx::apply_resolution_scale<true>(section.surface->resolution_scaling_config, section.dst_area.width, h, attr.width, attr.height);
std::tie(src_x, src_y) = rsx::apply_resolution_scale<false>(src_x, src_y, surface_width, surface_height);
std::tie(dst_x, dst_y) = rsx::apply_resolution_scale<false>(dst_x, dst_y, attr.width, attr.height);
std::tie(src_x, src_y) = rsx::apply_resolution_scale<false>(section.surface->resolution_scaling_config, src_x, src_y, surface_width, surface_height);
std::tie(dst_x, dst_y) = rsx::apply_resolution_scale<false>(section.surface->resolution_scaling_config, dst_x, dst_y, attr.width, attr.height);
section.surface->memory_barrier(cmd, rsx::surface_access::transfer_read);
@ -430,8 +430,10 @@ namespace rsx
if (scaling)
{
// Since output is upscaled, also upscale on dst
const auto [_dst_x, _dst_y] = rsx::apply_resolution_scale<false>(static_cast<u16>(dst_offset.x), static_cast<u16>(dst_y - dst_slice_begin), attr.width, attr.height);
const auto [_dst_w, _dst_h] = rsx::apply_resolution_scale<true>(dst_w, height, attr.width, attr.height);
const auto& scaling_config = rsx::get_current_renderer()->resolution_scaling_config;
const auto [_dst_x, _dst_y] = rsx::apply_resolution_scale<false>(scaling_config, static_cast<u16>(dst_offset.x), static_cast<u16>(dst_y - dst_slice_begin), attr.width, attr.height);
const auto [_dst_w, _dst_h] = rsx::apply_resolution_scale<true>(scaling_config, dst_w, height, attr.width, attr.height);
out.push_back
({
@ -660,10 +662,10 @@ namespace rsx
bool is_depth = texptr->is_depth_surface();
auto attr2 = attr;
if (rsx::get_resolution_scale_percent() != 100)
if (texptr->resolution_scaling_config.scale_percent != 100)
{
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(attr.width, attr.height, surface_width, surface_height);
const auto [unused, scaled_slice_h] = rsx::apply_resolution_scale<false>(RSX_SURFACE_DIMENSION_IGNORED, attr.slice_h, surface_width, surface_height);
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(texptr->resolution_scaling_config, attr.width, attr.height, surface_width, surface_height);
const auto [unused, scaled_slice_h] = rsx::apply_resolution_scale<false>(texptr->resolution_scaling_config, RSX_SURFACE_DIMENSION_IGNORED, attr.slice_h, surface_width, surface_height);
attr2.width = scaled_w;
attr2.height = scaled_h;
attr2.slice_h = scaled_slice_h;
@ -841,7 +843,8 @@ namespace rsx
}
// If this method was called, there is no easy solution, likely means atlas gather is needed
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale(attr2.width, attr2.height);
const auto& scaling_config = rsx::get_current_renderer()->resolution_scaling_config;
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale(scaling_config, attr2.width, attr2.height);
const auto format_class = classify_format(attr2.gcm_format);
const auto upload_context = (fbos.empty()) ? texture_upload_context::shader_read : texture_upload_context::framebuffer_storage;
@ -892,14 +895,15 @@ namespace rsx
return result;
}
template<typename sampled_image_descriptor, typename copy_region_descriptor_type>
template<typename to_surface_type_converter, typename sampled_image_descriptor, typename copy_region_descriptor_type>
bool append_mipmap_level(
to_surface_type_converter&& as_surface_type, // Cast function to surface type
rsx::simple_array<copy_region_descriptor_type>& sections, // Destination list
const sampled_image_descriptor& level, // Descriptor for the image level being checked
const image_section_attributes_t& attr, // Attributes of image level
u8 mipmap_level, // Level index
bool apply_upscaling, // Whether to upscale the results or not
const image_section_attributes_t& level0_attr) // Attributes of the first mipmap level
const sampled_image_descriptor& level, // Descriptor for the image level being checked
const image_section_attributes_t& attr, // Attributes of image level
u8 mipmap_level, // Level index
bool apply_upscaling, // Whether to upscale the results or not
const image_section_attributes_t& level0_attr) // Attributes of the first mipmap level
{
if (level.image_handle)
{
@ -916,7 +920,8 @@ namespace rsx
// Calculate transfer dimensions from attr
if (level.upload_context == rsx::texture_upload_context::framebuffer_storage) [[likely]]
{
std::tie(mip.src_w, mip.src_h) = rsx::apply_resolution_scale<true>(attr.width, attr.height);
auto rtv = as_surface_type(mip);
std::tie(mip.src_w, mip.src_h) = rsx::apply_resolution_scale<true>(rtv->resolution_scaling_config, attr.width, attr.height);
}
else
{
@ -964,7 +969,9 @@ namespace rsx
if (apply_upscaling)
{
auto& mip = sections.back();
std::tie(mip.dst_w, mip.dst_h) = rsx::apply_resolution_scale<true>(mip.dst_w, mip.dst_h, level0_attr.width, level0_attr.height);
std::tie(mip.dst_w, mip.dst_h) = rsx::apply_resolution_scale<true>(
as_surface_type(mip)->resolution_scaling_config,
mip.dst_w, mip.dst_h, level0_attr.width, level0_attr.height);
}
return true;

View File

@ -49,7 +49,7 @@ namespace rsx
}
}
std::string framebuffer_statistics_t::to_string(bool squash) const
std::string framebuffer_statistics_t::to_string(const surface_scaling_config_t& scaling_config, bool squash) const
{
// Format is sorted by sample count
struct sorted_message_t
@ -70,7 +70,7 @@ namespace rsx
for (const auto& [aa_mode, stat] : data)
{
auto real_stat = stat;
std::tie(real_stat.width, real_stat.height) = apply_resolution_scale(stat.width, stat.height);
std::tie(real_stat.width, real_stat.height) = apply_resolution_scale(scaling_config, stat.width, stat.height);
real_stats.push_back(real_stat);
sorted_message_t msg;

View File

@ -12,6 +12,8 @@ namespace rsx
{
enum class surface_antialiasing : u8;
struct surface_scaling_config_t;
struct framebuffer_dimensions_t
{
u16 width;
@ -42,7 +44,7 @@ namespace rsx
void add(u16 width, u16 height, rsx::surface_antialiasing aa);
// Returns a formatted string representing the statistics collected over the frame.
std::string to_string(bool squash) const;
std::string to_string(const surface_scaling_config_t& scaling_config, bool squash) const;
};
struct frame_statistics_t

View File

@ -699,7 +699,9 @@ namespace rsx
const auto window_origin = REGS(m_ctx)->shader_window_origin();
const u32 window_height = REGS(m_ctx)->shader_window_height();
const auto pixel_center = REGS(m_ctx)->pixel_center();
const f32 resolution_scale = (window_height <= static_cast<u32>(g_cfg.video.min_scalable_dimension)) ? 1.f : rsx::get_resolution_scale();
const f32 resolution_scale = (window_height <= RSX(m_ctx)->resolution_scaling_config.min_scalable_dimension)
? 1.f
: RSX(m_ctx)->resolution_scaling_config.scale_factor();
payload.wpos_scale = (window_origin == rsx::window_origin::top) ? (1.f / resolution_scale) : (-1.f / resolution_scale);
payload.wpos_bias[0] = 0.f;

View File

@ -227,7 +227,7 @@ void GLGSRender::update_draw_state()
case rsx::primitive_type::lines:
case rsx::primitive_type::line_loop:
case rsx::primitive_type::line_strip:
gl_state.line_width(rsx::method_registers.line_width() * rsx::get_resolution_scale());
gl_state.line_width(rsx::method_registers.line_width() * resolution_scaling_config.scale_factor());
gl_state.enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
break;
default:

View File

@ -73,6 +73,7 @@ void GLGSRender::set_viewport()
{
// NOTE: scale offset matrix already contains the viewport transformation
const auto [clip_width, clip_height] = rsx::apply_resolution_scale<true>(
resolution_scaling_config,
rsx::method_registers.surface_clip_width(), rsx::method_registers.surface_clip_height());
glViewport(0, 0, clip_width, clip_height);
@ -936,7 +937,7 @@ void GLGSRender::load_program_env()
m_draw_processor.fill_scale_offset_data(buf, false);
m_draw_processor.fill_user_clip_data(buf + 64);
*(reinterpret_cast<u32*>(buf + 68)) = rsx::method_registers.transform_branch_bits();
*(reinterpret_cast<f32*>(buf + 72)) = rsx::method_registers.point_size() * rsx::get_resolution_scale();
*(reinterpret_cast<f32*>(buf + 72)) = rsx::method_registers.point_size() * resolution_scaling_config.scale_factor();
*(reinterpret_cast<f32*>(buf + 76)) = rsx::method_registers.clip_min();
*(reinterpret_cast<f32*>(buf + 80)) = rsx::method_registers.clip_max();

View File

@ -95,6 +95,7 @@ gl::texture* GLGSRender::get_present_source(gl::present_surface_info* info, cons
image = section.surface->get_surface(rsx::surface_access::transfer_read);
std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>(
resolution_scaling_config,
std::min(surface_width, info->width),
std::min(surface_height, info->height));
}
@ -225,7 +226,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
if (avconfig.stereo_enabled) [[unlikely]]
{
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
if (image_to_flip->height() < min_expected_height)
{
// Get image for second eye
@ -240,7 +241,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
else
{
// Account for possible insets
const auto [unused2, scaled_buffer_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height);
const auto [unused2, scaled_buffer_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, RSX_SURFACE_DIMENSION_IGNORED, buffer_height);
buffer_height = std::min<u32>(image_to_flip->height() - min_expected_height, scaled_buffer_height);
}
}
@ -477,7 +478,7 @@ void GLGSRender::flip(const rsx::display_flip_info_t& info)
"Texture uploads: %11u (%u from CPU - %02u%%, %u copies avoided)\n"
"Vertex cache hits: %9u/%u (%u%%)\n"
"Program cache lookup ellision: %u/%u (%u%%)",
info.stats.framebuffer_stats.to_string(!backend_config.supports_hw_msaa),
info.stats.framebuffer_stats.to_string(resolution_scaling_config, !backend_config.supports_hw_msaa),
get_load(), info.stats.draw_calls, info.stats.setup_time, info.stats.vertex_upload_time,
info.stats.textures_upload_time, info.stats.draw_exec_time, num_dirty_textures, texture_memory_size,
num_flushes, num_misses, cache_miss_ratio, num_unavoidable, num_mispredict, num_speculate,

View File

@ -141,7 +141,8 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool /*
m_framebuffer_layout.width, m_framebuffer_layout.height,
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_framebuffer_layout.actual_color_pitch, m_framebuffer_layout.actual_zeta_pitch,
resolution_scaling_config);
std::array<GLuint, 4> color_targets;
GLuint depth_stencil_target;
@ -448,7 +449,7 @@ void gl::render_target::load_memory(gl::command_context& cmd)
subres.data = { vm::get_super_ptr<const std::byte>(base_addr), static_cast<std::span<const std::byte>::size_type>(rsx_pitch * surface_height * samples_y) };
// TODO: MSAA support
if (g_cfg.video.resolution_scale_percent == 100 && spp == 1) [[likely]]
if (resolution_scaling_config.scale_percent == 100 && spp == 1) [[likely]]
{
gl::upload_texture(cmd, this, get_gcm_format(), is_swizzled, { subres });
}

View File

@ -98,7 +98,7 @@ namespace gl
bool matches_dimensions(u16 _width, u16 _height) const
{
//Use forward scaling to account for rounding and clamping errors
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(_width, _height);
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(resolution_scaling_config, _width, _height);
return (scaled_w == width()) && (scaled_h == height());
}
@ -138,11 +138,12 @@ struct gl_render_target_traits
u32 address,
rsx::surface_color_format surface_color_format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& resolution_scaling_config
)
{
auto format = rsx::internals::surface_color_format_to_gl(surface_color_format);
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
u8 samples;
rsx::surface_sample_layout sample_layout;
@ -162,6 +163,7 @@ struct gl_render_target_traits
result->set_name(fmt::format("RTV_%u@0x%x", result->id(), address));
result->set_aa_mode(antialias);
result->set_resolution_scaling_config(resolution_scaling_config);
result->set_native_pitch(static_cast<u32>(width) * get_format_block_size_in_bytes(surface_color_format) * result->samples_x);
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
result->set_format(surface_color_format);
@ -182,11 +184,12 @@ struct gl_render_target_traits
u32 address,
rsx::surface_depth_format2 surface_depth_format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& resolution_scaling_config
)
{
auto format = rsx::internals::surface_depth_format_to_gl(surface_depth_format);
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
u8 samples;
rsx::surface_sample_layout sample_layout;
@ -206,6 +209,7 @@ struct gl_render_target_traits
result->set_name(fmt::format("DSV_%u@0x%x", result->id(), address));
result->set_aa_mode(antialias);
result->set_resolution_scaling_config(resolution_scaling_config);
result->set_surface_dimensions(static_cast<u16>(width), static_cast<u16>(height), static_cast<u32>(pitch));
result->set_format(surface_depth_format);
result->set_native_pitch(static_cast<u32>(width) * get_format_block_size_in_bytes(surface_depth_format) * result->samples_x);
@ -230,8 +234,11 @@ struct gl_render_target_traits
if (!sink)
{
auto internal_format = static_cast<GLenum>(ref->get_internal_format());
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(), ref->get_surface_height<rsx::surface_metrics::pixels>());
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(
ref->resolution_scaling_config,
prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(),
ref->get_surface_height<rsx::surface_metrics::pixels>());
sink = std::make_unique<gl::render_target>(new_w, new_h, ref->samples(), internal_format, ref->format_class());
sink->add_ref();
@ -240,6 +247,9 @@ struct gl_render_target_traits
sink->state_flags = rsx::surface_state_flags::erase_bkgnd;
sink->format_info = ref->format_info;
sink->sample_layout = ref->sample_layout;
sink->resolution_scaling_config = ref->resolution_scaling_config;
sink->set_name(fmt::format("SINK_%u@0x%x", sink->id(), address));
sink->set_spp(ref->get_spp());
sink->set_native_pitch(static_cast<u32>(prev.width) * ref->get_bpp() * ref->samples_x);

View File

@ -287,6 +287,7 @@ namespace gl
u32 transfer_width = width;
u32 transfer_height = height;
u32 transfer_x = 0, transfer_y = 0;
u16 resolution_scale_percent = 100;
if (context == rsx::texture_upload_context::framebuffer_storage)
{
@ -295,9 +296,10 @@ namespace gl
target_texture = surface->get_surface(rsx::surface_access::transfer_read);
transfer_width *= surface->samples_x;
transfer_height *= surface->samples_y;
resolution_scale_percent = surface->resolution_scaling_config.scale_percent;
}
if ((rsx::get_resolution_scale_percent() != 100 && context == rsx::texture_upload_context::framebuffer_storage) ||
if ((resolution_scale_percent != 100 && context == rsx::texture_upload_context::framebuffer_storage) ||
(vram_texture->pitch() != rsx_pitch))
{
areai src_area = { 0, 0, 0, 0 };

View File

@ -996,6 +996,12 @@ namespace rsx
fifo_ctrl = std::make_unique<::rsx::FIFO::FIFO_control>(this);
fifo_ctrl->set_get(ctrl->get);
resolution_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),
};
last_guest_flip_timestamp = get_system_time() - 1000000;
vblank_count = 0;
@ -1940,8 +1946,8 @@ namespace rsx
m_graphics_state.set(rsx::rtt_config_valid);
}
std::tie(region.x1, region.y1) = rsx::apply_resolution_scale<false>(x1, y1, m_framebuffer_layout.width, m_framebuffer_layout.height);
std::tie(region.x2, region.y2) = rsx::apply_resolution_scale<true>(x2, y2, m_framebuffer_layout.width, m_framebuffer_layout.height);
std::tie(region.x1, region.y1) = rsx::apply_resolution_scale<false>(resolution_scaling_config, x1, y1, m_framebuffer_layout.width, m_framebuffer_layout.height);
std::tie(region.x2, region.y2) = rsx::apply_resolution_scale<true>(resolution_scaling_config, x2, y2, m_framebuffer_layout.width, m_framebuffer_layout.height);
return true;
}

View File

@ -215,6 +215,8 @@ namespace rsx
atomic_bitmask_t<flip_request> async_flip_requested{};
u8 async_flip_buffer{ 0 };
surface_scaling_config_t resolution_scaling_config{};
void capture_frame(const std::string& name);
const backend_configuration& get_backend_config() const { return backend_config; }

View File

@ -335,7 +335,7 @@ namespace rsx
auto scale_result = [](u32 value)
{
const auto scale = rsx::get_resolution_scale_percent();
const auto scale = get_current_renderer()->resolution_scaling_config.scale_percent;
const auto result = (value * 10000ull) / (scale * scale);
return std::max(1u, static_cast<u32>(result));
};

View File

@ -164,7 +164,7 @@ void VKGSRender::update_draw_state()
rsx::method_registers.current_draw_clause.primitive <= rsx::primitive_type::line_strip)
{
const float actual_line_width =
m_device->get_wide_lines_support() ? rsx::method_registers.line_width() * rsx::get_resolution_scale() : 1.f;
m_device->get_wide_lines_support() ? rsx::method_registers.line_width() * resolution_scaling_config.scale_factor() : 1.f;
vkCmdSetLineWidth(*m_current_command_buffer, actual_line_width);
}

View File

@ -1152,6 +1152,7 @@ void VKGSRender::check_present_status()
void VKGSRender::set_viewport()
{
const auto [clip_width, clip_height] = rsx::apply_resolution_scale<true>(
resolution_scaling_config,
rsx::method_registers.surface_clip_width(), rsx::method_registers.surface_clip_height());
const auto zclip_near = rsx::method_registers.clip_min();
@ -1952,7 +1953,7 @@ void VKGSRender::load_program_env()
m_draw_processor.fill_scale_offset_data(buf, false);
m_draw_processor.fill_user_clip_data(buf + 64);
*(reinterpret_cast<u32*>(buf + 68)) = ctx->transform_branch_bits();
*(reinterpret_cast<f32*>(buf + 72)) = ctx->point_size() * rsx::get_resolution_scale();
*(reinterpret_cast<f32*>(buf + 72)) = ctx->point_size() * resolution_scaling_config.scale_factor();
*(reinterpret_cast<f32*>(buf + 76)) = ctx->clip_min();
*(reinterpret_cast<f32*>(buf + 80)) = ctx->clip_max();
@ -2441,6 +2442,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
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,
resolution_scaling_config,
(*m_device), *m_current_command_buffer);
// Reset framebuffer information
@ -2620,7 +2622,7 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
m_cached_renderpass = vk::get_renderpass(*m_device, m_current_renderpass_key);
// Search old framebuffers for this same configuration
const auto [fbo_width, fbo_height] = rsx::apply_resolution_scale<true>(m_framebuffer_layout.width, m_framebuffer_layout.height);
const auto [fbo_width, fbo_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, m_framebuffer_layout.width, m_framebuffer_layout.height);
if (m_draw_fbo)
{

View File

@ -341,6 +341,7 @@ vk::viewable_image* VKGSRender::get_present_source(/* inout */ vk::present_surfa
image_to_flip = section.surface->get_surface(rsx::surface_access::transfer_read);
std::tie(info->width, info->height) = rsx::apply_resolution_scale<true>(
resolution_scaling_config,
std::min(surface_width, info->width),
std::min(surface_height, info->height));
}
@ -550,7 +551,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
if (avconfig.stereo_enabled) [[unlikely]]
{
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
const auto [unused, min_expected_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, RSX_SURFACE_DIMENSION_IGNORED, buffer_height + 30);
if (image_to_flip->height() < min_expected_height)
{
// Get image for second eye
@ -565,7 +566,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
else
{
// Account for possible insets
const auto [unused2, scaled_buffer_height] = rsx::apply_resolution_scale<true>(RSX_SURFACE_DIMENSION_IGNORED, buffer_height);
const auto [unused2, scaled_buffer_height] = rsx::apply_resolution_scale<true>(resolution_scaling_config, RSX_SURFACE_DIMENSION_IGNORED, buffer_height);
buffer_height = std::min<u32>(image_to_flip->height() - min_expected_height, scaled_buffer_height);
}
}
@ -935,7 +936,7 @@ void VKGSRender::flip(const rsx::display_flip_info_t& info)
"Texture uploads: %12u (%u from CPU - %02u%%, %u copies avoided)\n"
"Vertex cache hits: %10u/%u (%u%%)\n"
"Program cache lookup ellision: %u/%u (%u%%)",
info.stats.framebuffer_stats.to_string(!backend_config.supports_hw_msaa),
info.stats.framebuffer_stats.to_string(resolution_scaling_config, !backend_config.supports_hw_msaa),
get_load(), info.stats.draw_calls, info.stats.submit_count, info.stats.setup_time, info.stats.vertex_upload_time,
info.stats.textures_upload_time, info.stats.draw_exec_time, info.stats.flip_time,
num_dirty_textures, texture_memory_size, tmp_texture_memory_size,

View File

@ -735,7 +735,7 @@ namespace vk
#endif
}
if (g_cfg.video.resolution_scale_percent == 100 && spp == 1) [[likely]]
if (resolution_scaling_config.scale_percent == 100 && spp == 1) [[likely]]
{
push_layout(cmd, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
vk::upload_image(cmd, this, { subres }, get_gcm_format(), is_swizzled, 1, aspect(), upload_heap, heap_align, upload_flags);
@ -842,7 +842,7 @@ namespace vk
bool render_target::matches_dimensions(u16 _width, u16 _height) const
{
// Use forward scaling to account for rounding and clamping errors
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(_width, _height);
const auto [scaled_w, scaled_h] = rsx::apply_resolution_scale<true>(resolution_scaling_config, _width, _height);
return (scaled_w == width()) && (scaled_h == height());
}

View File

@ -200,6 +200,7 @@ namespace vk
rsx::surface_color_format format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& resolution_scaling_config,
vk::render_device& device, vk::command_buffer& cmd)
{
const auto fmt = vk::get_compatible_surface_format(format);
@ -231,7 +232,7 @@ namespace vk
}
std::unique_ptr<vk::render_target> rtt;
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
rtt = std::make_unique<vk::render_target>(device, device.get_memory_mapping().device_local,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@ -251,6 +252,7 @@ namespace vk
rtt->set_format(format);
rtt->set_aa_mode(antialias);
rtt->set_resolution_scaling_config(resolution_scaling_config);
rtt->sample_layout = sample_layout;
rtt->memory_usage_flags = rsx::surface_usage_flags::attachment;
rtt->state_flags = rsx::surface_state_flags::erase_bkgnd;
@ -270,6 +272,7 @@ namespace vk
rsx::surface_depth_format2 format,
usz width, usz height, usz pitch,
rsx::surface_antialiasing antialias,
const rsx::surface_scaling_config_t& resolution_scaling_config,
vk::render_device& device, vk::command_buffer& cmd)
{
const VkFormat requested_format = vk::get_compatible_depth_surface_format(device.get_formats_support(), format);
@ -296,7 +299,7 @@ namespace vk
}
std::unique_ptr<vk::render_target> ds;
const auto [width_, height_] = rsx::apply_resolution_scale<true>(static_cast<u16>(width), static_cast<u16>(height));
const auto [width_, height_] = rsx::apply_resolution_scale<true>(resolution_scaling_config, static_cast<u16>(width), static_cast<u16>(height));
ds = std::make_unique<vk::render_target>(device, device.get_memory_mapping().device_local,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
@ -316,6 +319,7 @@ namespace vk
ds->set_format(format);
ds->set_aa_mode(antialias);
ds->set_resolution_scaling_config(resolution_scaling_config);
ds->sample_layout = sample_layout;
ds->memory_usage_flags = rsx::surface_usage_flags::attachment;
ds->state_flags = rsx::surface_state_flags::erase_bkgnd;
@ -337,7 +341,9 @@ namespace vk
{
if (!sink)
{
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(prev.width, prev.height,
const auto [new_w, new_h] = rsx::apply_resolution_scale<true>(
ref->resolution_scaling_config,
prev.width, prev.height,
ref->get_surface_width<rsx::surface_metrics::pixels>(), ref->get_surface_height<rsx::surface_metrics::pixels>());
auto& dev = cmd.get_command_pool().get_owner();
@ -355,6 +361,10 @@ namespace vk
ref->format_class());
sink->add_ref();
sink->sample_layout = ref->sample_layout;
sink->resolution_scaling_config = ref->resolution_scaling_config;
sink->set_spp(ref->get_spp());
sink->format_info = ref->format_info;
sink->memory_usage_flags = rsx::surface_usage_flags::storage;

View File

@ -214,7 +214,7 @@ namespace vk
const auto local_memory_usage = vmm_get_application_memory_usage(mem_info.device_local);
constexpr u64 _1M = 0x100000;
const auto res_scale = rsx::get_resolution_scale();
const auto res_scale = rsx::get_current_renderer()->resolution_scaling_config.scale_factor();
const auto mem_threshold_1 = static_cast<u64>(256 * res_scale * res_scale) * _1M;
const auto mem_threshold_2 = static_cast<u64>(64 * res_scale * res_scale) * _1M;

View File

@ -37,7 +37,38 @@ namespace rsx
fatal
};
//Base for resources with reference counting
namespace limits
{
enum
{
fragment_textures_count = 16,
vertex_textures_count = 4,
vertex_count = 16,
fragment_count = 32,
tiles_count = 15,
zculls_count = 8,
color_buffers_count = 4
};
}
namespace constants
{
constexpr std::array<const char*, 16> fragment_texture_names =
{
"tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7",
"tex8", "tex9", "tex10", "tex11", "tex12", "tex13", "tex14", "tex15",
};
constexpr std::array<const char*, 4> vertex_texture_names =
{
"vtex0", "vtex1", "vtex2", "vtex3",
};
// Local RSX memory base (known as constant)
constexpr u32 local_mem_base = 0xC0000000;
}
// Base for resources with reference counting
class ref_counted
{
protected:
@ -73,37 +104,6 @@ namespace rsx
}
};
namespace limits
{
enum
{
fragment_textures_count = 16,
vertex_textures_count = 4,
vertex_count = 16,
fragment_count = 32,
tiles_count = 15,
zculls_count = 8,
color_buffers_count = 4
};
}
namespace constants
{
constexpr std::array<const char*, 16> fragment_texture_names =
{
"tex0", "tex1", "tex2", "tex3", "tex4", "tex5", "tex6", "tex7",
"tex8", "tex9", "tex10", "tex11", "tex12", "tex13", "tex14", "tex15",
};
constexpr std::array<const char*, 4> vertex_texture_names =
{
"vtex0", "vtex1", "vtex2", "vtex3",
};
// Local RSX memory base (known as constant)
constexpr u32 local_mem_base = 0xC0000000;
}
/**
* Holds information about a framebuffer
*/
@ -214,6 +214,14 @@ namespace rsx
bool swizzled;
};
struct surface_scaling_config_t
{
u16 scale_percent = 100;
u16 min_scalable_dimension = 0;
f32 scale_factor() const { return scale_percent * 0.01f; }
};
template <typename T>
void pad_texture(const void* input_pixels, void* output_pixels, u16 input_width, u16 input_height, u16 output_width, u16 /*output_height*/)
{
@ -575,28 +583,23 @@ namespace rsx
}
}
static inline f32 get_resolution_scale()
{
return g_cfg.video.strict_rendering_mode ? 1.f : (g_cfg.video.resolution_scale_percent / 100.f);
}
static inline int get_resolution_scale_percent()
{
return g_cfg.video.strict_rendering_mode ? 100 : g_cfg.video.resolution_scale_percent;
}
template <bool clamp = false>
static inline const std::pair<u16, u16> apply_resolution_scale(u16 width, u16 height, u16 ref_width = 0, u16 ref_height = 0)
static inline const std::pair<u16, u16> apply_resolution_scale(
const surface_scaling_config_t& config,
u16 width,
u16 height,
u16 ref_width = 0,
u16 ref_height = 0)
{
ref_width = (ref_width) ? ref_width : width;
ref_height = (ref_height) ? ref_height : height;
const u16 ref = std::max(ref_width, ref_height);
if (ref > g_cfg.video.min_scalable_dimension)
if (ref > config.min_scalable_dimension)
{
// Upscale both width and height
width = (get_resolution_scale_percent() * width) / 100;
height = (get_resolution_scale_percent() * height) / 100;
width = (config.scale_percent * width) / 100;
height = (config.scale_percent * height) / 100;
if constexpr (clamp)
{
@ -609,11 +612,14 @@ namespace rsx
}
template <bool clamp = false>
static inline const std::pair<u16, u16> apply_inverse_resolution_scale(u16 width, u16 height)
static inline const std::pair<u16, u16> apply_inverse_resolution_scale(
const surface_scaling_config_t& config,
u16 width,
u16 height)
{
// Inverse scale
auto width_ = (width * 100) / get_resolution_scale_percent();
auto height_ = (height * 100) / get_resolution_scale_percent();
auto width_ = (width * 100) / config.scale_percent;
auto height_ = (height * 100) / config.scale_percent;
if constexpr (clamp)
{
@ -621,7 +627,7 @@ namespace rsx
height_ = std::max<u16>(height_, 1);
}
if (std::max(width_, height_) > g_cfg.video.min_scalable_dimension)
if (std::max(width_, height_) > config.min_scalable_dimension)
{
return { width_, height_ };
}

View File

@ -15,6 +15,7 @@
#include "Emu/Cell/Modules/cellScreenshot.h"
#include "Emu/Cell/Modules/cellAudio.h"
#include "Emu/Cell/lv2/sys_rsxaudio.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/RSX/rsx_utils.h"
#include "Emu/RSX/Overlays/overlay_message.h"
#include "Emu/Io/interception.h"
@ -1040,7 +1041,7 @@ void gs_frame::take_screenshot(std::vector<u8>&& data, u32 sshot_width, u32 ssho
if (new_size.width != static_cast<u32>(img.width()) || new_size.height != static_cast<u32>(img.height()))
{
const int scale = rsx::get_resolution_scale_percent();
const int scale = rsx::get_current_renderer()->resolution_scaling_config.scale_percent;
const int x = (scale * manager.overlay_offset_x) / 100;
const int y = (scale * manager.overlay_offset_y) / 100;
const int width = (scale * overlay_img.width()) / 100;