From 64ec99be33939467f1eff8360349a492463cb2da Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sat, 4 Feb 2023 22:10:29 +0300 Subject: [PATCH] rsx: Unify UI rendering shaders --- rpcs3/Emu/RSX/GL/GLOverlays.cpp | 158 ++---------- .../Program/GLSLSnippets/OverlayRenderFS.glsl | 145 +++++++++++ .../Program/GLSLSnippets/OverlayRenderVS.glsl | 60 +++++ rpcs3/Emu/RSX/Program/RSXOverlay.h | 60 +++++ rpcs3/Emu/RSX/VK/VKOverlays.cpp | 236 ++++++------------ rpcs3/Emu/RSX/VK/VKOverlays.h | 8 +- rpcs3/emucore.vcxproj | 3 + rpcs3/emucore.vcxproj.filters | 9 + 8 files changed, 379 insertions(+), 300 deletions(-) create mode 100644 rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl create mode 100644 rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderVS.glsl create mode 100644 rpcs3/Emu/RSX/Program/RSXOverlay.h diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.cpp b/rpcs3/Emu/RSX/GL/GLOverlays.cpp index d140b88b68..df92d383db 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.cpp +++ b/rpcs3/Emu/RSX/GL/GLOverlays.cpp @@ -1,6 +1,7 @@ #include "GLOverlays.h" #include "../rsx_utils.h" +#include "../Program/RSXOverlay.h" namespace gl { @@ -194,132 +195,19 @@ namespace gl ui_overlay_renderer::ui_overlay_renderer() { vs_src = - "#version 420\n\n" - "layout(location=0) in vec4 in_pos;\n" - "layout(location=0) out vec2 tc0;\n" - "layout(location=1) flat out vec4 clip_rect;\n" - "uniform vec4 ui_scale;\n" - "uniform vec4 viewport;\n" - "uniform vec4 clip_bounds;\n" - "\n" - "vec2 snap_to_grid(vec2 normalized)\n" - "{\n" - " return (floor(normalized * viewport.xy) + 0.5) / viewport.xy;\n" - "}\n" - "\n" - "vec4 clip_to_ndc(const in vec4 coord)\n" - "{\n" - " vec4 ret = (coord * ui_scale.zwzw) / ui_scale.xyxy;\n" - " ret.yw = 1. - ret.yw;\n" - " return ret;\n" - "}\n" - "\n" - "vec4 ndc_to_window(const in vec4 coord)\n" - "{\n" - " return fma(coord, viewport.xyxy, viewport.zwzw);\n" - "}\n" - "\n" - "void main()\n" - "{\n" - " tc0.xy = in_pos.zw;\n" - " clip_rect = ndc_to_window(clip_to_ndc(clip_bounds)).xwzy; // Swap y1 and y2 due to flipped origin!\n" - " vec4 pos = vec4(clip_to_ndc(in_pos).xy, 0.5, 1.);\n" - " pos.xy = snap_to_grid(pos.xy);\n" - " gl_Position = (pos + pos) - 1.;\n" - "}\n"; + #include "../Program/GLSLSnippets/OverlayRenderVS.glsl" + ; fs_src = - "#version 420\n\n" - "layout(binding=31) uniform sampler2D fs0;\n" - "layout(binding=30) uniform sampler2DArray fs1;\n" - "layout(location=0) in vec2 tc0;\n" - "layout(location=1) flat in vec4 clip_rect;\n" - "layout(location=0) out vec4 ocol;\n" - "uniform vec4 color;\n" - "uniform float time;\n" - "uniform int sampler_mode;\n" - "uniform int pulse_glow;\n" - "uniform int clip_region;\n" - "uniform int blur_strength;\n" - "\n" - "vec4 blur_sample(sampler2D tex, vec2 coord, vec2 tex_offset)\n" - "{\n" - " vec2 coords[9];\n" - " coords[0] = coord - tex_offset\n;" - " coords[1] = coord + vec2(0., -tex_offset.y);\n" - " coords[2] = coord + vec2(tex_offset.x, -tex_offset.y);\n" - " coords[3] = coord + vec2(-tex_offset.x, 0.);\n" - " coords[4] = coord;\n" - " coords[5] = coord + vec2(tex_offset.x, 0.);\n" - " coords[6] = coord + vec2(-tex_offset.x, tex_offset.y);\n" - " coords[7] = coord + vec2(0., tex_offset.y);\n" - " coords[8] = coord + tex_offset;\n" - "\n" - " float weights[9] =\n" - " {\n" - " 1., 2., 1.,\n" - " 2., 4., 2.,\n" - " 1., 2., 1.\n" - " };\n" - "\n" - " vec4 blurred = vec4(0.);\n" - " for (int n = 0; n < 9; ++n)\n" - " {\n" - " blurred += texture(tex, coords[n]) * weights[n];\n" - " }\n" - "\n" - " return blurred / 16.f;\n" - "}\n" - "\n" - "vec4 sample_image(sampler2D tex, vec2 coord)\n" - "{\n" - " vec4 original = texture(tex, coord);\n" - " if (blur_strength == 0) return original;\n" - " \n" - " vec2 constraints = 1.f / vec2(640, 360);\n" - " vec2 res_offset = 1.f / textureSize(fs0, 0);\n" - " vec2 tex_offset = max(res_offset, constraints);\n" - "\n" - " // Sample triangle pattern and average\n" - " // TODO: Nicer looking gaussian blur with less sampling\n" - " vec4 blur0 = blur_sample(tex, coord + vec2(-res_offset.x, 0.), tex_offset);\n" - " vec4 blur1 = blur_sample(tex, coord + vec2(res_offset.x, 0.), tex_offset);\n" - " vec4 blur2 = blur_sample(tex, coord + vec2(0., res_offset.y), tex_offset);\n" - "\n" - " vec4 blurred = blur0 + blur1 + blur2;\n" - " blurred /= 3.;\n" - " return mix(original, blurred, float(blur_strength) / 100.);\n" - "}\n" - "\n" - "void main()\n" - "{\n" - " if (clip_region != 0)\n" - " {" - " if (gl_FragCoord.x < clip_rect.x || gl_FragCoord.x > clip_rect.z ||\n" - " gl_FragCoord.y < clip_rect.y || gl_FragCoord.y > clip_rect.w)\n" - " {\n" - " discard;\n" - " return;\n" - " }\n" - " }\n" - "\n" - " vec4 diff_color = color;\n" - " if (pulse_glow != 0)\n" - " diff_color.a *= (sin(time) + 1.f) * 0.5f;\n" - "\n" - " switch (sampler_mode)\n" - " {\n" - " case 1:\n" - " ocol = sample_image(fs0, tc0) * diff_color;\n" - " break;\n" - " case 2:\n" - " ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))) * diff_color;\n" - " break;\n" - " default:\n" - " ocol = diff_color;\n" - " break;\n" - " }\n" - "}\n"; + #include "../Program/GLSLSnippets/OverlayRenderFS.glsl" + ; + + vs_src = fmt::replace_all(vs_src, + { + { "#version 450", "#version 420" }, + { "%preprocessor", "// %preprocessor" } + }); + fs_src = fmt::replace_all(fs_src, "%preprocessor", "// %preprocessor"); // Smooth filtering required for inputs m_input_filter = gl::filter::linear; @@ -513,7 +401,7 @@ namespace gl set_primitive_type(cmd.config.primitives); upload_vertex_data(cmd.verts.data(), ::size32(cmd.verts)); num_drawable_elements = ::size32(cmd.verts); - GLint texture_read = GL_TRUE; + auto texture_mode = rsx::overlays::texture_sampling_mode::texture2D; switch (cmd.config.texture_ref) { @@ -522,7 +410,7 @@ namespace gl // TODO case rsx::overlays::image_resource_id::none: { - texture_read = GL_FALSE; + texture_mode = rsx::overlays::texture_sampling_mode::none; cmd_->bind_texture(31, GL_TEXTURE_2D, GL_NONE); break; } @@ -533,7 +421,7 @@ namespace gl } case rsx::overlays::image_resource_id::font_file: { - texture_read = (GL_TRUE + 1); + texture_mode = rsx::overlays::texture_sampling_mode::font3D; cmd_->bind_texture(30, GL_TEXTURE_2D_ARRAY, find_font(cmd.config.font_ref)->id()); break; } @@ -544,13 +432,17 @@ namespace gl } } - program_handle.uniforms["time"] = cmd.config.get_sinus_value(); - program_handle.uniforms["color"] = cmd.config.color; - program_handle.uniforms["sampler_mode"] = texture_read; - program_handle.uniforms["pulse_glow"] = static_cast(cmd.config.pulse_glow); - program_handle.uniforms["blur_strength"] = static_cast(cmd.config.blur_strength); - program_handle.uniforms["clip_region"] = static_cast(cmd.config.clip_region); + rsx::overlays::fragment_options draw_opts; + program_handle.uniforms["fragment_config"] = draw_opts + .texture_mode(texture_mode) + .clip_fragments(cmd.config.clip_region) + .pulse_glow(cmd.config.pulse_glow) + .get(); + + program_handle.uniforms["timestamp"] = cmd.config.get_sinus_value(); + program_handle.uniforms["albedo"] = cmd.config.color; program_handle.uniforms["clip_bounds"] = cmd.config.clip_rect; + program_handle.uniforms["blur_intensity"] = static_cast(cmd.config.blur_strength); overlay_pass::run(cmd_, viewport, target, gl::image_aspect::color, true); } diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl new file mode 100644 index 0000000000..7ac6c0a694 --- /dev/null +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderFS.glsl @@ -0,0 +1,145 @@ +R"( +#version 420 +#extension GL_ARB_separate_shader_objects : enable + +%preprocessor + +#ifdef VULKAN +#define USE_UBO 1 +#endif + +#define SAMPLER_MODE_NONE 0 +#define SAMPLER_MODE_FONT2D 1 +#define SAMPLER_MODE_FONT3D 2 +#define SAMPLER_MODE_TEXTURE2D 3 + +#ifdef VULKAN + layout(set=0, binding=1) uniform sampler2D fs0; + layout(set=0, binding=2) uniform sampler2DArray fs1; +#else + layout(binding=31) uniform sampler2D fs0; + layout(binding=30) uniform sampler2DArray fs1; +#endif + +layout(location=0) in vec2 tc0; +layout(location=1) in vec4 color; +layout(location=2) in vec4 clip_rect; + +layout(location=0) out vec4 ocol; + +#if USE_UBO +layout(%push_block) uniform FragmentConfiguration +{ + %push_block_offset + uint fragment_config; + float timestamp; + float blur_intensity; +}; +#else + uniform uint fragment_config; + uniform float timestamp; + uniform float blur_intensity; +#endif + +struct config_t +{ + bool clip_fragments; + bool use_pulse_glow; + uint sampler_mode; +}; + +config_t unpack_fragment_options() +{ + config_t result; + 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); + return result; +} + +vec4 blur_sample(sampler2D tex, vec2 coord, vec2 tex_offset) +{ + vec2 coords[9]; + coords[0] = coord - tex_offset; + coords[1] = coord + vec2(0., -tex_offset.y); + coords[2] = coord + vec2(tex_offset.x, -tex_offset.y); + coords[3] = coord + vec2(-tex_offset.x, 0.); + coords[4] = coord; + coords[5] = coord + vec2(tex_offset.x, 0.); + coords[6] = coord + vec2(-tex_offset.x, tex_offset.y); + coords[7] = coord + vec2(0., tex_offset.y); + coords[8] = coord + tex_offset; + + float weights[9] = + { + 1., 2., 1., + 2., 4., 2., + 1., 2., 1. + }; + + vec4 blurred = vec4(0.); + for (int n = 0; n < 9; ++n) + { + blurred += texture(tex, coords[n]) * weights[n]; + } + + return blurred / 16.f; +} + +vec4 sample_image(sampler2D tex, vec2 coord, float blur_strength) +{ + vec4 original = texture(tex, coord); + if (blur_strength == 0) return original; + + vec2 constraints = 1.f / vec2(640, 360); + vec2 res_offset = 1.f / textureSize(fs0, 0); + vec2 tex_offset = max(res_offset, constraints); + + // Sample triangle pattern and average + // TODO: Nicer looking gaussian blur with less sampling + vec4 blur0 = blur_sample(tex, coord + vec2(-res_offset.x, 0.), tex_offset); + vec4 blur1 = blur_sample(tex, coord + vec2(res_offset.x, 0.), tex_offset); + vec4 blur2 = blur_sample(tex, coord + vec2(0., res_offset.y), tex_offset); + + vec4 blurred = blur0 + blur1 + blur2; + blurred /= 3.; + return mix(original, blurred, blur_strength); +} + +void main() +{ + config_t config = unpack_fragment_options(); + if (config.clip_fragments) + { + if (gl_FragCoord.x < clip_rect.x || gl_FragCoord.x > clip_rect.z || + gl_FragCoord.y < clip_rect.y || gl_FragCoord.y > clip_rect.w) + { + discard; + return; + } + } + + vec4 diff_color = color; + if (config.use_pulse_glow) + { + diff_color.a *= (sin(timestamp) + 1.f) * 0.5f; + } + + switch (config.sampler_mode) + { + default: + case SAMPLER_MODE_NONE: + ocol = diff_color; + break; + case SAMPLER_MODE_FONT2D: + ocol = texture(fs0, tc0).rrrr * diff_color; + break; + case SAMPLER_MODE_FONT3D: + ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color; + break; + case SAMPLER_MODE_TEXTURE2D: + ocol = sample_image(fs0, tc0, blur_intensity).bgra * diff_color; + break; + } +} +)" diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderVS.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderVS.glsl new file mode 100644 index 0000000000..177b2eea4b --- /dev/null +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/OverlayRenderVS.glsl @@ -0,0 +1,60 @@ +R"( +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +%preprocessor + +#ifdef VULKAN + #define USE_UBO 1 +#endif + +layout(location=0) in vec4 in_pos; +layout(location=0) out vec2 tc0; +layout(location=1) out vec4 color; +layout(location=2) out vec4 clip_rect; + +#if USE_UBO +layout(%push_block) uniform Configuration +{ + vec4 ui_scale; + vec4 albedo; + vec4 viewport; + vec4 clip_bounds; +}; +#else + uniform vec4 ui_scale; + uniform vec4 albedo; + uniform vec4 viewport; + uniform vec4 clip_bounds; +#endif + +vec2 snap_to_grid(const in vec2 normalized) +{ + return floor(fma(normalized, viewport.xy, vec2(0.5))) / viewport.xy; +} + +vec4 clip_to_ndc(const in vec4 coord) +{ + vec4 ret = (coord * ui_scale.zwzw) / ui_scale.xyxy; +#ifndef VULKAN + // Flip Y for OpenGL + ret.yw = 1. - ret.yw; +#endif + return ret; +} + +vec4 ndc_to_window(const in vec4 coord) +{ + return fma(coord, viewport.xyxy, viewport.zwzw); +} + +void main() +{ + tc0.xy = in_pos.zw; + color = albedo; + clip_rect = ndc_to_window(clip_to_ndc(clip_bounds)); + vec4 pos = vec4(clip_to_ndc(in_pos).xy, 0.5, 1.); + pos.xy = snap_to_grid(pos.xy); + gl_Position = (pos + pos) - 1.; +} +)" diff --git a/rpcs3/Emu/RSX/Program/RSXOverlay.h b/rpcs3/Emu/RSX/Program/RSXOverlay.h new file mode 100644 index 0000000000..e705557c86 --- /dev/null +++ b/rpcs3/Emu/RSX/Program/RSXOverlay.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +namespace rsx +{ + namespace overlays + { + // This is overlay common code meant only for render backends + enum class texture_sampling_mode: s32 + { + none = 0, + font2D = 1, + font3D = 2, + texture2D = 3 + }; + + class fragment_options + { + u32 value = 0; + + enum e_offsets: s32 + { + fragment_clip_bit = 0, + pulse_glow_bit = 1, + sampling_mode_bit = 2 + }; + + public: + fragment_options& texture_mode(texture_sampling_mode mode) + { + value |= static_cast(mode) << e_offsets::sampling_mode_bit; + return *this; + } + + fragment_options& pulse_glow(bool enable = true) + { + if (enable) + { + value |= (1 << e_offsets::pulse_glow_bit); + } + return *this; + } + + fragment_options& clip_fragments(bool enable = true) + { + if (enable) + { + value |= (1 << e_offsets::fragment_clip_bit); + } + return *this; + } + + u32 get() const + { + return value; + } + }; + } +} diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.cpp b/rpcs3/Emu/RSX/VK/VKOverlays.cpp index 62aa4d9460..29ff72b065 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.cpp +++ b/rpcs3/Emu/RSX/VK/VKOverlays.cpp @@ -11,6 +11,7 @@ #include "vkutils/scratch.h" #include "../Overlays/overlays.h" +#include "../Program/RSXOverlay.h" #include "util/fnv_hash.hpp" @@ -353,137 +354,25 @@ namespace vk ui_overlay_renderer::ui_overlay_renderer() { vs_src = - "#version 450\n" - "#extension GL_ARB_separate_shader_objects : enable\n" - "layout(location=0) in vec4 in_pos;\n" - "layout(std140, set=0, binding=0) uniform static_data{ vec4 regs[8]; };\n" - "layout(location=0) out vec2 tc0;\n" - "layout(location=1) out vec4 color;\n" - "layout(location=2) out vec4 parameters;\n" - "layout(location=3) out vec4 clip_rect;\n" - "layout(location=4) out vec4 parameters2;\n" - "\n" - "vec2 snap_to_grid(const in vec2 normalized)\n" - "{\n" - " return (floor(normalized * regs[5].xy) + 0.5) / regs[5].xy;\n" - "}\n" - "\n" - "vec4 clip_to_ndc(const in vec4 coord)\n" - "{\n" - " return (coord * regs[0].zwzw) / regs[0].xyxy;\n" - "}\n" - "\n" - "vec4 ndc_to_window(const in vec4 coord)\n" - "{\n" - " return fma(coord, regs[5].xyxy, regs[5].zwzw);\n" - "}\n" - "\n" - "void main()\n" - "{\n" - " tc0.xy = in_pos.zw;\n" - " color = regs[1];\n" - " parameters = regs[2];\n" - " parameters2 = regs[4];\n" - " clip_rect = ndc_to_window(clip_to_ndc(regs[3]));\n" - " vec4 pos = vec4(clip_to_ndc(in_pos).xy, 0.5, 1.);\n" - " pos.xy = snap_to_grid(pos.xy);\n" - " gl_Position = (pos + pos) - 1.;\n" - "}\n"; + #include "../Program/GLSLSnippets/OverlayRenderVS.glsl" + ; fs_src = - "#version 420\n" - "#extension GL_ARB_separate_shader_objects : enable\n" - "layout(set=0, binding=1) uniform sampler2D fs0;\n" - "layout(set=0, binding=2) uniform sampler2DArray fs1;\n" - "layout(location=0) in vec2 tc0;\n" - "layout(location=1) in vec4 color;\n" - "layout(location=2) in vec4 parameters;\n" - "layout(location=3) in vec4 clip_rect;\n" - "layout(location=4) in vec4 parameters2;\n" - "layout(location=0) out vec4 ocol;\n" - "\n" - "vec4 blur_sample(sampler2D tex, vec2 coord, vec2 tex_offset)\n" - "{\n" - " vec2 coords[9];\n" - " coords[0] = coord - tex_offset\n;" - " coords[1] = coord + vec2(0., -tex_offset.y);\n" - " coords[2] = coord + vec2(tex_offset.x, -tex_offset.y);\n" - " coords[3] = coord + vec2(-tex_offset.x, 0.);\n" - " coords[4] = coord;\n" - " coords[5] = coord + vec2(tex_offset.x, 0.);\n" - " coords[6] = coord + vec2(-tex_offset.x, tex_offset.y);\n" - " coords[7] = coord + vec2(0., tex_offset.y);\n" - " coords[8] = coord + tex_offset;\n" - "\n" - " float weights[9] =\n" - " {\n" - " 1., 2., 1.,\n" - " 2., 4., 2.,\n" - " 1., 2., 1.\n" - " };\n" - "\n" - " vec4 blurred = vec4(0.);\n" - " for (int n = 0; n < 9; ++n)\n" - " {\n" - " blurred += texture(tex, coords[n]) * weights[n];\n" - " }\n" - "\n" - " return blurred / 16.f;\n" - "}\n" - "\n" - "vec4 sample_image(sampler2D tex, vec2 coord, float blur_strength)\n" - "{\n" - " vec4 original = texture(tex, coord);\n" - " if (blur_strength == 0) return original;\n" - " \n" - " vec2 constraints = 1.f / vec2(640, 360);\n" - " vec2 res_offset = 1.f / textureSize(fs0, 0);\n" - " vec2 tex_offset = max(res_offset, constraints);\n" - "\n" - " // Sample triangle pattern and average\n" - " // TODO: Nicer looking gaussian blur with less sampling\n" - " vec4 blur0 = blur_sample(tex, coord + vec2(-res_offset.x, 0.), tex_offset);\n" - " vec4 blur1 = blur_sample(tex, coord + vec2(res_offset.x, 0.), tex_offset);\n" - " vec4 blur2 = blur_sample(tex, coord + vec2(0., res_offset.y), tex_offset);\n" - "\n" - " vec4 blurred = blur0 + blur1 + blur2;\n" - " blurred /= 3.;\n" - " return mix(original, blurred, blur_strength);\n" - "}\n" - "\n" - "void main()\n" - "{\n" - " if (parameters.w != 0)\n" - " {" - " if (gl_FragCoord.x < clip_rect.x || gl_FragCoord.x > clip_rect.z ||\n" - " gl_FragCoord.y < clip_rect.y || gl_FragCoord.y > clip_rect.w)\n" - " {\n" - " discard;\n" - " return;\n" - " }\n" - " }\n" - "\n" - " vec4 diff_color = color;\n" - " if (parameters.y != 0)\n" - " diff_color.a *= (sin(parameters.x) + 1.f) * 0.5f;\n" - "\n" - " if (parameters.z < 1.)\n" - " {\n" - " ocol = diff_color;\n" - " }\n" - " else if (parameters.z > 2.)\n" - " {\n" - " ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color;\n" - " }\n" - " else if (parameters.z > 1.)\n" - " {\n" - " ocol = texture(fs0, tc0).rrrr * diff_color;\n" - " }\n" - " else\n" - " {\n" - " ocol = sample_image(fs0, tc0, parameters2.x).bgra * diff_color;\n" - " }\n" - "}\n"; + #include "../Program/GLSLSnippets/OverlayRenderFS.glsl" + ; + + vs_src = fmt::replace_all(vs_src, + { + { "%preprocessor", "// %preprocessor" }, + { "%push_block", "push_constant" } + }); + + fs_src = fmt::replace_all(fs_src, + { + { "%preprocessor", "// %preprocessor" }, + { "%push_block_offset", "layout(offset=64)" }, + { "%push_block", "push_constant" } + }); // 2 input textures m_num_usable_samplers = 2; @@ -646,45 +535,63 @@ namespace vk false, true, desc->data, owner_uid); } - void ui_overlay_renderer::update_uniforms(vk::command_buffer& /*cmd*/, vk::glsl::program* /*program*/) + std::vector ui_overlay_renderer::get_push_constants() { - m_ubo_offset = static_cast(m_ubo.alloc<256>(128)); - auto dst = static_cast(m_ubo.map(m_ubo_offset, 128)); + return + { + { + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .offset = 0, + .size = 64 + }, + { + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + .offset = 64, + .size = 16 + } + }; + } - // regs[0] = scaling parameters - dst[0] = m_scale_offset.r; - dst[1] = m_scale_offset.g; - dst[2] = m_scale_offset.b; - dst[3] = m_scale_offset.a; + void ui_overlay_renderer::update_uniforms(vk::command_buffer& cmd, vk::glsl::program* /*program*/) + { + // Byte Layout + // 00: vec4 ui_scale; + // 16: vec4 albedo; + // 32: vec4 viewport; + // 48: vec4 clip_bounds; + // 64: uint fragment_config; + // 68: float timestamp; + // 72: float blur_intensity; - // regs[1] = color - dst[4] = m_color.r; - dst[5] = m_color.g; - dst[6] = m_color.b; - dst[7] = m_color.a; + f32 push_buf[32]; + // 1. Vertex config (00 - 63) + std::memcpy(push_buf, m_scale_offset.rgba, 16); + std::memcpy(push_buf + 4, m_color.rgba, 16); - // regs[2] = fs config parameters - dst[8] = m_time; - dst[9] = m_pulse_glow? 1.f : 0.f; - dst[10] = m_skip_texture_read? 0.f : static_cast(m_texture_type); - dst[11] = m_clip_enabled ? 1.f : 0.f; + push_buf[8] = m_viewport.width; + push_buf[9] = m_viewport.height; + push_buf[10] = m_viewport.x; + push_buf[11] = m_viewport.y; - // regs[3] = clip rect - dst[12] = m_clip_region.x1; - dst[13] = m_clip_region.y1; - dst[14] = m_clip_region.x2; - dst[15] = m_clip_region.y2; + push_buf[12] = m_clip_region.x1; + push_buf[13] = m_clip_region.y1; + push_buf[14] = m_clip_region.x2; + push_buf[15] = m_clip_region.y2; - // regs[4] = fs config parameters 2 - dst[16] = m_blur_strength; + // 2. Fragment stuff + rsx::overlays::fragment_options frag_opts; + const auto frag_config = frag_opts + .texture_mode(m_texture_type) + .clip_fragments(m_clip_enabled) + .pulse_glow(m_pulse_glow) + .get(); - // regs[5] = viewport - dst[20] = m_viewport.width; - dst[21] = m_viewport.height; - dst[22] = m_viewport.x; - dst[23] = m_viewport.y; + std::memcpy(push_buf + 16, &frag_config, 4); + //push_buf[16] = std::bit_cast(frag_config); + push_buf[17] = m_time; + push_buf[18] = m_blur_strength; - m_ubo.unmap(); + vkCmdPushConstants(cmd, m_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, 80, push_buf); } void ui_overlay_renderer::set_primitive_type(rsx::overlays::primitive_type type) @@ -757,13 +664,12 @@ namespace vk set_primitive_type(command.config.primitives); m_time = command.config.get_sinus_value(); - m_skip_texture_read = false; + m_texture_type = rsx::overlays::texture_sampling_mode::texture2D; m_color = command.config.color; m_pulse_glow = command.config.pulse_glow; m_blur_strength = static_cast(command.config.blur_strength) * 0.01f; m_clip_enabled = command.config.clip_region; m_clip_region = command.config.clip_rect; - m_texture_type = 1; vk::image_view* src = nullptr; switch (command.config.texture_ref) @@ -772,11 +678,13 @@ namespace vk case rsx::overlays::image_resource_id::backbuffer: // TODO case rsx::overlays::image_resource_id::none: - m_skip_texture_read = true; + m_texture_type = rsx::overlays::texture_sampling_mode::none; break; case rsx::overlays::image_resource_id::font_file: src = find_font(command.config.font_ref, cmd, upload_heap); - m_texture_type = src->image()->layers() == 1 ? 2 : 3; + m_texture_type = src->image()->layers() == 1 + ? rsx::overlays::texture_sampling_mode::font2D + : rsx::overlays::texture_sampling_mode::font3D; break; case rsx::overlays::image_resource_id::raw_image: src = find_temp_image(static_cast(command.config.external_data_ref), cmd, upload_heap, ui.uid); diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 811f519f96..31111ba06f 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -18,6 +18,7 @@ namespace rsx { namespace overlays { + enum class texture_sampling_mode; struct overlay; } } @@ -135,9 +136,8 @@ namespace vk color4f m_scale_offset; color4f m_color; bool m_pulse_glow = false; - bool m_skip_texture_read = false; bool m_clip_enabled = false; - int m_texture_type; + rsx::overlays::texture_sampling_mode m_texture_type; areaf m_clip_region; coordf m_viewport; @@ -162,7 +162,9 @@ namespace vk vk::image_view* find_font(rsx::overlays::font* font, vk::command_buffer& cmd, vk::data_heap& upload_heap); vk::image_view* find_temp_image(rsx::overlays::image_info* desc, vk::command_buffer& cmd, vk::data_heap& upload_heap, u32 owner_uid); - void update_uniforms(vk::command_buffer& /*cmd*/, vk::glsl::program* /*program*/) override; + std::vector get_push_constants() override; + + void update_uniforms(vk::command_buffer& cmd, vk::glsl::program* program) override; void set_primitive_type(rsx::overlays::primitive_type type); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 6f063f60d5..24a579a1fc 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -546,6 +546,7 @@ + @@ -865,6 +866,8 @@ + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index c3ffadb229..4511ea73aa 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -2251,6 +2251,9 @@ Emu\GPU\RSX\Overlays + + Emu\GPU\RSX\Program + @@ -2280,5 +2283,11 @@ Emu\GPU\RSX\Program\Snippets + + Emu\GPU\RSX\Program\Snippets + + + Emu\GPU\RSX\Program\Snippets + \ No newline at end of file