Added parameters to all modified files.

Fixed a bug (introduced when porting to slang) related
to crt-hyllian and the PHOSPHOR feature.
This commit is contained in:
Arzed Five 2016-08-03 06:24:41 +01:00
parent 69ab6da976
commit 6a31c2dec5
9 changed files with 437 additions and 321 deletions

View file

@ -1,8 +1,4 @@
#version 450 #version 450
/* COMPATIBILITY
- HLSL compilers
- Cg compilers
*/
/* /*
cgwg's CRT shader cgwg's CRT shader
@ -25,6 +21,13 @@
) )
*/ */
layout(push_constant) uniform Push
{
float CRTCGWG_GAMMA;
} param;
#pragma parameter CRTCGWG_GAMMA "CRTcgwg Gamma" 2.7 0.0 10.0 0.01
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -55,11 +58,11 @@ layout(location = 10) out vec2 ratio_scale;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord;
vec2 delta = 1.0 / global.SourceSize.xy; vec2 delta = global.SourceSize.zw;
float dx = delta.x; float dx = delta.x;
float dy = delta.y; float dy = delta.y;
c01 = vTexCoord + vec2(-dx, 0.0); c01 = vTexCoord + vec2(-dx, 0.0);
c11 = vTexCoord + vec2(0.0, 0.0); c11 = vTexCoord + vec2(0.0, 0.0);
@ -88,9 +91,6 @@ layout(location = 10) in vec2 ratio_scale;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
/* Config */
#define CRTCGWG_GAMMA 2.7
#define TEX2D(c) texture(Source ,(c)) #define TEX2D(c) texture(Source ,(c))
#define PI 3.141592653589 #define PI 3.141592653589
@ -115,8 +115,8 @@ void main()
vec3 wid = 2.0 * pow(col, vec3(4.0, 4.0, 4.0)) + 2.0; vec3 wid = 2.0 * pow(col, vec3(4.0, 4.0, 4.0)) + 2.0;
vec3 wid2 = 2.0 * pow(col2, vec3(4.0, 4.0, 4.0)) + 2.0; vec3 wid2 = 2.0 * pow(col2, vec3(4.0, 4.0, 4.0)) + 2.0;
col = pow(col, vec3(CRTCGWG_GAMMA, CRTCGWG_GAMMA, CRTCGWG_GAMMA)); col = pow(col, vec3(param.CRTCGWG_GAMMA));
col2 = pow(col2, vec3(CRTCGWG_GAMMA, CRTCGWG_GAMMA, CRTCGWG_GAMMA)); col2 = pow(col2, vec3(param.CRTCGWG_GAMMA));
vec3 sqrt1 = inversesqrt(0.5 * wid); vec3 sqrt1 = inversesqrt(0.5 * wid);
vec3 sqrt2 = inversesqrt(0.5 * wid2); vec3 sqrt2 = inversesqrt(0.5 * wid2);

View file

@ -1,11 +1,50 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float BRIGHT_BOOST;
float DILATION;
float GAMMA_INPUT;
float GAMMA_OUTPUT;
float MASK_SIZE;
float MASK_STAGGER;
float MASK_STRENGTH;
float MASK_DOT_HEIGHT;
float MASK_DOT_WIDTH;
float SCANLINE_CUTOFF;
float SCANLINE_BEAM_WIDTH_MAX;
float SCANLINE_BEAM_WIDTH_MIN;
float SCANLINE_BRIGHT_MAX;
float SCANLINE_BRIGHT_MIN;
float SCANLINE_STRENGTH;
float SHARPNESS_H;
float SHARPNESS_V;
} param;
#pragma parameter SHARPNESS_H "Sharpness Horizontal" 0.5 0.0 1.0 0.05
#pragma parameter SHARPNESS_V "Sharpness Vertical" 1.0 0.0 1.0 0.05
#pragma parameter MASK_STRENGTH "Mask Strength" 0.3 0.0 1.0 0.01
#pragma parameter MASK_DOT_WIDTH "Mask Dot Width" 1.0 1.0 100.0 1.0
#pragma parameter MASK_DOT_HEIGHT "Mask Dot Height" 1.0 1.0 100.0 1.0
#pragma parameter MASK_STAGGER "Mask Stagger" 0.0 0.0 100.0 1.0
#pragma parameter MASK_SIZE "Mask Size" 1.0 1.0 100.0 1.0
#pragma parameter SCANLINE_STRENGTH "Scanline Strength" 1.0 0.0 1.0 0.05
#pragma parameter SCANLINE_BEAM_WIDTH_MIN "Scanline Beam Width Min." 1.5 0.5 5.0 0.5
#pragma parameter SCANLINE_BEAM_WIDTH_MAX "Scanline Beam Width Max." 1.5 0.5 5.0 0.5
#pragma parameter SCANLINE_BRIGHT_MIN "Scanline Brightness Min." 0.35 0.0 1.0 0.05
#pragma parameter SCANLINE_BRIGHT_MAX "Scanline Brightness Max." 0.65 0.0 1.0 0.05
#pragma parameter SCANLINE_CUTOFF "Scanline Cutoff" 400.0 1.0 1000.0 1.0
#pragma parameter GAMMA_INPUT "Gamma Input" 2.0 0.1 5.0 0.1
#pragma parameter GAMMA_OUTPUT "Gamma Output" 1.8 0.1 5.0 0.1
#pragma parameter BRIGHT_BOOST "Brightness Boost" 1.2 1.0 2.0 0.01
#pragma parameter DILATION "Dilation" 1.0 0.0 1.0 1.0
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
vec4 OutputSize; vec4 OutputSize;
vec4 OriginalSize; vec4 OriginalSize;
vec4 SourceSize; vec4 SourceSize;
} global; } global;
#pragma stage vertex #pragma stage vertex
@ -15,8 +54,8 @@ layout(location = 0) out vec2 vTexCoord;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord;
} }
/* /*
@ -53,24 +92,6 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define SHARPNESS_H 0.5
#define SHARPNESS_V 1.0
#define MASK_STRENGTH 0.3
#define MASK_DOT_WIDTH 1.0
#define MASK_DOT_HEIGHT 1.0
#define MASK_STAGGER 0.0
#define MASK_SIZE 1.0
#define SCANLINE_STRENGTH 1.0
#define SCANLINE_BEAM_WIDTH_MIN 1.5
#define SCANLINE_BEAM_WIDTH_MAX 1.5
#define SCANLINE_BRIGHT_MIN 0.35
#define SCANLINE_BRIGHT_MAX 0.65
#define SCANLINE_CUTOFF 400.0
#define GAMMA_INPUT 2.0
#define GAMMA_OUTPUT 1.8
#define BRIGHT_BOOST 1.2
#define DILATION 1.0
#define FIX(c) max(abs(c), 1e-5) #define FIX(c) max(abs(c), 1e-5)
#define PI 3.141592653589 #define PI 3.141592653589
@ -81,7 +102,7 @@ layout(set = 0, binding = 2) uniform sampler2D Source;
vec4 dilate(vec4 col) vec4 dilate(vec4 col)
{ {
vec4 x = mix(vec4(1.0), col, DILATION); vec4 x = mix(vec4(1.0), col, param.DILATION);
return col * x; return col * x;
} }
@ -129,7 +150,7 @@ void main()
vec3 col, col2; vec3 col, col2;
#if ENABLE_LANCZOS #if ENABLE_LANCZOS
curve_x = curve_distance(dist.x, SHARPNESS_H * SHARPNESS_H); curve_x = curve_distance(dist.x, param.SHARPNESS_H * param.SHARPNESS_H);
vec4 coeffs = PI * vec4(1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x); vec4 coeffs = PI * vec4(1.0 + curve_x, curve_x, 1.0 - curve_x, 2.0 - curve_x);
@ -140,38 +161,38 @@ void main()
col = filter_lanczos(coeffs, get_color_matrix(tex_co, dx)); col = filter_lanczos(coeffs, get_color_matrix(tex_co, dx));
col2 = filter_lanczos(coeffs, get_color_matrix(tex_co + dy, dx)); col2 = filter_lanczos(coeffs, get_color_matrix(tex_co + dy, dx));
#else #else
curve_x = curve_distance(dist.x, SHARPNESS_H); curve_x = curve_distance(dist.x, param.SHARPNESS_H);
col = mix(TEX2D(tex_co).rgb, TEX2D(tex_co + dx).rgb, curve_x); col = mix(TEX2D(tex_co).rgb, TEX2D(tex_co + dx).rgb, curve_x);
col2 = mix(TEX2D(tex_co + dy).rgb, TEX2D(tex_co + dx + dy).rgb, curve_x); col2 = mix(TEX2D(tex_co + dy).rgb, TEX2D(tex_co + dx + dy).rgb, curve_x);
#endif #endif
col = mix(col, col2, curve_distance(dist.y, SHARPNESS_V)); col = mix(col, col2, curve_distance(dist.y, param.SHARPNESS_V));
col = pow(col, vec3(GAMMA_INPUT / (DILATION + 1.0))); col = pow(col, vec3(param.GAMMA_INPUT / (param.DILATION + 1.0)));
float luma = dot(vec3(0.2126, 0.7152, 0.0722), col); float luma = dot(vec3(0.2126, 0.7152, 0.0722), col);
float bright = (max(col.r, max(col.g, col.b)) + luma) * 0.5; float bright = (max(col.r, max(col.g, col.b)) + luma) * 0.5;
float scan_bright = clamp(bright, SCANLINE_BRIGHT_MIN, SCANLINE_BRIGHT_MAX); float scan_bright = clamp(bright, param.SCANLINE_BRIGHT_MIN, param.SCANLINE_BRIGHT_MAX);
float scan_beam = clamp(bright * SCANLINE_BEAM_WIDTH_MAX, SCANLINE_BEAM_WIDTH_MIN, SCANLINE_BEAM_WIDTH_MAX); float scan_beam = clamp(bright * param.SCANLINE_BEAM_WIDTH_MAX, param.SCANLINE_BEAM_WIDTH_MIN, param.SCANLINE_BEAM_WIDTH_MAX);
float scan_weight = 1.0 - pow(cos(vTexCoord.y * 2.0 * PI * global.SourceSize.y) * 0.5 + 0.5, scan_beam) * SCANLINE_STRENGTH; float scan_weight = 1.0 - pow(cos(vTexCoord.y * 2.0 * PI * global.SourceSize.y) * 0.5 + 0.5, scan_beam) * param.SCANLINE_STRENGTH;
float mask = 1.0 - MASK_STRENGTH; float mask = 1.0 - param.MASK_STRENGTH;
vec2 mod_fac = floor(vTexCoord * global.OutputSize.xy * global.SourceSize.xy / (global.SourceSize.xy * vec2(MASK_SIZE, MASK_DOT_HEIGHT * MASK_SIZE))); vec2 mod_fac = floor(vTexCoord * global.OutputSize.xy * global.SourceSize.xy / (global.SourceSize.xy * vec2(param.MASK_SIZE, param.MASK_DOT_HEIGHT * param.MASK_SIZE)));
int dot_no = int(mod((mod_fac.x + mod(mod_fac.y, 2.0) * MASK_STAGGER) / MASK_DOT_WIDTH, 3.0)); int dot_no = int(mod((mod_fac.x + mod(mod_fac.y, 2.0) * param.MASK_STAGGER) / param.MASK_DOT_WIDTH, 3.0));
vec3 mask_weight; vec3 mask_weight;
if (dot_no == 0) mask_weight = vec3(1.0, mask, mask); if (dot_no == 0) mask_weight = vec3(1.0, mask, mask);
else if (dot_no == 1) mask_weight = vec3(mask, 1.0, mask); else if (dot_no == 1) mask_weight = vec3(mask, 1.0, mask);
else mask_weight = vec3(mask, mask, 1.0); else mask_weight = vec3(mask, mask, 1.0);
if (global.SourceSize.y >= SCANLINE_CUTOFF) if (global.SourceSize.y >= param.SCANLINE_CUTOFF)
scan_weight = 1.0; scan_weight = 1.0;
col2 = col.rgb; col2 = col.rgb;
col *= vec3(scan_weight); col *= vec3(scan_weight);
col = mix(col, col2, scan_bright); col = mix(col, col2, scan_bright);
col *= mask_weight; col *= mask_weight;
col = pow(col, vec3(1.0 / GAMMA_OUTPUT)); col = pow(col, vec3(1.0 / param.GAMMA_OUTPUT));
FragColor = vec4(col * BRIGHT_BOOST, 1.0); FragColor = vec4(col * param.BRIGHT_BOOST, 1.0);
} }

View file

@ -1,5 +1,36 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float PHOSPHOR;
float VSCANLINES;
float InputGamma;
float OutputGamma;
float SHARPNESS;
float COLOR_BOOST;
float RED_BOOST;
float GREEN_BOOST;
float BLUE_BOOST;
float SCANLINES_STRENGTH;
float BEAM_MIN_WIDTH;
float BEAM_MAX_WIDTH;
float CRT_ANTI_RINGING;
} param;
#pragma parameter PHOSPHOR "CRT - Phosphor ON/OFF" 1.0 0.0 1.0 1.0
#pragma parameter VSCANLINES "CRT - Scanlines Direction" 0.0 0.0 1.0 1.0
#pragma parameter InputGamma "CRT - Input gamma" 2.5 0.0 5.0 0.1
#pragma parameter OutputGamma "CRT - Output Gamma" 2.2 0.0 5.0 0.1
#pragma parameter SHARPNESS "CRT - Sharpness Hack" 1.0 1.0 5.0 1.0
#pragma parameter COLOR_BOOST "CRT - Color Boost" 1.5 1.0 2.0 0.05
#pragma parameter RED_BOOST "CRT - Red Boost" 1.0 1.0 2.0 0.01
#pragma parameter GREEN_BOOST "CRT - Green Boost" 1.0 1.0 2.0 0.01
#pragma parameter BLUE_BOOST "CRT - Blue Boost" 1.0 1.0 2.0 0.01
#pragma parameter SCANLINES_STRENGTH "CRT - Scanline Strength" 0.50 0.0 1.0 0.02
#pragma parameter BEAM_MIN_WIDTH "CRT - Min Beam Width" 0.86 0.0 1.0 0.02
#pragma parameter BEAM_MAX_WIDTH "CRT - Max Beam Width" 1.0 0.0 1.0 0.02
#pragma parameter CRT_ANTI_RINGING "CRT - Anti-Ringing" 0.8 0.0 1.0 0.1
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -12,65 +43,45 @@ layout(std140, set = 0, binding = 0) uniform UBO
layout(location = 0) in vec4 Position; layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord; layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord; layout(location = 0) out vec2 vTexCoord;
layout(location = 2) out float frame_count;
layout(location = 3) out float frame_direction;
layout(location = 4) out float frame_rotation;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord;
} }
#pragma stage fragment #pragma stage fragment
layout(location = 0) in vec2 vTexCoord; layout(location = 0) in vec2 vTexCoord;
layout(location = 1) in vec2 FragCoord; layout(location = 1) in vec2 FragCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(location = 2) in float frame_count;
layout(location = 3) in float frame_direction;
layout(location = 4) in float frame_rotation;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define PHOSPHOR 1.0
#define VSCANLINES 0.0
#define InputGamma 2.5
#define OutputGamma 2.2
#define SHARPNESS 1.0
#define COLOR_BOOST 1.5
#define RED_BOOST 1.0
#define GREEN_BOOST 1.0
#define BLUE_BOOST 1.0
#define SCANLINES_STRENGTH 0.50
#define BEAM_MIN_WIDTH 0.86
#define BEAM_MAX_WIDTH 1.0
#define CRT_ANTI_RINGING 0.8
/* /*
Hyllian's CRT Shader Hyllian's CRT Shader
Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com Copyright (C) 2011-2016 Hyllian - sergiogdb@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
#define GAMMA_IN(color) pow(color, vec3(InputGamma, InputGamma, InputGamma)) #define GAMMA_IN(color) pow(color, vec3(param.InputGamma, param.InputGamma, param.InputGamma))
#define GAMMA_OUT(color) pow(color, vec3(1.0 / OutputGamma, 1.0 / OutputGamma, 1.0 / OutputGamma)) #define GAMMA_OUT(color) pow(color, vec3(1.0 / param.OutputGamma, 1.0 / param.OutputGamma, 1.0 / param.OutputGamma))
// Horizontal cubic filter. // Horizontal cubic filter.
@ -103,16 +114,16 @@ void main()
{ {
vec3 color; vec3 color;
vec2 TextureSize = vec2(SHARPNESS*global.SourceSize.x, global.SourceSize.y); vec2 TextureSize = vec2(param.SHARPNESS*global.SourceSize.x, global.SourceSize.y);
vec2 dx = mix(vec2(1.0/TextureSize.x, 0.0), vec2(0.0, 1.0/TextureSize.y), VSCANLINES); vec2 dx = mix(vec2(1.0/TextureSize.x, 0.0), vec2(0.0, 1.0/TextureSize.y), param.VSCANLINES);
vec2 dy = mix(vec2(0.0, 1.0/TextureSize.y), vec2(1.0/TextureSize.x, 0.0), VSCANLINES); vec2 dy = mix(vec2(0.0, 1.0/TextureSize.y), vec2(1.0/TextureSize.x, 0.0), param.VSCANLINES);
vec2 pix_coord = vTexCoord*TextureSize + vec2(-0.5, 0.5); vec2 pix_coord = vTexCoord*TextureSize + vec2(-0.5, 0.5);
vec2 tc = mix((floor(pix_coord) + vec2(0.5, 0.5))/TextureSize, (floor(pix_coord) + vec2(1.0, -0.5))/TextureSize, VSCANLINES); vec2 tc = mix((floor(pix_coord) + vec2(0.5, 0.5))/TextureSize, (floor(pix_coord) + vec2(1.0, -0.5))/TextureSize, param.VSCANLINES);
vec2 fp = mix(fract(pix_coord), fract(pix_coord.yx), VSCANLINES); vec2 fp = mix(fract(pix_coord), fract(pix_coord.yx), param.VSCANLINES);
vec3 c00 = GAMMA_IN(texture(Source, tc - dx - dy).xyz); vec3 c00 = GAMMA_IN(texture(Source, tc - dx - dy).xyz);
vec3 c01 = GAMMA_IN(texture(Source, tc - dy).xyz); vec3 c01 = GAMMA_IN(texture(Source, tc - dy).xyz);
@ -137,36 +148,36 @@ void main()
// Anti-ringing // Anti-ringing
vec3 aux = color0; vec3 aux = color0;
color0 = clamp(color0, min_sample, max_sample); color0 = clamp(color0, min_sample, max_sample);
color0 = mix(aux, color0, CRT_ANTI_RINGING); color0 = mix(aux, color0, param.CRT_ANTI_RINGING);
aux = color1; aux = color1;
color1 = clamp(color1, min_sample, max_sample); color1 = clamp(color1, min_sample, max_sample);
color1 = mix(aux, color1, CRT_ANTI_RINGING); color1 = mix(aux, color1, param.CRT_ANTI_RINGING);
float pos0 = fp.y; float pos0 = fp.y;
float pos1 = 1 - fp.y; float pos1 = 1 - fp.y;
vec3 lum0 = mix(vec3(BEAM_MIN_WIDTH), vec3(BEAM_MAX_WIDTH), color0); vec3 lum0 = mix(vec3(param.BEAM_MIN_WIDTH), vec3(param.BEAM_MAX_WIDTH), color0);
vec3 lum1 = mix(vec3(BEAM_MIN_WIDTH), vec3(BEAM_MAX_WIDTH), color1); vec3 lum1 = mix(vec3(param.BEAM_MIN_WIDTH), vec3(param.BEAM_MAX_WIDTH), color1);
vec3 d0 = clamp(pos0/(lum0 + 0.0000001), 0.0, 1.0); vec3 d0 = clamp(pos0/(lum0 + 0.0000001), 0.0, 1.0);
vec3 d1 = clamp(pos1/(lum1 + 0.0000001), 0.0, 1.0); vec3 d1 = clamp(pos1/(lum1 + 0.0000001), 0.0, 1.0);
d0 = exp(-10.0*SCANLINES_STRENGTH*d0*d0); d0 = exp(-10.0*param.SCANLINES_STRENGTH*d0*d0);
d1 = exp(-10.0*SCANLINES_STRENGTH*d1*d1); d1 = exp(-10.0*param.SCANLINES_STRENGTH*d1*d1);
color = clamp(color0*d0 + color1*d1, 0.0, 1.0); color = clamp(color0*d0 + color1*d1, 0.0, 1.0);
color *= COLOR_BOOST*vec3(RED_BOOST, GREEN_BOOST, BLUE_BOOST); color *= param.COLOR_BOOST*vec3(param.RED_BOOST, param.GREEN_BOOST, param.BLUE_BOOST);
float mod_factor = mix(vTexCoord.x * global.OutputSize.x * global.SourceSize.x, vTexCoord.y * global.OutputSize.y * global.SourceSize.y, VSCANLINES); float mod_factor = mix(vTexCoord.x * global.OutputSize.x, vTexCoord.y * global.OutputSize.y, param.VSCANLINES);
vec3 dotMaskWeights = mix( vec3 dotMaskWeights = mix(
vec3(1.0, 0.7, 1.0), vec3(1.0, 0.7, 1.0),
vec3(0.7, 1.0, 0.7), vec3(0.7, 1.0, 0.7),
floor(mod(mod_factor, 2.0)) /* Possible bug - Does mod() behave like fmod() ? */ floor(mod(mod_factor, 2.0))
); );
color.rgb *= mix(vec3(1.0, 1.0, 1.0), dotMaskWeights, PHOSPHOR); color.rgb *= mix(vec3(1.0), dotMaskWeights, param.PHOSPHOR);
color = GAMMA_OUT(color); color = GAMMA_OUT(color);

View file

@ -1,5 +1,36 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float hardScan;
float hardPix;
float warpX;
float warpY;
float maskDark;
float maskLight;
float scaleInLinearGamma;
float shadowMask;
float brightBoost;
float hardBloomScan;
float hardBloomPix;
float bloomAmount;
float shape;
} param;
#pragma parameter hardScan "hardScan" -8.0 -20.0 0.0 1.0
#pragma parameter hardPix "hardPix" -3.0 -20.0 0.0 1.0
#pragma parameter warpX "warpX" 0.031 0.0 0.125 0.01
#pragma parameter warpY "warpY" 0.041 0.0 0.125 0.01
#pragma parameter maskDark "maskDark" 0.5 0.0 2.0 0.1
#pragma parameter maskLight "maskLight" 1.5 0.0 2.0 0.1
#pragma parameter scaleInLinearGamma "scaleInLinearGamma" 1.0 0.0 1.0 1.0
#pragma parameter shadowMask "shadowMask" 3.0 0.0 4.0 1.0
#pragma parameter brightBoost "brightness boost" 1.0 0.0 2.0 0.05
#pragma parameter hardBloomPix "bloom-x soft" -1.5 -2.0 -0.5 0.1
#pragma parameter hardBloomScan "bloom-y soft" -2.0 -4.0 -1.0 0.1
#pragma parameter bloomAmount "bloom ammount" 0.15 0.0 1.0 0.05
#pragma parameter shape "filter kernel shape" 2.0 0.0 10.0 0.05
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -15,8 +46,8 @@ layout(location = 0) out vec2 vTexCoord;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord;
} }
// PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER // PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER
@ -38,22 +69,6 @@ layout(location = 1) in vec2 FragCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
// -- config -- //
#define hardScan -8.0
#define hardPix -3.0
#define warpX 0.031
#define warpY 0.041
#define maskDark 0.5
#define maskLight 1.5
#define scaleInLinearGamma 1
#define shadowMask 1
#define brightboost 1
#define hardBloomScan -2.0
#define hardBloomPix -1.5
#define bloomAmount 1.0/16.0
#define shape 2.0
//Uncomment to reduce instructions with simpler linearization //Uncomment to reduce instructions with simpler linearization
//(fixes HD3000 Sandy Bridge IGP) //(fixes HD3000 Sandy Bridge IGP)
//#define SIMPLE_LINEAR_GAMMA //#define SIMPLE_LINEAR_GAMMA
@ -66,41 +81,49 @@ layout(set = 0, binding = 2) uniform sampler2D Source;
#ifdef SIMPLE_LINEAR_GAMMA #ifdef SIMPLE_LINEAR_GAMMA
float ToLinear1(float c) float ToLinear1(float c)
{ {
return c; return c;
} }
float3 ToLinear(vec3 c) vec3 ToLinear(vec3 c)
{ {
return c; return c;
} }
vec3 ToSrgb(vec3 c) vec3 ToSrgb(vec3 c)
{ {
return pow(c, 1.0 / 2.2); return pow(c, 1.0 / 2.2);
} }
#else #else
float ToLinear1(float c) float ToLinear1(float c)
{ {
if (scaleInLinearGamma==0) return c; if (param.scaleInLinearGamma == 0)
return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4); return c;
return(c<=0.04045) ? c/12.92 : pow((c + 0.055)/1.055, 2.4);
} }
vec3 ToLinear(vec3 c) vec3 ToLinear(vec3 c)
{ {
if (scaleInLinearGamma==0) return c; if (param.scaleInLinearGamma==0)
return vec3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b)); return c;
return vec3(ToLinear1(c.r), ToLinear1(c.g), ToLinear1(c.b));
} }
// Linear to sRGB. // Linear to sRGB.
// Assuming using sRGB typed textures this should not be needed. // Assuming using sRGB typed textures this should not be needed.
float ToSrgb1(float c) float ToSrgb1(float c)
{ {
if (scaleInLinearGamma==0) return c; if (param.scaleInLinearGamma == 0)
return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055); return c;
return(c<0.0031308 ? c*12.92 : 1.055*pow(c, 0.41666) - 0.055);
} }
vec3 ToSrgb(vec3 c) vec3 ToSrgb(vec3 c)
{ {
if (scaleInLinearGamma==0) return c; if (param.scaleInLinearGamma == 0)
return vec3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b)); return c;
return vec3(ToSrgb1(c.r), ToSrgb1(c.g), ToSrgb1(c.b));
} }
#endif #endif
@ -111,177 +134,224 @@ vec3 ToSrgb(vec3 c)
vec3 Fetch(vec2 pos,vec2 off){ vec3 Fetch(vec2 pos,vec2 off){
pos=(floor(pos*global.SourceSize.xy+off)+vec2(0.5,0.5))/global.SourceSize.xy; pos=(floor(pos*global.SourceSize.xy+off)+vec2(0.5,0.5))/global.SourceSize.xy;
#ifdef SIMPLE_LINEAR_GAMMA #ifdef SIMPLE_LINEAR_GAMMA
return ToLinear(brightboost * pow(texture(Source,pos.xy).rgb, 2.2)); return ToLinear(param.brightBoost * pow(texture(Source,pos.xy).rgb, 2.2));
#else #else
return ToLinear(brightboost * texture(Source,pos.xy).rgb);} return ToLinear(param.brightBoost * texture(Source,pos.xy).rgb);}
#endif #endif
// Distance in emulated pixels to nearest texel. // Distance in emulated pixels to nearest texel.
vec2 Dist(vec2 pos){pos=pos*global.SourceSize.xy;return -((pos-floor(pos))-vec2(0.5));} vec2 Dist(vec2 pos)
{
pos = pos*global.SourceSize.xy;
return -((pos - floor(pos)) - vec2(0.5));
}
// 1D Gaussian. // 1D Gaussian.
float Gaus(float pos,float scale){return exp2(scale*pow(abs(pos),shape));} float Gaus(float pos, float scale)
{
return exp2(scale*pow(abs(pos), param.shape));
}
// 3-tap Gaussian filter along horz line. // 3-tap Gaussian filter along horz line.
vec3 Horz3(vec2 pos,float off){ vec3 Horz3(vec2 pos, float off)
vec3 b=Fetch(pos,vec2(-1.0,off)); {
vec3 c=Fetch(pos,vec2( 0.0,off)); vec3 b = Fetch(pos, vec2(-1.0, off));
vec3 d=Fetch(pos,vec2( 1.0,off)); vec3 c = Fetch(pos, vec2( 0.0, off));
float dst=Dist(pos).x; vec3 d = Fetch(pos, vec2( 1.0, off));
// Convert distance to weight. float dst = Dist(pos).x;
float scale=hardPix;
float wb=Gaus(dst-1.0,scale); // Convert distance to weight.
float wc=Gaus(dst+0.0,scale); float scale = param.hardPix;
float wd=Gaus(dst+1.0,scale); float wb = Gaus(dst-1.0,scale);
// Return filtered sample. float wc = Gaus(dst+0.0,scale);
return (b*wb+c*wc+d*wd)/(wb+wc+wd);} float wd = Gaus(dst+1.0,scale);
// Return filtered sample.
return (b*wb+c*wc+d*wd)/(wb+wc+wd);
}
// 5-tap Gaussian filter along horz line. // 5-tap Gaussian filter along horz line.
vec3 Horz5(vec2 pos,float off){ vec3 Horz5(vec2 pos,float off){
vec3 a=Fetch(pos,vec2(-2.0,off)); vec3 a = Fetch(pos,vec2(-2.0, off));
vec3 b=Fetch(pos,vec2(-1.0,off)); vec3 b = Fetch(pos,vec2(-1.0, off));
vec3 c=Fetch(pos,vec2( 0.0,off)); vec3 c = Fetch(pos,vec2( 0.0, off));
vec3 d=Fetch(pos,vec2( 1.0,off)); vec3 d = Fetch(pos,vec2( 1.0, off));
vec3 e=Fetch(pos,vec2( 2.0,off)); vec3 e = Fetch(pos,vec2( 2.0, off));
float dst=Dist(pos).x;
// Convert distance to weight. float dst = Dist(pos).x;
float scale=hardPix; // Convert distance to weight.
float wa=Gaus(dst-2.0,scale); float scale = param.hardPix;
float wb=Gaus(dst-1.0,scale); float wa = Gaus(dst - 2.0, scale);
float wc=Gaus(dst+0.0,scale); float wb = Gaus(dst - 1.0, scale);
float wd=Gaus(dst+1.0,scale); float wc = Gaus(dst + 0.0, scale);
float we=Gaus(dst+2.0,scale); float wd = Gaus(dst + 1.0, scale);
// Return filtered sample. float we = Gaus(dst + 2.0, scale);
return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);}
// Return filtered sample.
return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we);
}
// 7-tap Gaussian filter along horz line. // 7-tap Gaussian filter along horz line.
vec3 Horz7(vec2 pos,float off){ vec3 Horz7(vec2 pos,float off)
vec3 a=Fetch(pos,vec2(-3.0,off)); {
vec3 b=Fetch(pos,vec2(-2.0,off)); vec3 a = Fetch(pos, vec2(-3.0, off));
vec3 c=Fetch(pos,vec2(-1.0,off)); vec3 b = Fetch(pos, vec2(-2.0, off));
vec3 d=Fetch(pos,vec2( 0.0,off)); vec3 c = Fetch(pos, vec2(-1.0, off));
vec3 e=Fetch(pos,vec2( 1.0,off)); vec3 d = Fetch(pos, vec2( 0.0, off));
vec3 f=Fetch(pos,vec2( 2.0,off)); vec3 e = Fetch(pos, vec2( 1.0, off));
vec3 g=Fetch(pos,vec2( 3.0,off)); vec3 f = Fetch(pos, vec2( 2.0, off));
float dst=Dist(pos).x; vec3 g = Fetch(pos, vec2( 3.0, off));
// Convert distance to weight.
float scale=hardBloomPix; float dst = Dist(pos).x;
float wa=Gaus(dst-3.0,scale); // Convert distance to weight.
float wb=Gaus(dst-2.0,scale); float scale = param.hardBloomPix;
float wc=Gaus(dst-1.0,scale); float wa = Gaus(dst - 3.0, scale);
float wd=Gaus(dst+0.0,scale); float wb = Gaus(dst - 2.0, scale);
float we=Gaus(dst+1.0,scale); float wc = Gaus(dst - 1.0, scale);
float wf=Gaus(dst+2.0,scale); float wd = Gaus(dst + 0.0, scale);
float wg=Gaus(dst+3.0,scale); float we = Gaus(dst + 1.0, scale);
// Return filtered sample. float wf = Gaus(dst + 2.0, scale);
return (a*wa+b*wb+c*wc+d*wd+e*we+f*wf+g*wg)/(wa+wb+wc+wd+we+wf+wg);} float wg = Gaus(dst + 3.0, scale);
// Return filtered sample.
return (a*wa+b*wb+c*wc+d*wd+e*we+f*wf+g*wg)/(wa+wb+wc+wd+we+wf+wg);
}
// Return scanline weight. // Return scanline weight.
float Scan(vec2 pos,float off){ float Scan(vec2 pos, float off)
float dst=Dist(pos).y; {
return Gaus(dst+off,hardScan);} float dst = Dist(pos).y;
return Gaus(dst + off, param.hardScan);
}
// Return scanline weight for bloom. // Return scanline weight for bloom.
float BloomScan(vec2 pos,float off){ float BloomScan(vec2 pos, float off)
float dst=Dist(pos).y; {
return Gaus(dst+off,hardBloomScan);} float dst = Dist(pos).y;
return Gaus(dst + off, param.hardBloomScan);
}
// Allow nearest three lines to effect pixel. // Allow nearest three lines to effect pixel.
vec3 Tri(vec2 pos){ vec3 Tri(vec2 pos)
vec3 a=Horz3(pos,-1.0); {
vec3 b=Horz5(pos, 0.0); vec3 a = Horz3(pos,-1.0);
vec3 c=Horz3(pos, 1.0); vec3 b = Horz5(pos, 0.0);
float wa=Scan(pos,-1.0); vec3 c = Horz3(pos, 1.0);
float wb=Scan(pos, 0.0);
float wc=Scan(pos, 1.0); float wa = Scan(pos,-1.0);
return a*wa+b*wb+c*wc;} float wb = Scan(pos, 0.0);
float wc = Scan(pos, 1.0);
return a*wa + b*wb + c*wc;
}
// Small bloom. // Small bloom.
vec3 Bloom(vec2 pos){ vec3 Bloom(vec2 pos)
vec3 a=Horz5(pos,-2.0); {
vec3 b=Horz7(pos,-1.0); vec3 a = Horz5(pos,-2.0);
vec3 c=Horz7(pos, 0.0); vec3 b = Horz7(pos,-1.0);
vec3 d=Horz7(pos, 1.0); vec3 c = Horz7(pos, 0.0);
vec3 e=Horz5(pos, 2.0); vec3 d = Horz7(pos, 1.0);
float wa=BloomScan(pos,-2.0); vec3 e = Horz5(pos, 2.0);
float wb=BloomScan(pos,-1.0);
float wc=BloomScan(pos, 0.0); float wa = BloomScan(pos,-2.0);
float wd=BloomScan(pos, 1.0); float wb = BloomScan(pos,-1.0);
float we=BloomScan(pos, 2.0); float wc = BloomScan(pos, 0.0);
return a*wa+b*wb+c*wc+d*wd+e*we;} float wd = BloomScan(pos, 1.0);
float we = BloomScan(pos, 2.0);
return a*wa+b*wb+c*wc+d*wd+e*we;
}
// Distortion of scanlines, and end of screen alpha. // Distortion of scanlines, and end of screen alpha.
vec2 Warp(vec2 pos){ vec2 Warp(vec2 pos)
pos=pos*2.0-1.0; {
pos*=vec2(1.0+(pos.y*pos.y)*warpX,1.0+(pos.x*pos.x)*warpY); pos = pos*2.0-1.0;
return pos*0.5+0.5;} pos *= vec2(1.0 + (pos.y*pos.y)*param.warpX, 1.0 + (pos.x*pos.x)*param.warpY);
return pos*0.5 + 0.5;
}
// Shadow mask. // Shadow mask.
vec3 Mask(vec2 pos){ vec3 Mask(vec2 pos)
vec3 mask=vec3(maskDark,maskDark,maskDark); {
vec3 mask = vec3(param.maskDark, param.maskDark, param.maskDark);
// Very compressed TV style shadow mask. // Very compressed TV style shadow mask.
if (shadowMask == 1.0) { if (param.shadowMask == 1.0)
float line=maskLight; {
float odd=0.0; float line = param.maskLight;
if(fract(pos.x/6.0)<0.5)odd=1.0; float odd = 0.0;
if(fract((pos.y+odd)/2.0)<0.5)line=maskDark;
pos.x=fract(pos.x/3.0);
if(pos.x<0.333)mask.r=maskLight; if (fract(pos.x*0.166666666) < 0.5) odd = 1.0;
else if(pos.x<0.666)mask.g=maskLight; if (fract((pos.y + odd) * 0.5) < 0.5) line = param.maskDark;
else mask.b=maskLight;
mask*=line;
}
// Aperture-grille. pos.x = fract(pos.x*0.333333333);
else if (shadowMask == 2.0) {
pos.x=fract(pos.x/3.0);
if(pos.x<0.333)mask.r=maskLight; if (pos.x < 0.333) mask.r = param.maskLight;
else if(pos.x<0.666)mask.g=maskLight; else if (pos.x < 0.666) mask.g = param.maskLight;
else mask.b=maskLight; else mask.b = param.maskLight;
} mask*=line;
}
// Stretched VGA style shadow mask (same as prior shaders). // Aperture-grille.
else if (shadowMask == 3.0) { else if (param.shadowMask == 2.0)
pos.x+=pos.y*3.0; {
pos.x=fract(pos.x/6.0); pos.x = fract(pos.x*0.333333333);
if(pos.x<0.333)mask.r=maskLight; if (pos.x < 0.333) mask.r = param.maskLight;
else if(pos.x<0.666)mask.g=maskLight; else if (pos.x < 0.666) mask.g = param.maskLight;
else mask.b=maskLight; else mask.b = param.maskLight;
} }
// VGA style shadow mask. // Stretched VGA style shadow mask (same as prior shaders).
else if (shadowMask == 4.0) { else if (param.shadowMask == 3.0)
pos.xy=floor(pos.xy*vec2(1.0,0.5)); {
pos.x+=pos.y*3.0; pos.x += pos.y*3.0;
pos.x=fract(pos.x/6.0); pos.x = fract(pos.x*0.166666666);
if(pos.x<0.333)mask.r=maskLight; if (pos.x < 0.333) mask.r = param.maskLight;
else if(pos.x<0.666)mask.g=maskLight; else if (pos.x < 0.666) mask.g = param.maskLight;
else mask.b=maskLight; else mask.b = param.maskLight;
} }
return mask;} // VGA style shadow mask.
else if (param.shadowMask == 4.0)
{
pos.xy = floor(pos.xy*vec2(1.0, 0.5));
pos.x += pos.y*3.0;
pos.x = fract(pos.x*0.166666666);
if (pos.x < 0.333) mask.r = param.maskLight;
else if (pos.x < 0.666) mask.g = param.maskLight;
else mask.b = param.maskLight;
}
return mask;
}
void main() void main()
{ {
vec2 pos=Warp(vTexCoord); vec2 pos = Warp(vTexCoord);
vec3 outColor = Tri(pos); vec3 outColor = Tri(pos);
#ifdef DO_BLOOM
//Add Bloom
outColor.rgb+=Bloom(pos)*bloomAmount;
#endif
if(shadowMask > 0.0)
outColor.rgb*=Mask(vTexCoord.xy / global.OutputSize.zw * 1.000001);
//hacky clamp fix
vec2 bordertest = (pos);
if ( bordertest.x > 0.0001 && bordertest.x < 0.9999 && bordertest.y > 0.0001 && bordertest.y < 0.9999)
outColor.rgb = outColor.rgb;
else
outColor.rgb = vec3(0.0);
FragColor = vec4(ToSrgb(outColor.rgb), 1.0); #ifdef DO_BLOOM
//Add Bloom
outColor.rgb += Bloom(pos)*param.bloomAmount;
#endif
if (param.shadowMask > 0.0)
outColor.rgb *= Mask(vTexCoord.xy / global.OutputSize.zw * 1.000001);
/* TODO/FIXME - hacky clamp fix */
vec2 bordertest = (pos);
if ( bordertest.x > 0.0001 && bordertest.x < 0.9999 && bordertest.y > 0.0001 && bordertest.y < 0.9999)
outColor.rgb = outColor.rgb;
else
outColor.rgb = vec3(0.0);
FragColor = vec4(ToSrgb(outColor.rgb), 1.0);
} }

View file

@ -1,5 +1,12 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float BOOST;
} param;
#pragma parameter BOOST "Color Boost" 1.0 0.5 1.5 0.02
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -48,8 +55,6 @@ vec3 beam(vec3 color, float dist)
#endif #endif
} }
#define COLOR_BOOST 1.0
void main() void main()
{ {
vec2 texel = floor(data_pix_no); vec2 texel = floor(data_pix_no);
@ -67,6 +72,6 @@ void main()
scanline += beam(top, dist0); scanline += beam(top, dist0);
scanline += beam(bottom, dist1); scanline += beam(bottom, dist1);
FragColor = vec4(COLOR_BOOST * scanline * 0.869565217391304, 1.0); FragColor = vec4(param.BOOST * scanline * 0.869565217391304, 1.0);
} }

View file

@ -1,5 +1,12 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float INPUT_GAMMA;
} param;
#pragma parameter INPUT_GAMMA "Input Gamma" 2.4 2.0 2.6 0.02
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -24,11 +31,9 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define INPUT_GAMMA 2.4
void main() void main()
{ {
vec3 color = texture(Source, vTexCoord).rgb; vec3 color = texture(Source, vTexCoord).rgb;
FragColor = vec4(pow(color, vec3(INPUT_GAMMA)), 1.0); FragColor = vec4(pow(color, vec3(param.INPUT_GAMMA)), 1.0);
} }

View file

@ -1,5 +1,14 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float BLOOM_STRENGTH;
float OUTPUT_GAMMA;
} param;
#pragma parameter BLOOM_STRENGTH "Glow Strength" 0.45 0.0 0.8 0.05
#pragma parameter OUTPUT_GAMMA "Monitor Gamma" 2.2 1.8 2.6 0.02
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -29,9 +38,6 @@ layout(set = 0, binding = 2) uniform sampler2D CRTPass;
// For debugging // For debugging
#define BLOOM_ONLY 0 #define BLOOM_ONLY 0
#define BLOOM_STRENGTH 0.45
#define OUTPUT_GAMMA 2.2
#define CRT_PASS CRTPass #define CRT_PASS CRTPass
void main() void main()
@ -42,7 +48,7 @@ void main()
vec3 source = 1.15 * texture(CRT_PASS, vTexCoord).rgb; vec3 source = 1.15 * texture(CRT_PASS, vTexCoord).rgb;
vec3 bloom = texture(Source, vTexCoord).rgb; vec3 bloom = texture(Source, vTexCoord).rgb;
source += BLOOM_STRENGTH * bloom; source += param.BLOOM_STRENGTH * bloom;
#endif #endif
FragColor = vec4(pow(clamp(source, 0.0, 1.0), vec3(1.0 / OUTPUT_GAMMA)), 1.0); FragColor = vec4(pow(clamp(source, 0.0, 1.0), vec3(1.0 / param.OUTPUT_GAMMA)), 1.0);
} }

View file

@ -1,5 +1,14 @@
#version 450 #version 450
layout(push_constant) uniform Push
{
float GLOW_WHITEPOINT;
float GLOW_ROLLOFF;
} param;
#pragma parameter GLOW_WHITEPOINT "Glow Whitepoint" 1.0 0.5 1.1 0.02
#pragma parameter GLOW_ROLLOFF "Glow Rolloff" 3.0 1.2 6.0 0.1
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -24,13 +33,10 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
#define GLOW_WHITEPOINT 1.0
#define GLOW_ROLLOFF 3.0
void main() void main()
{ {
vec3 color = 1.15 * texture(Source, vTexCoord).rgb; vec3 color = 1.15 * texture(Source, vTexCoord).rgb;
vec3 factor = clamp(color / GLOW_WHITEPOINT, 0.0, 1.0); vec3 factor = clamp(color / param.GLOW_WHITEPOINT, 0.0, 1.0);
FragColor = vec4(pow(factor, vec3(GLOW_ROLLOFF)), 1.0); FragColor = vec4(pow(factor, vec3(param.GLOW_ROLLOFF)), 1.0);
} }

View file

@ -43,6 +43,17 @@
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
layout(push_constant) uniform Push
{
float FIR_GAIN;
float FIR_INVGAIN;
float PHASE_NOISE;
} param;
#pragma parameter FIR_GAIN "FIR lowpass gain" 1.5 0.0 5.0 0.1
#pragma parameter FIR_INVGAIN "Inverse gain for luma recovery" 1.1 0.0 5.0 0.1
#pragma parameter PHASE_NOISE "Phase noise" 1.0 0.0 5.0 0.1
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
{ {
mat4 MVP; mat4 MVP;
@ -68,30 +79,12 @@ layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor; layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source; layout(set = 0, binding = 2) uniform sampler2D Source;
/* Config options */
/* FIR lowpass gain */
#define FIR_GAIN 1.5
/* Inverse gain for luma recovery (correct for stripes) */
#define FIR_INVGAIN 1.1
/* phase noise (2.5 for crappy cable) */
#define PHASE_NOISE 1.0
/* Subcarrier frequency */ /* Subcarrier frequency */
#define FSC 4433618.75 #define FSC 4433618.75
/* Line frequency */ /* Line frequency */
#define FLINE 15625 #define FLINE 15625
#define VISIBLELINES 312 #define VISIBLELINES 312
#define PI 3.14159265358 #define PI 3.14159265358
@ -140,14 +133,13 @@ float FIR[FIRTAPS] = float[FIRTAPS] (
/* subcarrier counts per scan line = FSC/FLINE = 283.7516 */ /* subcarrier counts per scan line = FSC/FLINE = 283.7516 */
/* We save the reciprocal of this only to optimize it */ /* We save the reciprocal of this only to optimize it */
float counts_per_scanline_reciprocal = 0.00352420920269701; float counts_per_scanline_reciprocal = 1.0 / (FSC/FLINE);
float width_ratio; float width_ratio;
float height_ratio; float height_ratio;
float altv; float altv;
float invx; float invx;
/* http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ */ /* http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/ */
float rand(vec2 co) float rand(vec2 co)
{ {
@ -160,7 +152,8 @@ float rand(vec2 co)
return fract(sin(sn) * c); return fract(sin(sn) * c);
} }
float modulated(vec2 xy, float sinwt, float coswt) { float modulated(vec2 xy, float sinwt, float coswt)
{
vec3 rgb = fetch(0, xy, invx).xyz; vec3 rgb = fetch(0, xy, invx).xyz;
vec3 yuv = RGB_to_YUV * rgb; vec3 yuv = RGB_to_YUV * rgb;
@ -178,14 +171,13 @@ vec2 modem_uv(vec2 xy, float ofs) {
vec3 yuv = RGB_to_YUV * rgb; vec3 yuv = RGB_to_YUV * rgb;
float signal = clamp(yuv.x + yuv.y * sinwt + yuv.z * coswt, 0.0, 1.0); float signal = clamp(yuv.x + yuv.y * sinwt + yuv.z * coswt, 0.0, 1.0);
if (PHASE_NOISE != 0) if (param.PHASE_NOISE != 0)
{ {
/* .yy is horizontal noise, .xx looks bad, .xy is classic noise */ /* .yy is horizontal noise, .xx looks bad, .xy is classic noise */
vec2 seed = vTexCoord.yy + global.FrameCount; vec2 seed = xy.yy * global.FrameCount;
wt = wt + param.PHASE_NOISE * (rand(seed) - 0.5);
wt = wt + PHASE_NOISE * (rand(seed) - 0.5); sinwt = sin(wt);
sinwt = sin(wt); coswt = cos(wt + altv);
coswt = cos(wt + altv);
} }
return vec2(signal * sinwt, signal * coswt); return vec2(signal * sinwt, signal * coswt);
@ -203,7 +195,7 @@ void main()
vec2 filtered = vec2(0.0, 0.0); vec2 filtered = vec2(0.0, 0.0);
for (int i = 0; i < FIRTAPS; i++) { for (int i = 0; i < FIRTAPS; i++) {
vec2 uv = modem_uv(xy, i - FIRTAPS*0.5); vec2 uv = modem_uv(xy, i - FIRTAPS*0.5);
filtered += FIR_GAIN * uv * FIR[i]; filtered += param.FIR_GAIN * uv * FIR[i];
} }
float t = xy.x * global.SourceSize.x; float t = xy.x * global.SourceSize.x;
@ -212,7 +204,7 @@ void main()
float sinwt = sin(wt); float sinwt = sin(wt);
float coswt = cos(wt + altv); float coswt = cos(wt + altv);
float luma = modulated(xy, sinwt, coswt) - FIR_INVGAIN * (filtered.x * sinwt + filtered.y * coswt); float luma = modulated(xy, sinwt, coswt) - param.FIR_INVGAIN * (filtered.x * sinwt + filtered.y * coswt);
vec3 yuv_result = vec3(luma, filtered.x, filtered.y); vec3 yuv_result = vec3(luma, filtered.x, filtered.y);
FragColor = vec4(YUV_to_RGB * yuv_result, 1.0); FragColor = vec4(YUV_to_RGB * yuv_result, 1.0);