From 54999d15077b986bd993a02fb19a82525ffbd224 Mon Sep 17 00:00:00 2001 From: BehroozRezvani Date: Sun, 22 Mar 2026 04:37:20 +0000 Subject: [PATCH 01/98] Add Zed config files to gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 4688d5fa52..a3911be3a0 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,9 @@ CMakeSettings.json *PVS-Studio* PVS/* +# Zed Editor files +.zed/* + # Ignore other system generated files x64/* rpcs3/x64/* From e5840ab8680f896084d766a92f6e20d6c4b12c6a Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 22 Mar 2026 13:29:58 +0100 Subject: [PATCH 02/98] Qt: fix audio timer loop --- rpcs3/rpcs3qt/game_list_grid_item.cpp | 1 + rpcs3/rpcs3qt/qt_video_source.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/rpcs3/rpcs3qt/game_list_grid_item.cpp b/rpcs3/rpcs3qt/game_list_grid_item.cpp index 928a5fa264..a3952a264a 100644 --- a/rpcs3/rpcs3qt/game_list_grid_item.cpp +++ b/rpcs3/rpcs3qt/game_list_grid_item.cpp @@ -77,6 +77,7 @@ bool game_list_grid_item::event(QEvent* event) set_active(true); break; case QEvent::HoverLeave: + case QEvent::FocusOut: set_active(false); break; default: diff --git a/rpcs3/rpcs3qt/qt_video_source.cpp b/rpcs3/rpcs3qt/qt_video_source.cpp index e05b997565..1f60800752 100644 --- a/rpcs3/rpcs3qt/qt_video_source.cpp +++ b/rpcs3/rpcs3qt/qt_video_source.cpp @@ -199,6 +199,7 @@ void qt_video_source::start_movie_timer() if (!m_video_timer) { m_video_timer = std::make_unique(); + m_video_timer->setSingleShot(true); QObject::connect(m_video_timer.get(), &QTimer::timeout, m_video_timer.get(), [this]() { if (!m_active) return; From 1eb72e4b717af63b599fbca00aeada0b81f18ae7 Mon Sep 17 00:00:00 2001 From: Ani Date: Sun, 22 Mar 2026 14:58:21 +0100 Subject: [PATCH 03/98] rpcs3: Add missing #include , fix gcc-16 compilation --- rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp | 1 + rpcs3/util/atomic.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp index 91ee7e2426..b8d9ba75b0 100644 --- a/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp +++ b/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp @@ -10,6 +10,7 @@ #include "cellDmuxPamf.h" #include +#include vm::gvar g_cell_dmux_core_ops_pamf; vm::gvar g_cell_dmux_core_ops_raw_es; diff --git a/rpcs3/util/atomic.cpp b/rpcs3/util/atomic.cpp index 595162cd04..59f0eebe49 100644 --- a/rpcs3/util/atomic.cpp +++ b/rpcs3/util/atomic.cpp @@ -49,6 +49,7 @@ static bool has_waitv() #include #include #include +#include #include "asm.hpp" #include "endian.hpp" From b607993b7b5ba79d6e253aa566766167e19eb154 Mon Sep 17 00:00:00 2001 From: Ani Date: Sun, 22 Mar 2026 15:11:30 +0100 Subject: [PATCH 04/98] overlay: Remove redundant redeclaration Fixes one gcc compilation warning --- rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h index 13f47eb41e..ba8b730d44 100644 --- a/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h +++ b/rpcs3/Emu/RSX/Overlays/HomeMenu/overlay_home_menu_settings.h @@ -10,8 +10,6 @@ namespace rsx { namespace overlays { - void play_sound(sound_effect sound, std::optional volume); - struct home_menu_settings : public home_menu_page { public: From a0c91bf96a235e84de4ae834e6db659077e42a6e Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 21 Mar 2026 23:11:41 +0300 Subject: [PATCH 05/98] overlays: Use SDF equations to represent curved shapes --- rpcs3/Emu/RSX/Overlays/overlay_controls.cpp | 113 +++++++----------- rpcs3/Emu/RSX/Overlays/overlay_controls.h | 36 +++++- .../Program/GLSLSnippets/OverlayRenderFS.glsl | 74 ++++++++++++ rpcs3/Emu/RSX/Program/RSXOverlay.h | 17 ++- 4 files changed, 167 insertions(+), 73 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp index 02b0ff5a68..0a1af3c6c5 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.cpp @@ -585,6 +585,18 @@ namespace rsx return result; } + void overlay_element::configure_sdf(compiled_resource::command_config& config, sdf_function func) + { + config.sdf_config.func = func; + config.sdf_config.cx = margin_left + x + (w / 2.f); + config.sdf_config.cy = margin_top + y + (h / 2.f); + config.sdf_config.hx = w / 2.f; + config.sdf_config.hy = h / 2.f; + config.sdf_config.br = 0.f; + config.sdf_config.bw = border_size; + config.sdf_config.border_color = border_color; + } + compiled_resource& overlay_element::get_compiled() { if (is_compiled()) @@ -609,6 +621,14 @@ namespace rsx config.pulse_sinus_offset = pulse_sinus_offset; config.pulse_speed_modifier = pulse_speed_modifier; + if (border_size != 0 && + border_color.a > 0.f && + w > border_size && + h > border_size) + { + configure_sdf(config, sdf_function::box); + } + auto& verts = compiled_resources_temp.draw_commands.front().verts; verts.resize(4); @@ -1095,82 +1115,33 @@ namespace rsx return compiled_resources; } -#ifdef __APPLE__ - if (true) -#else - if (radius == 0 || radius > (w / 2)) -#endif + overlay_element::get_compiled(); + auto& config = compiled_resources.draw_commands.front().config; + configure_sdf(config, sdf_function::rounded_box); + config.sdf_config.br = radius; + + m_is_compiled = true; + return compiled_resources; + } + + compiled_resource& ellipse::get_compiled() + { + if (is_compiled()) + { + return compiled_resources; + } + + compiled_resources.clear(); + + if (!is_visible()) { - // Invalid radius - compiled_resources = overlay_element::get_compiled(); m_is_compiled = true; return compiled_resources; } - compiled_resource compiled_resources_temp = {}; - compiled_resources_temp.append({}); // Bg horizontal mid - compiled_resources_temp.append({}); // Bg horizontal top - compiled_resources_temp.append({}); // Bg horizontal bottom - compiled_resources_temp.append({}); // Bg upper-left - compiled_resources_temp.append({}); // Bg lower-left - compiled_resources_temp.append({}); // Bg upper-right - compiled_resources_temp.append({}); // Bg lower-right - - for (auto& draw_cmd : compiled_resources_temp.draw_commands) - { - auto& config = draw_cmd.config; - config.color = back_color; - config.disable_vertex_snap = true; - config.pulse_glow = pulse_effect_enabled; - config.pulse_sinus_offset = pulse_sinus_offset; - config.pulse_speed_modifier = pulse_speed_modifier; - } - - auto& bg0 = compiled_resources_temp.draw_commands[0]; - auto& bg1 = compiled_resources_temp.draw_commands[1]; - auto& bg2 = compiled_resources_temp.draw_commands[2]; - - bg0.verts.emplace_back(f32(x), f32(y + radius), 0.f, 0.f); - bg0.verts.emplace_back(f32(x + w), f32(y + radius), 0.f, 0.f); - bg0.verts.emplace_back(f32(x), f32(y + h) - radius, 0.f, 0.f); - bg0.verts.emplace_back(f32(x + w), f32(y + h) - radius, 0.f, 0.f); - - bg1.verts.emplace_back(f32(x + radius), f32(y), 0.f, 0.f); - bg1.verts.emplace_back(f32(x + w) - radius, f32(y), 0.f, 0.f); - bg1.verts.emplace_back(f32(x + radius), f32(y + radius), 0.f, 0.f); - bg1.verts.emplace_back(f32(x + w) - radius, f32(y + radius), 0.f, 0.f); - - bg2.verts.emplace_back(f32(x + radius), f32(y + h) - radius, 0.f, 0.f); - bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h) - radius, 0.f, 0.f); - bg2.verts.emplace_back(f32(x + radius), f32(y + h), 0.f, 0.f); - bg2.verts.emplace_back(f32(x + w) - radius, f32(y + h), 0.f, 0.f); - - // Generate the quadrants - const f32 corners[4][2] = - { - { f32(x + radius), f32(y + radius) }, - { f32(x + radius), f32(y + h) - radius }, - { f32(x + w) - radius, f32(y + radius) }, - { f32(x + w) - radius, f32(y + h) - radius } - }; - - const f32 radius_f = static_cast(radius); - const f32 scale[4][2] = - { - { -radius_f, -radius_f }, - { -radius_f, +radius_f }, - { +radius_f, -radius_f }, - { +radius_f, +radius_f } - }; - - for (int i = 0; i < 4; ++i) - { - auto& command = compiled_resources_temp.draw_commands[i + 3]; - command.config.primitives = rsx::overlays::primitive_type::triangle_fan; - command.verts = generate_unit_quadrant(num_control_points, corners[i], scale[i]); - } - - compiled_resources.add(std::move(compiled_resources_temp), margin_left, margin_top); + rounded_rect::get_compiled(); + auto& config = compiled_resources.draw_commands.front().config; + configure_sdf(config, sdf_function::ellipse); m_is_compiled = true; return compiled_resources; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index dcfe33b199..0932eaa9ed 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -31,6 +31,14 @@ namespace rsx triangle_fan = 4 }; + enum class sdf_function : u8 + { + none = 0, + ellipse, + box, + rounded_box, + }; + struct image_info_base { int w = 0, h = 0, channels = 0; @@ -95,6 +103,20 @@ namespace rsx struct compiled_resource { + struct sdf_config_t + { + sdf_function func = sdf_function::none; + + f32 cx; // Center x + f32 cy; // Center y + f32 hx; // Half-size in X + f32 hy; // Half-size in Y + f32 br; // Border radius + f32 bw; // Border width + + color4f border_color; + }; + struct command_config { primitive_type primitives = primitive_type::quad_list; @@ -105,6 +127,8 @@ namespace rsx f32 pulse_sinus_offset = 0.0f; // The current pulse offset f32 pulse_speed_modifier = 0.005f; + sdf_config_t sdf_config; + areaf clip_rect = {}; bool clip_region = false; @@ -171,6 +195,9 @@ namespace rsx f32 pulse_sinus_offset = 0.0f; // The current pulse offset f32 pulse_speed_modifier = 0.005f; + u8 border_size = 0; + color4f border_color = { 0.f, 0.f, 0.f, 1.f }; + // Analog to command_config::get_sinus_value // Apply modifier for sinus pulse. Resets the pulse. For example: // 0 -> reset to 0.5 rising @@ -237,6 +264,8 @@ namespace rsx protected: bool m_is_compiled = false; // Only use m_is_compiled as a getter in is_compiled() if possible + + void configure_sdf(compiled_resource::command_config& config, sdf_function func); }; struct layout_container : public overlay_element @@ -317,12 +346,17 @@ namespace rsx struct rounded_rect : public overlay_element { u8 radius = 5; - u8 num_control_points = 8; // Smoothness control using overlay_element::overlay_element; compiled_resource& get_compiled() override; }; + struct ellipse : public rounded_rect + { + using rounded_rect::rounded_rect; + compiled_resource& get_compiled() override; + }; + struct image_view : public overlay_element { protected: diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl index 84fdfdb8b7..6bf8b07bee 100644 --- a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl @@ -13,6 +13,11 @@ R"( #define SAMPLER_MODE_FONT3D 2 #define SAMPLER_MODE_TEXTURE2D 3 +#define SDF_DISABLED 0 +#define SDF_ELLIPSE 1 +#define SDF_BOX 2 +#define SDF_ROUND_BOX 3 + #ifdef VULKAN layout(set=0, binding=0) uniform sampler2D fs0; layout(set=0, binding=1) uniform sampler2DArray fs1; @@ -34,11 +39,17 @@ layout(%push_block) uniform FragmentConfiguration uint fragment_config; float timestamp; float blur_intensity; + vec4 sdf_params; + vec4 sdf_origin; + vec4 sdf_border_color; }; #else uniform uint fragment_config; uniform float timestamp; uniform float blur_intensity; + uniform vec4 sdf_params; + uniform vec2 sdf_origin; + uniform vec4 sdf_border_color; #endif struct config_t @@ -46,6 +57,7 @@ struct config_t bool clip_fragments; bool use_pulse_glow; uint sampler_mode; + uint sdf; }; config_t unpack_fragment_options() @@ -54,9 +66,64 @@ config_t unpack_fragment_options() result.clip_fragments = bitfieldExtract(fragment_config, 0, 1) != 0; result.use_pulse_glow = bitfieldExtract(fragment_config, 1, 1) != 0; result.sampler_mode = bitfieldExtract(fragment_config, 2, 2); + result.sdf = bitfieldExtract(fragment_config, 4, 2); return result; } +vec4 SDF_blend( + const in float sd, + const in float border_width, + const in vec4 inner_color, + const in vec4 border_color, + const in vec4 outer_color) +{ + // Crucially, we need to get the derivative without subracting the border width. + // Subtracting the border width makes the function non-continuous and makes the jaggies hard to get rid of. + float fw = fwidth(sd); + + // Compute the two transition points. The inner edge is of course biased by the border amount as the clamping point + // Treat smoothstep as fancy clamp where e0 < x < e1 + float a = smoothstep(-border_width + fw, -border_width - fw, sd); // inner edge transition + float b = smoothstep(fw, -fw, sd); // outer edge transition + + // Mix the 3 colors with the transition values. + vec4 color = mix(outer_color, border_color, b); + color = mix(color, inner_color, a); + return color; +} + +float SDF_fn(const in uint sdf) +{ + const vec2 p = floor(gl_FragCoord.xy) - sdf_origin.xy; // Screen-spac distance + const vec2 hs = sdf_params.xy; // Half size + const float r = sdf_params.z; // Radius (for round box, ellipses use half size instead) + vec2 v; // Scratch + float d; // Distance calculated + + switch (sdf) + { + case SDF_ELLIPSE: + // Slightly inaccurate hack, but good enough for classification and allows oval shapes + d = length(p / hs) - 1.f; + // Now we need to correct for the border because the circle was scaled down to a unit + return d * length(hs); + case SDF_BOX: + // Insanity, reduced junction of 3 functions + // If for each axis the axis-aligned distance = D then you can select/clamp each axis separately by doing a max(D, 0) on all dimensions + // Length then does the squareroot transformation. + // The second term is to add back the inner distance which is useful for rendering borders + v = abs(p) - hs; + return length(max(v, 0.f)) + min(max(v.x, v.y), 0.0); + case SDF_ROUND_BOX: + // Modified BOX SDF. + // The half box size is shrunk by R in it's diagonal, but we add radius back into the output to bias the output again + v = abs(p) - (hs - r); + return length(max(v, 0.f)) + min(max(v.x, v.y), 0.0) - r; + default: + return -1.f; + } +} + vec4 blur_sample(sampler2D tex, vec2 coord, vec2 tex_offset) { vec2 coords[9]; @@ -125,6 +192,13 @@ void main() diff_color.a *= (sin(timestamp) + 1.f) * 0.5f; } + if (config.sdf != SDF_DISABLED) + { + const float border_w = sdf_params.w; // Border width + const float d = SDF_fn(config.sdf); + diff_color = SDF_blend(d, border_w, diff_color, sdf_border_color, vec4(0.)); + } + switch (config.sampler_mode) { default: diff --git a/rpcs3/Emu/RSX/Program/RSXOverlay.h b/rpcs3/Emu/RSX/Program/RSXOverlay.h index ebb2071a8b..42ee92823d 100644 --- a/rpcs3/Emu/RSX/Program/RSXOverlay.h +++ b/rpcs3/Emu/RSX/Program/RSXOverlay.h @@ -23,7 +23,8 @@ namespace rsx { fragment_clip_bit = 0, pulse_glow_bit = 1, - sampling_mode_bit = 2 + sampling_mode_bit = 2, + sdf_func_offset_bit = 4 }; public: @@ -51,6 +52,13 @@ namespace rsx return *this; } + fragment_options& set_sdf(sdf_function func) + { + value &= ~(0x3 << e_offsets::sdf_func_offset_bit); + value |= (static_cast(func) << e_offsets::sdf_func_offset_bit); + return *this; + } + u32 get() const { return value; @@ -74,6 +82,13 @@ namespace rsx } } + void set_bits(u32 offset, u32 count, u32 set) + { + const u32 mask = (0xffffffffu >> (32 - count)) << offset; + value &= ~mask; + value |= set; + } + public: vertex_options& disable_vertex_snap(bool enable) { From 45bae0046a3e792ae20c572c863a5347d8ac594b Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 21 Mar 2026 23:14:34 +0300 Subject: [PATCH 06/98] vk: Add support for basic SDF rendering - Does not support scaled coordinates yet --- rpcs3/Emu/RSX/VK/VKOverlays.cpp | 21 +++++++++++++++++++-- rpcs3/Emu/RSX/VK/VKOverlays.h | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 55daab4a90..c555e7a341 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -510,7 +510,7 @@ namespace vk glsl::input_type_push_constant, 0, 0, - glsl::push_constant_ref {.offset = 68, .size = 12 } + glsl::push_constant_ref {.offset = 68, .size = 60 } ) ); return result; @@ -527,6 +527,10 @@ namespace vk // 68: uint fragment_config; // 72: float timestamp; // 76: float blur_intensity; + // 80: vec4 sdf_params; + // 96: vec2 sdf_origin; + // 104: vec2 reserved; + // 112: vec4 sdf_border_color; f32 push_buf[32]; // 1. Vertex config (00 - 63) @@ -557,13 +561,24 @@ namespace vk .texture_mode(m_texture_type) .clip_fragments(m_clip_enabled) .pulse_glow(m_pulse_glow) + .set_sdf(m_sdf_config.func) .get(); push_buf[0] = std::bit_cast(frag_config); push_buf[1] = m_time; push_buf[2] = m_blur_strength; + push_buf[3] = m_sdf_config.hx; + push_buf[4] = m_sdf_config.hy; + push_buf[5] = m_sdf_config.br; + push_buf[6] = m_sdf_config.bw; + push_buf[7] = m_sdf_config.cx; + push_buf[8] = m_sdf_config.cy; + push_buf[9] = 0.f; + push_buf[10] = 0.f; - vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 68, 12, push_buf); + std::memcpy(push_buf + 11, m_sdf_config.border_color.rgba, 16); + + vkCmdPushConstants(cmd, program->layout(), VK_SHADER_STAGE_FRAGMENT_BIT, 68, 60, push_buf); } void ui_overlay_renderer::set_primitive_type(rsx::overlays::primitive_type type) @@ -644,6 +659,8 @@ namespace vk m_clip_region = command.config.clip_rect; m_disable_vertex_snap = command.config.disable_vertex_snap; + m_sdf_config = command.config.sdf_config; + vk::image_view* src = nullptr; switch (command.config.texture_ref) { diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 414c7c4945..de2c218ebe 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -132,6 +132,8 @@ namespace vk areaf m_clip_region; coordf m_viewport; + rsx::overlays::compiled_resource::sdf_config_t m_sdf_config{}; + std::vector> resources; std::unordered_map> font_cache; std::unordered_map> view_cache; From 57e37862f44292b73540e8d8939a71ac9d953d81 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 21 Mar 2026 23:18:36 +0300 Subject: [PATCH 07/98] overlays: Use ellipse SDF for circles --- rpcs3/Emu/RSX/Overlays/overlay_checkbox.cpp | 2 +- rpcs3/Emu/RSX/Overlays/overlay_slider.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpcs3/Emu/RSX/Overlays/overlay_checkbox.cpp b/rpcs3/Emu/RSX/Overlays/overlay_checkbox.cpp index f7cb19237e..d3199f0866 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_checkbox.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_checkbox.cpp @@ -99,7 +99,7 @@ namespace rsx::overlays } auto ellipse_part = std::make_unique(); - auto circle_part = std::make_unique(); + auto circle_part = std::make_unique(); ellipse_part->set_size(dim * 2, dim / 2); ellipse_part->set_pos(0, dim / 4); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_slider.cpp b/rpcs3/Emu/RSX/Overlays/overlay_slider.cpp index bf00563ef5..0040d5b20d 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_slider.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_slider.cpp @@ -29,7 +29,7 @@ namespace rsx::overlays // Base components auto background = std::make_unique(); auto foreground = std::make_unique(); - auto indicator = std::make_unique(); + auto indicator = std::make_unique(); auto value_label = std::make_unique