From 799aa9e4d567db0874111d2aed9c9b9058a19641 Mon Sep 17 00:00:00 2001 From: hunterk Date: Sun, 5 Mar 2023 19:06:04 -0600 Subject: [PATCH] Update NTSC-Adaptive (#184) * remove float framebuffer flag from ntsc-adaptive * pack float framebuffer values * unpack float values * fix typo * reduce packing range * reduce packing range * bring ntsc-adaptive up-to-date with slang version --- ntsc/ntsc-adaptive.glslp | 1 + ntsc/shaders/ntsc-adaptive/ntsc-pass1.glsl | 101 +++++++++++++++++--- ntsc/shaders/ntsc-adaptive/ntsc-pass2.glsl | 103 ++++++++++++++++++--- 3 files changed, 180 insertions(+), 25 deletions(-) diff --git a/ntsc/ntsc-adaptive.glslp b/ntsc/ntsc-adaptive.glslp index bc3bcab..f98f0d3 100644 --- a/ntsc/ntsc-adaptive.glslp +++ b/ntsc/ntsc-adaptive.glslp @@ -12,3 +12,4 @@ scale_type1 = source scale_x1 = 0.5 scale_y1 = 1.0 filter_linear1 = false +wrap_mode1 = mirrored_repeat diff --git a/ntsc/shaders/ntsc-adaptive/ntsc-pass1.glsl b/ntsc/shaders/ntsc-adaptive/ntsc-pass1.glsl index e3ffdbc..0e2254a 100644 --- a/ntsc/shaders/ntsc-adaptive/ntsc-pass1.glsl +++ b/ntsc/shaders/ntsc-adaptive/ntsc-pass1.glsl @@ -3,8 +3,16 @@ // NTSC-Adaptive // based on Themaister's NTSC shader -#pragma parameter quality "Quality (Composite = 0, Svideo = 1)" 0.0 0.0 1.0 1.0 -#pragma parameter bw "Black and White" 0.0 0.0 1.0 1.0 +#pragma parameter quality "NTSC Preset (Svideo=0 Composite=1 RF=2 Custom=-1)" 1.0 -1.0 2.0 1.0 +#pragma parameter ntsc_fields "NTSC Merge Fields" 0.0 0.0 1.0 1.0 +#pragma parameter ntsc_phase "NTSC Phase: Auto | 2 phase | 3 phase" 1.0 1.0 3.0 1.0 +#pragma parameter ntsc_scale "NTSC Resolution Scaling" 1.0 0.20 3.0 0.05 +#pragma parameter ntsc_sat "NTSC Color Saturation" 1.0 0.0 2.0 0.01 +#pragma parameter ntsc_bright "NTSC Brightness" 1.0 0.0 1.5 0.01 +#pragma parameter cust_fringing "NTSC Custom Fringing Value" 0.0 0.0 5.0 0.1 +#pragma parameter cust_artifacting "NTSC Custom Artifacting Value" 0.0 0.0 5.0 0.1 + +#define PI 3.14159265 #if defined(VERTEX) @@ -28,6 +36,13 @@ COMPAT_ATTRIBUTE vec4 VertexCoord; COMPAT_ATTRIBUTE vec4 TexCoord; COMPAT_VARYING vec4 TEX0; COMPAT_VARYING vec2 pix_no; +COMPAT_VARYING float phase; +COMPAT_VARYING float BRIGHTNESS; +COMPAT_VARYING float SATURATION; +COMPAT_VARYING float FRINGING; +COMPAT_VARYING float ARTIFACTING; +COMPAT_VARYING float CHROMA_MOD_FREQ; +COMPAT_VARYING float MERGE; uniform mat4 MVPMatrix; uniform COMPAT_PRECISION int FrameDirection; @@ -35,17 +50,47 @@ uniform COMPAT_PRECISION int FrameCount; uniform COMPAT_PRECISION vec2 OutputSize; uniform COMPAT_PRECISION vec2 TextureSize; uniform COMPAT_PRECISION vec2 InputSize; +uniform COMPAT_PRECISION vec2 OrigInputSize; // compatibility #defines #define vTexCoord TEX0.xy #define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize #define OutSize vec4(OutputSize, 1.0 / OutputSize) +#ifdef PARAMETER_UNIFORM +uniform COMPAT_PRECISION float quality, ntsc_sat, cust_fringing, cust_artifacting, ntsc_bright, ntsc_scale, ntsc_fields, ntsc_phase; +#else +#define ntsc_fields 0.0 +#define ntsc_phase 1.0 +#define ntsc_sat 1.0 +#define ntsc_bright 1.0 +#define cust_fringing 0.0 +#define cust_artifacting 0.0 +#define quality 0.0 +#endif + void main() { + float res = ntsc_scale; + float OriginalSize = OrigInputSize.x; gl_Position = MVPMatrix * VertexCoord; TEX0.xy = TexCoord.xy; + if (res < 1.0) pix_no = vTexCoord * SourceSize.xy * (res * OutSize.xy / InputSize.xy); + else + pix_no = vTexCoord * SourceSize.xy * ( OutSize.xy / InputSize.xy); pix_no = vTexCoord * SourceSize.xy * (OutSize.xy / InputSize.xy); + phase = (ntsc_phase < 1.5) ? ((OriginalSize > 300.0) ? 2.0 : 3.0) : ((ntsc_phase > 2.5) ? 3.0 : 2.0); + + res = max(res, 1.0); + CHROMA_MOD_FREQ = (phase < 2.5) ? (4.0 * PI / 15.0) : (PI / 3.0); + ARTIFACTING = (quality > -0.5) ? quality * 0.5*(res+1.0) : cust_artifacting; + FRINGING = (quality > -0.5) ? quality : cust_fringing; + SATURATION = ntsc_sat; + BRIGHTNESS = ntsc_bright; + pix_no.x = pix_no.x * res; + + MERGE = (int(quality) == 2 || phase < 2.5) ? 0.0 : 1.0; + MERGE = (int(quality) == -1) ? ntsc_fields : MERGE; } #elif defined(FRAGMENT) @@ -80,6 +125,13 @@ uniform COMPAT_PRECISION vec2 OrigInputSize; uniform sampler2D Texture; COMPAT_VARYING vec4 TEX0; COMPAT_VARYING vec2 pix_no; +COMPAT_VARYING float phase; +COMPAT_VARYING float BRIGHTNESS; +COMPAT_VARYING float SATURATION; +COMPAT_VARYING float FRINGING; +COMPAT_VARYING float ARTIFACTING; +COMPAT_VARYING float CHROMA_MOD_FREQ; +COMPAT_VARYING float MERGE; // compatibility #defines #define Source Texture @@ -89,16 +141,18 @@ COMPAT_VARYING vec2 pix_no; #define OutSize vec4(OutputSize, 1.0 / OutputSize) #ifdef PARAMETER_UNIFORM -uniform COMPAT_PRECISION float quality; -uniform COMPAT_PRECISION float bw; +uniform COMPAT_PRECISION float quality, ntsc_sat, cust_fringing, cust_artifacting, ntsc_bright, ntsc_scale, ntsc_fields, ntsc_phase; #else +#define ntsc_fields 0.0 +#define ntsc_phase 1.0 +#define ntsc_sat 1.0 +#define ntsc_bright 1.0 +#define cust_fringing 0.0 +#define cust_artifacting 0.0 #define quality 0.0 -#define bw 0.0 #endif #define PI 3.14159265 -float phase = (OrigInputSize.x > 300.0) ? 2.0 : 3.0; - #define mix_mat mat3(BRIGHTNESS, FRINGING, FRINGING, ARTIFACTING, 2.0 * SATURATION, 0.0, ARTIFACTING, 0.0, 2.0 * SATURATION) @@ -123,19 +177,32 @@ vec3 rgb2yiq(vec3 col) return col * yiq_mat; } +vec4 pack_float(vec4 color) +{ + return ((color * 10.0) - 1.0); +} + void main() { - float CHROMA_MOD_FREQ = (phase < 2.5) ? (4.0 * PI / 15.0) : (PI / 3.0); - float ARTIFACTING = 1.0 - quality; - float FRINGING = 1.0 - quality; - float SATURATION = 1.0 - bw; - // prevent some very slight clipping that happens at 1.0 - const float BRIGHTNESS = 0.95; vec3 col = COMPAT_TEXTURE(Source, vTexCoord).rgb; vec3 yiq = rgb2yiq(col); + vec3 yiq2 = yiq; - float chroma_phase = (phase < 2.5) ? PI * (mod(pix_no.y, 2.0) + mod(float(FrameCount), 2.)) : 0.6667 * PI * (mod(pix_no.y, 3.0) + mod(float(FrameCount), 2.)); + float mod1 = 2.0; + float mod2 = 3.0; +if (MERGE > 0.5) +{ + float chroma_phase2 = (phase < 2.5) ? PI * (mod(pix_no.y, mod1) + mod(FrameCount+1, 2.)) : 0.6667 * PI * (mod(pix_no.y, mod2) + mod(FrameCount+1, 2.)); + float mod_phase2 = chroma_phase2 + pix_no.x * CHROMA_MOD_FREQ; + float i_mod2 = cos(mod_phase2); + float q_mod2 = sin(mod_phase2); + yiq2.yz *= vec2(i_mod2, q_mod2); // Modulate. + yiq2 *= mix_mat; // Cross-talk. + yiq2.yz *= vec2(i_mod2, q_mod2); // Demodulate. +} + + float chroma_phase = (phase < 2.5) ? PI * (mod(pix_no.y, mod1) + mod(FrameCount, 2.)) : 0.6667 * PI * (mod(pix_no.y, mod2) + mod(FrameCount, 2.)); float mod_phase = chroma_phase + pix_no.x * CHROMA_MOD_FREQ; float i_mod = cos(mod_phase); @@ -144,6 +211,12 @@ void main() yiq.yz *= vec2(i_mod, q_mod); // Modulate. yiq *= mix_mat; // Cross-talk. yiq.yz *= vec2(i_mod, q_mod); // Demodulate. + + yiq = (MERGE < 0.5) ? yiq : 0.5*(yiq+yiq2); + FragColor = vec4(yiq, 1.0); +#ifdef GL_ES + FragColor = pack_float(FragColor); +#endif } #endif diff --git a/ntsc/shaders/ntsc-adaptive/ntsc-pass2.glsl b/ntsc/shaders/ntsc-adaptive/ntsc-pass2.glsl index fa5545c..359e1ac 100644 --- a/ntsc/shaders/ntsc-adaptive/ntsc-pass2.glsl +++ b/ntsc/shaders/ntsc-adaptive/ntsc-pass2.glsl @@ -5,8 +5,13 @@ #pragma parameter linearize "Linearize Output Gamma" 0.0 0.0 1.0 1.0 +#ifdef GL_ES +#define fetch_offset(offset, one_x) \ + unpack_float(COMPAT_TEXTURE(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz) +#else #define fetch_offset(offset, one_x) \ COMPAT_TEXTURE(Source, vTexCoord + vec2((offset) * (one_x), 0.0)).xyz +#endif #if defined(VERTEX) @@ -88,11 +93,18 @@ COMPAT_VARYING vec4 TEX0; #define OutSize vec4(OutputSize, 1.0 / OutputSize) #ifdef PARAMETER_UNIFORM -uniform COMPAT_PRECISION float linearize; +uniform COMPAT_PRECISION float linearize, ntsc_scale, ntsc_phase; #else #define linearize 0.0 +#define ntsc_scale 1.0 +#define ntsc_phase 1.0 #endif +vec3 unpack_float(vec3 color) +{ + return (color + 1.0) / 10.0; +} + const mat3 yiq2rgb_mat = mat3( 1.0, 0.956, 0.6210, 1.0, -0.2720, -0.6474, @@ -242,22 +254,86 @@ const float chroma_filter_3_phase[25] = float[25]( void main() { - float phase = (OrigInputSize.x > 300.0) ? 2.0 : 3.0; - float one_x = SourceSize.z; + float res = ntsc_scale; + float OriginalSize = OrigInputSize.x; + float phase = (ntsc_phase < 1.5) ? ((OriginalSize > 300.0) ? 2.0 : 3.0) : ((ntsc_phase > 2.5) ? 3.0 : 2.0); + float one_x = SourceSize.z / res; vec3 signal = vec3(0.0); if(phase < 2.5) { - for (int i = 0; i < TAPS_2_phase; i++) - { - float offset = float(i); + vec3 sums = fetch_offset(0.0 - 32.0, one_x) + fetch_offset(32.0 - 0.0, one_x); + signal += sums * vec3(luma_filter_2_phase[0], chroma_filter_2_phase[0], chroma_filter_2_phase[0]); + sums = fetch_offset(1.0 - 32.0, one_x) + fetch_offset(32.0 - 1.0, one_x); + signal += sums * vec3(luma_filter_2_phase[1], chroma_filter_2_phase[1], chroma_filter_2_phase[1]); + sums = fetch_offset(2.0 - 32.0, one_x) + fetch_offset(32.0 - 2.0, one_x); + signal += sums * vec3(luma_filter_2_phase[2], chroma_filter_2_phase[2], chroma_filter_2_phase[2]); + sums = fetch_offset(3.0 - 32.0, one_x) + fetch_offset(32.0 - 3.0, one_x); + signal += sums * vec3(luma_filter_2_phase[3], chroma_filter_2_phase[3], chroma_filter_2_phase[3]); + sums = fetch_offset(4.0 - 32.0, one_x) + fetch_offset(32.0 - 4.0, one_x); + signal += sums * vec3(luma_filter_2_phase[4], chroma_filter_2_phase[4], chroma_filter_2_phase[4]); + sums = fetch_offset(5.0 - 32.0, one_x) + fetch_offset(32.0 - 5.0, one_x); + signal += sums * vec3(luma_filter_2_phase[5], chroma_filter_2_phase[5], chroma_filter_2_phase[5]); + sums = fetch_offset(6.0 - 32.0, one_x) + fetch_offset(32.0 - 6.0, one_x); + signal += sums * vec3(luma_filter_2_phase[6], chroma_filter_2_phase[6], chroma_filter_2_phase[6]); + sums = fetch_offset(7.0 - 32.0, one_x) + fetch_offset(32.0 - 7.0, one_x); + signal += sums * vec3(luma_filter_2_phase[7], chroma_filter_2_phase[7], chroma_filter_2_phase[7]); + sums = fetch_offset(8.0 - 32.0, one_x) + fetch_offset(32.0 - 8.0, one_x); + signal += sums * vec3(luma_filter_2_phase[8], chroma_filter_2_phase[8], chroma_filter_2_phase[8]); + sums = fetch_offset(9.0 - 32.0, one_x) + fetch_offset(32.0 - 9.0, one_x); + signal += sums * vec3(luma_filter_2_phase[9], chroma_filter_2_phase[9], chroma_filter_2_phase[9]); + sums = fetch_offset(10.0 - 32.0, one_x) + fetch_offset(32.0 - 10.0, one_x); + signal += sums * vec3(luma_filter_2_phase[10], chroma_filter_2_phase[10], chroma_filter_2_phase[10]); + sums = fetch_offset(11.0 - 32.0, one_x) + fetch_offset(32.0 - 11.0, one_x); + signal += sums * vec3(luma_filter_2_phase[11], chroma_filter_2_phase[11], chroma_filter_2_phase[11]); + sums = fetch_offset(12.0 - 32.0, one_x) + fetch_offset(32.0 - 12.0, one_x); + signal += sums * vec3(luma_filter_2_phase[12], chroma_filter_2_phase[12], chroma_filter_2_phase[12]); + sums = fetch_offset(13.0 - 32.0, one_x) + fetch_offset(32.0 - 13.0, one_x); + signal += sums * vec3(luma_filter_2_phase[13], chroma_filter_2_phase[13], chroma_filter_2_phase[13]); + sums = fetch_offset(14.0 - 32.0, one_x) + fetch_offset(32.0 - 14.0, one_x); + signal += sums * vec3(luma_filter_2_phase[14], chroma_filter_2_phase[14], chroma_filter_2_phase[14]); + sums = fetch_offset(15.0 - 32.0, one_x) + fetch_offset(32.0 - 15.0, one_x); + signal += sums * vec3(luma_filter_2_phase[15], chroma_filter_2_phase[15], chroma_filter_2_phase[15]); + sums = fetch_offset(16.0 - 32.0, one_x) + fetch_offset(32.0 - 16.0, one_x); + signal += sums * vec3(luma_filter_2_phase[16], chroma_filter_2_phase[16], chroma_filter_2_phase[16]); + sums = fetch_offset(17.0 - 32.0, one_x) + fetch_offset(32.0 - 17.0, one_x); + signal += sums * vec3(luma_filter_2_phase[17], chroma_filter_2_phase[17], chroma_filter_2_phase[17]); + sums = fetch_offset(18.0 - 32.0, one_x) + fetch_offset(32.0 - 18.0, one_x); + signal += sums * vec3(luma_filter_2_phase[18], chroma_filter_2_phase[18], chroma_filter_2_phase[18]); + sums = fetch_offset(19.0 - 32.0, one_x) + fetch_offset(32.0 - 19.0, one_x); + signal += sums * vec3(luma_filter_2_phase[19], chroma_filter_2_phase[19], chroma_filter_2_phase[19]); + sums = fetch_offset(20.0 - 32.0, one_x) + fetch_offset(32.0 - 20.0, one_x); + signal += sums * vec3(luma_filter_2_phase[20], chroma_filter_2_phase[20], chroma_filter_2_phase[20]); + sums = fetch_offset(21.0 - 32.0, one_x) + fetch_offset(32.0 - 21.0, one_x); + signal += sums * vec3(luma_filter_2_phase[21], chroma_filter_2_phase[21], chroma_filter_2_phase[21]); + sums = fetch_offset(22.0 - 32.0, one_x) + fetch_offset(32.0 - 22.0, one_x); + signal += sums * vec3(luma_filter_2_phase[22], chroma_filter_2_phase[22], chroma_filter_2_phase[22]); + sums = fetch_offset(23.0 - 32.0, one_x) + fetch_offset(32.0 - 23.0, one_x); + signal += sums * vec3(luma_filter_2_phase[23], chroma_filter_2_phase[23], chroma_filter_2_phase[23]); + sums = fetch_offset(24.0 - 32.0, one_x) + fetch_offset(32.0 - 24.0, one_x); + signal += sums * vec3(luma_filter_2_phase[24], chroma_filter_2_phase[24], chroma_filter_2_phase[24]); + sums = fetch_offset(25.0 - 32.0, one_x) + fetch_offset(32.0 - 25.0, one_x); + signal += sums * vec3(luma_filter_2_phase[25], chroma_filter_2_phase[25], chroma_filter_2_phase[25]); + sums = fetch_offset(26.0 - 32.0, one_x) + fetch_offset(32.0 - 26.0, one_x); + signal += sums * vec3(luma_filter_2_phase[26], chroma_filter_2_phase[26], chroma_filter_2_phase[26]); + sums = fetch_offset(27.0 - 32.0, one_x) + fetch_offset(32.0 - 27.0, one_x); + signal += sums * vec3(luma_filter_2_phase[27], chroma_filter_2_phase[27], chroma_filter_2_phase[27]); + sums = fetch_offset(28.0 - 32.0, one_x) + fetch_offset(32.0 - 28.0, one_x); + signal += sums * vec3(luma_filter_2_phase[28], chroma_filter_2_phase[28], chroma_filter_2_phase[28]); + sums = fetch_offset(29.0 - 32.0, one_x) + fetch_offset(32.0 - 29.0, one_x); + signal += sums * vec3(luma_filter_2_phase[29], chroma_filter_2_phase[29], chroma_filter_2_phase[29]); + sums = fetch_offset(30.0 - 32.0, one_x) + fetch_offset(32.0 - 30.0, one_x); + signal += sums * vec3(luma_filter_2_phase[30], chroma_filter_2_phase[30], chroma_filter_2_phase[30]); + sums = fetch_offset(31.0 - 32.0, one_x) + fetch_offset(32.0 - 31.0, one_x); + signal += sums * vec3(luma_filter_2_phase[31], chroma_filter_2_phase[31], chroma_filter_2_phase[31]); - vec3 sums = fetch_offset(offset - float(TAPS_2_phase), one_x) + - fetch_offset(float(TAPS_2_phase) - offset, one_x); - signal += sums * vec3(luma_filter_2_phase[i], chroma_filter_2_phase[i], chroma_filter_2_phase[i]); - } +#ifdef GL_ES + signal += unpack_float(COMPAT_TEXTURE(Source, vTexCoord).xyz) * + vec3(luma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase]); +#else signal += COMPAT_TEXTURE(Source, vTexCoord).xyz * vec3(luma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase]); +#endif } else if(phase > 2.5) { @@ -269,10 +345,15 @@ void main() fetch_offset(float(TAPS_3_phase) - offset, one_x); signal += sums * vec3(luma_filter_3_phase[i], chroma_filter_3_phase[i], chroma_filter_3_phase[i]); } +#ifdef GL_ES + signal += unpack_float(COMPAT_TEXTURE(Source, vTexCoord).xyz) * + vec3(luma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase]); + } +#else signal += COMPAT_TEXTURE(Source, vTexCoord).xyz * vec3(luma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase]); } - +#endif vec3 rgb = yiq2rgb(signal); FragColor = vec4(rgb, 1.0); if(linearize < 0.5) return;