zfast_crt_geo + zfast_crt_nogeo (#235)

* zfast_crt_xxx presets

* zfast_crt_geo + zfast_crt_nogeo

Modified zfast_crt.glsl shader to include screen curvature, vignetting, round corners and phosphor*temperature while targeting 60fps on GPU deprived platforms like the Chromecast, Raspberry Pi-4B, Wii, etc
zfast_crt_nogeo is the same minus the screen curvature for extra performance, modeled after "widescreen" games like the Sega Genesis, NeoGeo, etc.
This commit is contained in:
Dogway 2023-07-07 14:32:49 +01:00 committed by GitHub
parent b57db40613
commit 53b773f4e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 422 additions and 0 deletions

View File

@ -0,0 +1,212 @@
#version 110
/*
zfast_crt_geo - A simple, fast CRT shader.
Copyright (C) 2017 Greg Hogan (SoltanGris42)
Copyright (C) 2023 Jose Linares (Dogway)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
Notes: This shader does scaling with a weighted linear filter
based on the algorithm by Iñigo Quilez here:
https://iquilezles.org/articles/texture/
but modified to be somewhat sharper. Then a scanline effect that varies
based on pixel brightness is applied along with a monochrome aperture mask.
This shader runs at ~60fps on the Chromecast HD (10GFlops) on a 1080p display.
(https://forums.libretro.com/t/android-googletv-compatible-shaders-nitpicky)
Dogway: I modified zfast_crt.glsl shader to include screen curvature,
vignetting, round corners and phosphor*temperature. Horizontal pixel is left out
from the Quilez' algo (read above) to provide a more S-Video like horizontal blur.
The scanlines and mask are also now performed in the recommended linear light.
For this to run smoothly on GPU deprived platforms like the Chromecast and
older consoles, I had to remove several parameters and hardcode them into the shader.
Another POV is to run the shader on handhelds like the Switch or SteamDeck so they consume less battery.
*/
//For testing compilation
//#define FRAGMENT
//#define VERTEX
// Parameter lines go here:
#pragma parameter SCANLINE_WEIGHT "Scanline Amount" 7.0 0.0 15.0 0.5
#pragma parameter MASK_DARK "Mask Effect Amount" 0.5 0.0 1.0 0.05
#pragma parameter g_vstr "Vignette Strength" 50.0 0.0 50.0 1.0
#pragma parameter g_vpower "Vignette Power" 0.40 0.0 0.5 0.01
#if defined(VERTEX)
#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying
#define COMPAT_ATTRIBUTE attribute
#define COMPAT_TEXTURE texture2D
#endif
#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif
COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;
COMPAT_VARYING vec2 invDims;
COMPAT_VARYING vec2 scale;
vec4 _oPosition1;
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
// compatibility #defines
#define vTexCoord TEX0.xy
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
uniform COMPAT_PRECISION float MASK_DARK;
uniform COMPAT_PRECISION float g_vstr;
uniform COMPAT_PRECISION float g_vpower;
#else
#define SCANLINE_WEIGHT 7.0
#define MASK_DARK 0.5
#define g_vstr 50.0
#define g_vpower 0.40
#endif
void main()
{
gl_Position = MVPMatrix * VertexCoord;
TEX0.xy = TexCoord.xy*1.00001;
invDims = 1.0/TextureSize.xy;
}
#elif defined(FRAGMENT)
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif
#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out COMPAT_PRECISION vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;
COMPAT_VARYING vec2 invDims;
// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy
#define scale vec2(TextureSize.xy/InputSize.xy)
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
uniform COMPAT_PRECISION float MASK_DARK;
uniform COMPAT_PRECISION float g_vstr;
uniform COMPAT_PRECISION float g_vpower;
#else
#define SCANLINE_WEIGHT 7.0
#define MASK_DARK 0.5
#define g_vstr 50.0
#define g_vpower 0.40
#endif
// NTSC-J (D93) -> Rec709 D65 Joint Matrix (with D93 simulation)
// This is compensated for a linearization hack (RGB*RGB and then sqrt())
const mat3 P22D93 = mat3(
1.00000, 0.00000, -0.06173,
0.07111, 0.96887, -0.01136,
0.00000, 0.08197, 1.07280);
vec2 Warp(vec2 pos)
{
pos = pos*2.0-1.0;
pos *= vec2(1.0 + (pos.y*pos.y)*0.0276, 1.0 + (pos.x*pos.x)*0.0414);
return pos*0.5 + 0.5;
}
void main()
{
vec2 vpos = vTexCoord*scale;
vec2 xy = Warp(vpos);
vec2 corn = min(xy,vec2(1.0)-xy); // This is used to mask the rounded
corn.x = 0.0001/corn.x; // corners later on
xy /= scale;
vpos *= (1.0 - vpos.xy);
float vig = vpos.x * vpos.y * g_vstr;
vig = min(pow(vig, g_vpower), 1.0);
vig = vig >= 0.5 ? smoothstep(0.0,1.0,vig) : vig;
// Of all the pixels that are mapped onto the texel we are
// currently rendering, which pixel are we currently rendering?
float ratio_scale = xy.y * TextureSize.y - 0.5;
// Snap to the center of the underlying texel.
float i = floor(ratio_scale) + 0.5;
// This is just like "Quilez Scaling" but sharper
float f = ratio_scale - i;
COMPAT_PRECISION float Y = f*f;
float p = (i + 4.0*Y*f)*invDims.y;
vec2 MSCL = OutputSize.y > 1499.0 ? vec2(0.30) : vec2(0.499999, 0.5);
COMPAT_PRECISION float whichmask = floor(vTexCoord.x*4.0*OutputSize.x)*-MSCL.x;
COMPAT_PRECISION float mask = 1.0 + float(fract(whichmask) < MSCL.y) * -MASK_DARK;
COMPAT_PRECISION vec3 colour = COMPAT_TEXTURE(Source, vec2(xy.x,p)).rgb;
vec3 P22 = ((colour*colour) * P22D93) * vig;
colour = max(vec3(0.0),P22);
COMPAT_PRECISION float scanLineWeight = (1.5 - SCANLINE_WEIGHT*(Y - Y*Y));
if (corn.y <= corn.x || corn.x < 0.0001 )
colour = vec3(0.0);
FragColor.rgba = vec4(sqrt(colour.rgb*(mix(scanLineWeight*mask, 1.0, dot(colour.rgb,vec3(0.26667))))),1.0);
}
#endif

View File

@ -0,0 +1,192 @@
#version 110
/*
zfast_crt_nogeo - A simple, fast CRT shader.
Copyright (C) 2017 Greg Hogan (SoltanGris42)
Copyright (C) 2023 Jose Linares (Dogway)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
Notes: This shader does scaling with a weighted linear filter
based on the algorithm by Iñigo Quilez here:
https://iquilezles.org/articles/texture/
but modified to be somewhat sharper. Then a scanline effect that varies
based on pixel brightness is applied along with a monochrome aperture mask.
This shader runs at ~60fps on the Chromecast HD (10GFlops) on a 1080p display.
(https://forums.libretro.com/t/android-googletv-compatible-shaders-nitpicky)
Dogway: This is the same as zfast_crt_geo but without the screen curvature for extra
performance, specially for (320x240) "widescreen" games like Sega Genesis, NeoGeo, etc.
*/
//For testing compilation
//#define FRAGMENT
//#define VERTEX
// Parameter lines go here:
#pragma parameter SCANLINE_WEIGHT "Scanline Amount" 9.0 0.0 15.0 0.5
#pragma parameter MASK_DARK "Mask Effect Amount" 0.1 0.0 1.0 0.05
#pragma parameter g_vstr "Vignette Strength" 50.0 0.0 50.0 1.0
#pragma parameter g_vpower "Vignette Power" 0.30 0.0 0.5 0.01
#if defined(VERTEX)
#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying
#define COMPAT_ATTRIBUTE attribute
#define COMPAT_TEXTURE texture2D
#endif
#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif
COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;
COMPAT_VARYING vec2 invDims;
COMPAT_VARYING vec2 scale;
vec4 _oPosition1;
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
// compatibility #defines
#define vTexCoord TEX0.xy
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
uniform COMPAT_PRECISION float MASK_DARK;
uniform COMPAT_PRECISION float g_vstr;
uniform COMPAT_PRECISION float g_vpower;
#else
#define SCANLINE_WEIGHT 7.0
#define MASK_DARK 0.5
#define g_vstr 50.0
#define g_vpower 0.40
#endif
void main()
{
gl_Position = MVPMatrix * VertexCoord;
TEX0.xy = TexCoord.xy*1.00001;
invDims = 1.0/TextureSize.xy;
}
#elif defined(FRAGMENT)
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif
#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out COMPAT_PRECISION vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;
COMPAT_VARYING vec2 invDims;
// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy
#define scale vec2(TextureSize.xy/InputSize.xy)
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
uniform COMPAT_PRECISION float MASK_DARK;
uniform COMPAT_PRECISION float g_vstr;
uniform COMPAT_PRECISION float g_vpower;
#else
#define SCANLINE_WEIGHT 7.0
#define MASK_DARK 0.5
#define g_vstr 50.0
#define g_vpower 0.40
#endif
// NTSC-J (D93) -> Rec709 D65 Joint Matrix (with D93 simulation)
// This is compensated for a linearization hack (RGB*RGB and then sqrt())
const mat3 P22D93 = mat3(
1.00000, 0.00000, -0.06173,
0.07111, 0.96887, -0.01136,
0.00000, 0.08197, 1.07280);
void main()
{
vec2 vpos = vTexCoord*scale;
vec2 corn = min(vpos,vec2(1.0)-vpos); // This is used to mask the rounded
corn.x = 0.0001/corn.x; // corners later on
vpos *= (1.0 - vpos.xy);
float vig = vpos.x * vpos.y * g_vstr;
vig = min(pow(vig, g_vpower), 1.0);
vig = vig >= 0.5 ? smoothstep(0.0,1.0,vig) : vig;
// This is just like "Quilez Scaling" but sharper
COMPAT_PRECISION float p = vTexCoord.y * TextureSize.y;
// Snap to the center of the underlying texel.
COMPAT_PRECISION float i = floor(p) + 0.5;
COMPAT_PRECISION float f = p - i;
COMPAT_PRECISION float Y = f*f;
p = (i + 4.0*Y*f)*invDims.y;
vec2 MSCL = OutputSize.y > 1499.0 ? vec2(0.30) : vec2(0.499999, 0.5);
COMPAT_PRECISION float whichmask = floor(vTexCoord.x*4.0*OutputSize.x)*-MSCL.x;
COMPAT_PRECISION float mask = 1.0 + float(fract(whichmask) < MSCL.y) * -MASK_DARK;
COMPAT_PRECISION vec3 colour = COMPAT_TEXTURE(Source, vec2(vTexCoord.x,p)).rgb;
vec3 P22 = ((colour*colour) * P22D93) * vig;
colour = max(vec3(0.0),P22);
COMPAT_PRECISION float scanLineWeight = (1.5 - SCANLINE_WEIGHT*(Y - Y*Y));
if (corn.y <= corn.x)
colour = vec3(0.0);
FragColor.rgba = vec4(sqrt(colour.rgb*(mix(scanLineWeight*mask, 1.0, dot(colour.rgb,vec3(0.26667))))),1.0);
}
#endif

9
crt/zfast_crt_geo.glslp Normal file
View File

@ -0,0 +1,9 @@
shaders = "1"
shader0 = "shaders/zfast_crt_geo.glsl"
filter_linear0 = "true"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"

View File

@ -0,0 +1,9 @@
shaders = "1"
shader0 = "shaders/zfast_crt_nogeo.glsl"
filter_linear0 = "true"
wrap_mode0 = "clamp_to_border"
mipmap_input0 = "false"
alias0 = ""
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"