diff --git a/rpcs3/Emu/RSX/GL/GLOverlays.h b/rpcs3/Emu/RSX/GL/GLOverlays.h index 70490d317841..ae8185067fed 100644 --- a/rpcs3/Emu/RSX/GL/GLOverlays.h +++ b/rpcs3/Emu/RSX/GL/GLOverlays.h @@ -18,6 +18,7 @@ namespace gl gl::glsl::shader fs; gl::fbo fbo; + gl::sampler_state m_sampler; gl::vao m_vao; gl::buffer m_vertex_data_buffer; @@ -26,6 +27,29 @@ namespace gl u32 num_drawable_elements = 4; GLenum primitives = GL_TRIANGLE_STRIP; + GLenum input_filter = GL_NEAREST; + + struct saved_sampler_state + { + GLuint saved = GL_NONE; + GLuint unit = 0; + + saved_sampler_state(GLuint _unit, const gl::sampler_state& sampler) + { + glActiveTexture(GL_TEXTURE0 + _unit); + glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&saved); + + unit = _unit; + sampler.bind(_unit); + } + + saved_sampler_state(const saved_sampler_state&) = delete; + + ~saved_sampler_state() + { + glBindSampler(unit, saved); + } + }; void create() { @@ -46,6 +70,9 @@ namespace gl fbo.create(); + m_sampler.create(); + m_sampler.apply_defaults(input_filter); + m_vertex_data_buffer.create(); int old_vao; @@ -76,6 +103,8 @@ namespace gl m_vao.remove(); m_vertex_data_buffer.remove(); + m_sampler.remove(); + compiled = false; } } @@ -283,7 +312,7 @@ namespace gl program_handle.uniforms["tex_scale"] = color2f(src_ratio_x, src_ratio_y); - glActiveTexture(GL_TEXTURE31); + saved_sampler_state saved(31, m_sampler); glBindTexture(GL_TEXTURE_2D, source->id()); overlay_pass::run(dst_area.x2, dst_area.y2, target->id(), true); @@ -322,7 +351,7 @@ namespace gl void run(u16 w, u16 h, GLuint target, GLuint source) { - glActiveTexture(GL_TEXTURE31); + saved_sampler_state saved(31, m_sampler); glBindTexture(GL_TEXTURE_2D, source); overlay_pass::run(w, h, target, false); @@ -346,19 +375,26 @@ namespace gl "#version 420\n\n" "layout(location=0) in vec4 in_pos;\n" "layout(location=0) out vec2 tc0;\n" - "layout(location=1) out vec4 clip_rect;\n" + "layout(location=1) flat out vec4 clip_rect;\n" "uniform vec4 ui_scale;\n" "uniform vec2 viewport;\n" "uniform vec4 clip_bounds;\n" "\n" + "vec2 snap_to_grid(vec2 normalized)\n" + "{\n" + " return (floor(normalized * viewport) + 0.5) / viewport;\n" + "}\n" + "\n" "void main()\n" "{\n" " tc0.xy = in_pos.zw;\n" " clip_rect = clip_bounds;\n" " clip_rect.yw = ui_scale.yy - clip_rect.wy; // Invert y axis\n" " clip_rect *= (ui_scale.zwzw * viewport.xyxy) / ui_scale.xyxy; // Normalize and convert to window coords\n" - " vec4 pos = vec4((in_pos.xy * ui_scale.zw) / ui_scale.xy, 0., 1.);\n" - " pos.y = (1. - pos.y); //invert y axis\n" + " vec2 window_coord = (in_pos.xy * ui_scale.zw) / ui_scale.xy;\n" + " window_coord = snap_to_grid(window_coord); // Half-integer offset\n" + " window_coord.y = (1. - window_coord.y); // Invert y axis\n" + " vec4 pos = vec4(window_coord, 0., 1.);\n" " gl_Position = (pos + pos) - 1.;\n" "}\n" }; @@ -368,7 +404,7 @@ namespace gl "#version 420\n\n" "layout(binding=31) uniform sampler2D fs0;\n" "layout(location=0) in vec2 tc0;\n" - "layout(location=1) in vec4 clip_rect;\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" @@ -448,6 +484,9 @@ namespace gl " ocol = diff_color;\n" "}\n" }; + + // Smooth filtering required for inputs + input_filter = GL_LINEAR; } gl::texture_view* load_simple_image(rsx::overlays::image_info* desc, bool temp_resource, u32 owner_uid) @@ -586,6 +625,9 @@ namespace gl program_handle.uniforms["viewport"] = color2f(f32(w), f32(h)); program_handle.uniforms["ui_scale"] = color4f((f32)ui.virtual_width, (f32)ui.virtual_height, 1.f, 1.f); program_handle.uniforms["time"] = (f32)(get_system_time() / 1000) * 0.005f; + + saved_sampler_state saved(31, m_sampler); + for (auto &cmd : ui.get_compiled().draw_commands) { upload_vertex_data((f32*)cmd.verts.data(), (u32)cmd.verts.size() * 4u); @@ -593,7 +635,6 @@ namespace gl is_font_draw = false; GLint texture_exists = GL_TRUE; - glActiveTexture(GL_TEXTURE31); switch (cmd.config.texture_ref) { case rsx::overlays::image_resource_id::game_icon: @@ -679,6 +720,8 @@ namespace gl " ocol = color;\n" "}\n" }; + + input_filter = GL_LINEAR; } void run(u16 w, u16 h, GLuint source, const areai& region, f32 gamma, bool limited_rgb) @@ -695,7 +738,7 @@ namespace gl program_handle.uniforms["gamma"] = gamma; program_handle.uniforms["limit_range"] = (int)limited_rgb; - glActiveTexture(GL_TEXTURE31); + saved_sampler_state saved(31, m_sampler); glBindTexture(GL_TEXTURE_2D, source); overlay_pass::run(w, h, GL_NONE, false, false); } diff --git a/rpcs3/Emu/RSX/GL/GLTexture.cpp b/rpcs3/Emu/RSX/GL/GLTexture.cpp index f87eb1c6b84b..2dc011c80b68 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.cpp +++ b/rpcs3/Emu/RSX/GL/GLTexture.cpp @@ -290,13 +290,13 @@ namespace gl glSamplerParameteri(samplerHandle, GL_TEXTURE_COMPARE_MODE, GL_NONE); } - void sampler_state::apply_defaults() + void sampler_state::apply_defaults(GLenum default_filter) { glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_S, GL_REPEAT); glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_T, GL_REPEAT); glSamplerParameteri(samplerHandle, GL_TEXTURE_WRAP_R, GL_REPEAT); - glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_FILTER, default_filter); + glSamplerParameteri(samplerHandle, GL_TEXTURE_MAG_FILTER, default_filter); glSamplerParameterf(samplerHandle, GL_TEXTURE_LOD_BIAS, 0.f); glSamplerParameteri(samplerHandle, GL_TEXTURE_MIN_LOD, 0); glSamplerParameteri(samplerHandle, GL_TEXTURE_MAX_LOD, 0); diff --git a/rpcs3/Emu/RSX/GL/GLTexture.h b/rpcs3/Emu/RSX/GL/GLTexture.h index 99f36a44bdd1..1d49af865aad 100644 --- a/rpcs3/Emu/RSX/GL/GLTexture.h +++ b/rpcs3/Emu/RSX/GL/GLTexture.h @@ -49,7 +49,7 @@ namespace gl glDeleteSamplers(1, &samplerHandle); } - void bind(int index) + void bind(int index) const { glBindSampler(index, samplerHandle); } @@ -57,6 +57,6 @@ namespace gl void apply(const rsx::fragment_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); void apply(const rsx::vertex_texture& tex, const rsx::sampled_image_descriptor_base* sampled_image); - void apply_defaults(); + void apply_defaults(GLenum default_filter = GL_NEAREST); }; } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 1b4f06b464eb..a456eed7ff27 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -248,7 +248,7 @@ namespace rsx return{}; stbtt_aligned_quad quad; - stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, true); + stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, false); return quad; } diff --git a/rpcs3/Emu/RSX/VK/VKOverlays.h b/rpcs3/Emu/RSX/VK/VKOverlays.h index 3189985842b9..8432543d8582 100644 --- a/rpcs3/Emu/RSX/VK/VKOverlays.h +++ b/rpcs3/Emu/RSX/VK/VKOverlays.h @@ -494,6 +494,11 @@ namespace vk "layout(location=3) out vec4 clip_rect;\n" "layout(location=4) out vec4 parameters2;\n" "\n" + "vec2 snap_to_grid(vec2 normalized)\n" + "{\n" + " return (floor(normalized * regs[5].xy) + 0.5) / regs[5].xy;\n" + "}\n" + "\n" "void main()\n" "{\n" " tc0.xy = in_pos.zw;\n" @@ -503,6 +508,7 @@ namespace vk " clip_rect = (regs[3] * regs[0].zwzw) / regs[0].xyxy; // Normalized coords\n" " clip_rect *= regs[5].xyxy; // Window coords\n" " vec4 pos = vec4((in_pos.xy * regs[0].zw) / regs[0].xy, 0.5, 1.);\n" + " pos.xy = snap_to_grid(pos.xy);\n" " gl_Position = (pos + pos) - 1.;\n" "}\n" };