summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules')
-rw-r--r--src/osd/modules/render/bgfx/chainmanager.cpp2
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_hq2x.sc75
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq2x/varying.def.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_hq2x.sc36
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_hq3x.sc75
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq3x/varying.def.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_hq3x.sc36
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_hq4x.sc75
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq4x/varying.def.sc9
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_blit.sc14
-rw-r--r--src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_hq4x.sc36
16 files changed, 445 insertions, 1 deletions
diff --git a/src/osd/modules/render/bgfx/chainmanager.cpp b/src/osd/modules/render/bgfx/chainmanager.cpp
index 2c8e08793b0..458a45d449c 100644
--- a/src/osd/modules/render/bgfx/chainmanager.cpp
+++ b/src/osd/modules/render/bgfx/chainmanager.cpp
@@ -245,7 +245,7 @@ void chain_manager::process_screen_quad(uint32_t view, uint32_t screen, render_p
tex_width, tex_height, prim->texture.rowpixels, prim->texture.palette, prim->texture.base);
std::string full_name = "screen" + std::to_string(screen);
- bgfx_texture *texture = new bgfx_texture(full_name, bgfx::TextureFormat::RGBA8, tex_width, tex_height, mem);
+ bgfx_texture *texture = new bgfx_texture(full_name, bgfx::TextureFormat::RGBA8, tex_width, tex_height, mem, BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT | BGFX_TEXTURE_MIP_POINT);
m_textures.add_provider(full_name, texture);
m_targets.update_target_sizes(screen, tex_width, tex_height, TARGET_STYLE_GUEST);
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_blit.sc
new file mode 100644
index 00000000000..9af7bcf0ee6
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_blit.sc
@@ -0,0 +1,14 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+
+void main()
+{
+ gl_FragColor = texture2D(s_tex, v_texcoord0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_hq2x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_hq2x.sc
new file mode 100644
index 00000000000..66bd69f253e
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq2x/fs_hq2x.sc
@@ -0,0 +1,75 @@
+$input v_color0, v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+// Samplers
+SAMPLER2D(decal, 0);
+SAMPLER2D(LUT, 1);
+
+#define trY 48.0
+#define trU 7.0
+#define trV 6.0
+
+#define SCALE 2.0
+
+float diff(vec3 yuv1, vec3 yuv2)
+{
+ vec3 yuv_threshold = vec3(trY / 255.0, trU / 255.0, trV / 255.0);
+ vec3 yuv_offset = vec3(0, 0.5, 0.5);
+ float res_x = (abs((yuv1.x + 0.0) - (yuv2.x + 0.0)) > (trY / 255.0)) ? 1.0 : 0.0;
+ float res_y = (abs((yuv1.y + 0.5) - (yuv2.y + 0.5)) > (trU / 255.0)) ? 1.0 : 0.0;
+ float res_z = (abs((yuv1.z + 0.5) - (yuv2.z + 0.5)) > (trV / 255.0)) ? 1.0 : 0.0;
+ return (res_x > 0.0) ? 1.0 : ((res_y > 0.0) ? 1.0 : ((res_z > 0.0) ? 1.0 : 0.0));
+}
+
+void main()
+{
+ mat3 yuv = mat3(0.299, 0.587, 0.114, -0.169, -0.331, 0.5, 0.5, -0.419, -0.081);
+
+ vec2 fp = fract(v_texcoord0 * u_tex_size0.xy);
+ vec2 quad = sign(-0.5 + fp);
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+
+ float dx = ps.x;
+ float dy = ps.y;
+ vec4 p1 = texture2D(decal, v_texcoord0);
+ vec4 p2 = texture2D(decal, v_texcoord0 + ps * quad);
+ vec4 p3 = texture2D(decal, v_texcoord0 + vec2(dx, 0) * quad);
+ vec4 p4 = texture2D(decal, v_texcoord0 + vec2(0, dy) * quad);
+
+ vec3 w1 = mul(yuv, texture2D(decal, v_texcoord1.xw).rgb);
+ vec3 w2 = mul(yuv, texture2D(decal, v_texcoord1.yw).rgb);
+ vec3 w3 = mul(yuv, texture2D(decal, v_texcoord1.zw).rgb);
+
+ vec3 w4 = mul(yuv, texture2D(decal, v_texcoord2.xw).rgb);
+ vec3 w5 = mul(yuv, p1.rgb);
+ vec3 w6 = mul(yuv, texture2D(decal, v_texcoord2.zw).rgb);
+
+ vec3 w7 = mul(yuv, texture2D(decal, v_texcoord3.xw).rgb);
+ vec3 w8 = mul(yuv, texture2D(decal, v_texcoord3.yw).rgb);
+ vec3 w9 = mul(yuv, texture2D(decal, v_texcoord3.zw).rgb);
+
+ mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
+ vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
+
+ vec2 index;
+ index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
+
+ vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
+ vec2 offset = step / vec2(2.0, 2.0);
+ vec4 weights = texture2D(LUT, index * step + offset);
+ float sum = dot(weights, vec4(1.0, 1.0, 1.0, 1.0));
+ mat4 transposed = mat4(vec4(p1.x, p2.x, p3.x, p4.x), vec4(p1.y, p2.y, p3.y, p4.y), vec4(p1.z, p2.z, p3.z, p4.z), vec4(p1.w, p2.w, p3.w, p4.w));
+ vec4 res = mul(transposed, weights / vec4(sum, sum, sum, sum));
+
+ gl_FragColor = vec4(res.rgb, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq2x/varying.def.sc b/src/osd/modules/render/bgfx/shaders/chains/hq2x/varying.def.sc
new file mode 100644
index 00000000000..57a7a910952
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq2x/varying.def.sc
@@ -0,0 +1,9 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+vec4 v_texcoord1 : TEXCOORD1 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord2 : TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord3 : TEXCOORD3 = vec4(0.0, 0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_blit.sc
new file mode 100644
index 00000000000..405ef8feb3b
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_blit.sc
@@ -0,0 +1,14 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_hq2x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_hq2x.sc
new file mode 100644
index 00000000000..a77ac7006f7
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq2x/vs_hq2x.sc
@@ -0,0 +1,36 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_color0 = a_color0;
+
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+ float dx = ps.x;
+ float dy = ps.y;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ v_texcoord0 = a_texcoord0;
+ v_texcoord1 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, -dy); // w1 | w2 | w3
+ v_texcoord2 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, 0.0); // w4 | w5 | w6
+ v_texcoord3 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, dy); // w7 | w8 | w9
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_blit.sc
new file mode 100644
index 00000000000..9af7bcf0ee6
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_blit.sc
@@ -0,0 +1,14 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+
+void main()
+{
+ gl_FragColor = texture2D(s_tex, v_texcoord0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_hq3x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_hq3x.sc
new file mode 100644
index 00000000000..8e0f46a80f1
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq3x/fs_hq3x.sc
@@ -0,0 +1,75 @@
+$input v_color0, v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+// Samplers
+SAMPLER2D(decal, 0);
+SAMPLER2D(LUT, 1);
+
+#define trY 48.0
+#define trU 7.0
+#define trV 6.0
+
+#define SCALE 3.0
+
+float diff(vec3 yuv1, vec3 yuv2)
+{
+ vec3 yuv_threshold = vec3(trY / 255.0, trU / 255.0, trV / 255.0);
+ vec3 yuv_offset = vec3(0, 0.5, 0.5);
+ float res_x = (abs((yuv1.x + 0.0) - (yuv2.x + 0.0)) > (trY / 255.0)) ? 1.0 : 0.0;
+ float res_y = (abs((yuv1.y + 0.5) - (yuv2.y + 0.5)) > (trU / 255.0)) ? 1.0 : 0.0;
+ float res_z = (abs((yuv1.z + 0.5) - (yuv2.z + 0.5)) > (trV / 255.0)) ? 1.0 : 0.0;
+ return (res_x > 0.0) ? 1.0 : ((res_y > 0.0) ? 1.0 : ((res_z > 0.0) ? 1.0 : 0.0));
+}
+
+void main()
+{
+ mat3 yuv = mat3(0.299, 0.587, 0.114, -0.169, -0.331, 0.5, 0.5, -0.419, -0.081);
+
+ vec2 fp = fract(v_texcoord0 * u_tex_size0.xy);
+ vec2 quad = sign(-0.5 + fp);
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+
+ float dx = ps.x;
+ float dy = ps.y;
+ vec4 p1 = texture2D(decal, v_texcoord0);
+ vec4 p2 = texture2D(decal, v_texcoord0 + ps * quad);
+ vec4 p3 = texture2D(decal, v_texcoord0 + vec2(dx, 0) * quad);
+ vec4 p4 = texture2D(decal, v_texcoord0 + vec2(0, dy) * quad);
+
+ vec3 w1 = mul(yuv, texture2D(decal, v_texcoord1.xw).rgb);
+ vec3 w2 = mul(yuv, texture2D(decal, v_texcoord1.yw).rgb);
+ vec3 w3 = mul(yuv, texture2D(decal, v_texcoord1.zw).rgb);
+
+ vec3 w4 = mul(yuv, texture2D(decal, v_texcoord2.xw).rgb);
+ vec3 w5 = mul(yuv, p1.rgb);
+ vec3 w6 = mul(yuv, texture2D(decal, v_texcoord2.zw).rgb);
+
+ vec3 w7 = mul(yuv, texture2D(decal, v_texcoord3.xw).rgb);
+ vec3 w8 = mul(yuv, texture2D(decal, v_texcoord3.yw).rgb);
+ vec3 w9 = mul(yuv, texture2D(decal, v_texcoord3.zw).rgb);
+
+ mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
+ vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
+
+ vec2 index;
+ index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
+
+ vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
+ vec2 offset = step / vec2(2.0, 2.0);
+ vec4 weights = texture2D(LUT, index * step + offset);
+ float sum = dot(weights, vec4(1.0, 1.0, 1.0, 1.0));
+ mat4 transposed = mat4(vec4(p1.x, p2.x, p3.x, p4.x), vec4(p1.y, p2.y, p3.y, p4.y), vec4(p1.z, p2.z, p3.z, p4.z), vec4(p1.w, p2.w, p3.w, p4.w));
+ vec4 res = mul(transposed, weights / vec4(sum, sum, sum, sum));
+
+ gl_FragColor = vec4(res.rgb, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq3x/varying.def.sc b/src/osd/modules/render/bgfx/shaders/chains/hq3x/varying.def.sc
new file mode 100644
index 00000000000..57a7a910952
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq3x/varying.def.sc
@@ -0,0 +1,9 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+vec4 v_texcoord1 : TEXCOORD1 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord2 : TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord3 : TEXCOORD3 = vec4(0.0, 0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_blit.sc
new file mode 100644
index 00000000000..405ef8feb3b
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_blit.sc
@@ -0,0 +1,14 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_hq3x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_hq3x.sc
new file mode 100644
index 00000000000..a77ac7006f7
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq3x/vs_hq3x.sc
@@ -0,0 +1,36 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_color0 = a_color0;
+
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+ float dx = ps.x;
+ float dy = ps.y;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ v_texcoord0 = a_texcoord0;
+ v_texcoord1 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, -dy); // w1 | w2 | w3
+ v_texcoord2 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, 0.0); // w4 | w5 | w6
+ v_texcoord3 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, dy); // w7 | w8 | w9
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_blit.sc
new file mode 100644
index 00000000000..9af7bcf0ee6
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_blit.sc
@@ -0,0 +1,14 @@
+$input v_color0, v_texcoord0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+// Samplers
+SAMPLER2D(s_tex, 0);
+
+void main()
+{
+ gl_FragColor = texture2D(s_tex, v_texcoord0) * v_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_hq4x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_hq4x.sc
new file mode 100644
index 00000000000..8e769bee46c
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq4x/fs_hq4x.sc
@@ -0,0 +1,75 @@
+$input v_color0, v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+// Samplers
+SAMPLER2D(decal, 0);
+SAMPLER2D(LUT, 1);
+
+#define trY 48.0
+#define trU 7.0
+#define trV 6.0
+
+#define SCALE 4.0
+
+float diff(vec3 yuv1, vec3 yuv2)
+{
+ vec3 yuv_threshold = vec3(trY / 255.0, trU / 255.0, trV / 255.0);
+ vec3 yuv_offset = vec3(0, 0.5, 0.5);
+ float res_x = (abs((yuv1.x + 0.0) - (yuv2.x + 0.0)) > (trY / 255.0)) ? 1.0 : 0.0;
+ float res_y = (abs((yuv1.y + 0.5) - (yuv2.y + 0.5)) > (trU / 255.0)) ? 1.0 : 0.0;
+ float res_z = (abs((yuv1.z + 0.5) - (yuv2.z + 0.5)) > (trV / 255.0)) ? 1.0 : 0.0;
+ return (res_x > 0.0) ? 1.0 : ((res_y > 0.0) ? 1.0 : ((res_z > 0.0) ? 1.0 : 0.0));
+}
+
+void main()
+{
+ mat3 yuv = mat3(0.299, 0.587, 0.114, -0.169, -0.331, 0.5, 0.5, -0.419, -0.081);
+
+ vec2 fp = fract(v_texcoord0 * u_tex_size0.xy);
+ vec2 quad = sign(-0.5 + fp);
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+
+ float dx = ps.x;
+ float dy = ps.y;
+ vec4 p1 = texture2D(decal, v_texcoord0);
+ vec4 p2 = texture2D(decal, v_texcoord0 + ps * quad);
+ vec4 p3 = texture2D(decal, v_texcoord0 + vec2(dx, 0) * quad);
+ vec4 p4 = texture2D(decal, v_texcoord0 + vec2(0, dy) * quad);
+
+ vec3 w1 = mul(yuv, texture2D(decal, v_texcoord1.xw).rgb);
+ vec3 w2 = mul(yuv, texture2D(decal, v_texcoord1.yw).rgb);
+ vec3 w3 = mul(yuv, texture2D(decal, v_texcoord1.zw).rgb);
+
+ vec3 w4 = mul(yuv, texture2D(decal, v_texcoord2.xw).rgb);
+ vec3 w5 = mul(yuv, p1.rgb);
+ vec3 w6 = mul(yuv, texture2D(decal, v_texcoord2.zw).rgb);
+
+ vec3 w7 = mul(yuv, texture2D(decal, v_texcoord3.xw).rgb);
+ vec3 w8 = mul(yuv, texture2D(decal, v_texcoord3.yw).rgb);
+ vec3 w9 = mul(yuv, texture2D(decal, v_texcoord3.zw).rgb);
+
+ mat3 pattern = mat3(diff(w5, w1), diff(w5, w2), diff(w5, w3), diff(w5, w4), 0.0, diff(w5, w6), diff(w5, w7), diff(w5, w8), diff(w5, w9));
+ vec4 cross = vec4(diff(w4, w2), diff(w2, w6), diff(w8, w4), diff(w6, w8));
+
+ vec2 index;
+ index.x = dot(pattern[0], vec3( 1.0, 2.0, 4.0)) +
+ dot(pattern[1], vec3( 8.0, 0.0, 16.0)) +
+ dot(pattern[2], vec3(32.0, 64.0, 128.0));
+ index.y = dot(cross, vec4(1.0, 2.0, 4.0, 8.0)) * SCALE * SCALE + dot(floor(fp * vec2(SCALE, SCALE)), vec2(1.0, SCALE));
+
+ vec2 step = vec2(1.0, 1.0) / vec2(256.0, 16.0 * (SCALE * SCALE));
+ vec2 offset = step / vec2(2.0, 2.0);
+ vec4 weights = texture2D(LUT, index * step + offset);
+ float sum = dot(weights, vec4(1.0, 1.0, 1.0, 1.0));
+ mat4 transposed = mat4(vec4(p1.x, p2.x, p3.x, p4.x), vec4(p1.y, p2.y, p3.y, p4.y), vec4(p1.z, p2.z, p3.z, p4.z), vec4(p1.w, p2.w, p3.w, p4.w));
+ vec4 res = mul(transposed, weights / vec4(sum, sum, sum, sum));
+
+ gl_FragColor = vec4(res.rgb, 1.0);
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq4x/varying.def.sc b/src/osd/modules/render/bgfx/shaders/chains/hq4x/varying.def.sc
new file mode 100644
index 00000000000..57a7a910952
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq4x/varying.def.sc
@@ -0,0 +1,9 @@
+vec4 v_color0 : COLOR0 = vec4(1.0, 0.0, 0.0, 1.0);
+vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
+vec4 v_texcoord1 : TEXCOORD1 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord2 : TEXCOORD2 = vec4(0.0, 0.0, 0.0, 0.0);
+vec4 v_texcoord3 : TEXCOORD3 = vec4(0.0, 0.0, 0.0, 0.0);
+
+vec3 a_position : POSITION;
+vec4 a_color0 : COLOR0;
+vec2 a_texcoord0 : TEXCOORD0;
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_blit.sc b/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_blit.sc
new file mode 100644
index 00000000000..405ef8feb3b
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_blit.sc
@@ -0,0 +1,14 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_color0
+
+// license:BSD-3-Clause
+// copyright-holders:Dario Manesku
+
+#include "common.sh"
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_texcoord0 = a_texcoord0;
+ v_color0 = a_color0;
+}
diff --git a/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_hq4x.sc b/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_hq4x.sc
new file mode 100644
index 00000000000..a77ac7006f7
--- /dev/null
+++ b/src/osd/modules/render/bgfx/shaders/chains/hq4x/vs_hq4x.sc
@@ -0,0 +1,36 @@
+$input a_position, a_texcoord0, a_color0
+$output v_texcoord0, v_texcoord1, v_texcoord2, v_texcoord3, v_color0
+
+// license:LGPL-2.1+
+// copyright-holders:Jules Blok,Cameron Zemek,Maxim Stepin
+
+#include "common.sh"
+
+// Autos
+uniform vec4 u_tex_size0;
+
+void main()
+{
+ gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));
+ v_color0 = a_color0;
+
+ vec2 ps = vec2(1.0, 1.0) / u_tex_size0.xy;
+ float dx = ps.x;
+ float dy = ps.y;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ v_texcoord0 = a_texcoord0;
+ v_texcoord1 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, -dy); // w1 | w2 | w3
+ v_texcoord2 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, 0.0); // w4 | w5 | w6
+ v_texcoord3 = a_texcoord0.xxxy + vec4(-dx, 0.0, dx, dy); // w7 | w8 | w9
+}