Add edgeNpixels shader (#630)

Co-authored-by: Andrei Timofeev <andrei.timofeev@mobirate.com>
This commit is contained in:
Decavoid 2024-08-30 21:20:50 +04:00 committed by GitHub
parent b9e012f25c
commit 1b2ad364b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 92 additions and 13 deletions

View File

@ -0,0 +1,5 @@
shaders = 1
shader0 = shaders/edgeNpixels.slang
filter_linear0 = true
scale_type0 = viewport

View File

@ -1,6 +1,7 @@
#version 450
// Interpolate a single row of display pixels between each pair of adjacent source pixels.
// Insert a single interpolated display (high-res)
// pixel row between each pair of adjacent source (low-res) pixels.
// by decavoid
@ -20,22 +21,21 @@ layout(std140, set = 0, binding = 0) uniform UBO
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
layout(location = 1) out vec2 inverseScale;
layout(location = 0) out vec2 PixelCoords;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
inverseScale = vec2(params.OriginalSize.xy / params.OutputSize.xy);
PixelCoords = TexCoord * params.SourceSize.xy; // NES x: [0; 256], y: [0; 240]
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 1) in vec2 inverseScale;
layout(location = 0) in vec2 PixelCoords;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
vec2 inverseScaleHalf = vec2(params.OriginalSize.xy / params.OutputSize.xy) * 0.5;
vec2 isInside(vec2 v, vec2 left, vec2 right)
{
return step(left, v) - step(right, v);
@ -46,11 +46,11 @@ vec2 isInside(vec2 v, vec2 left, vec2 right)
void main()
{
vec2 pixelCoords = vTexCoord * params.SourceSize.xy; // NES x: [0; 256], y: [0; 240]
vec2 coordAtPixelCenter = (floor(pixelCoords) + vec2(0.5));
vec2 coordBetweenPixels = round(pixelCoords);
vec2 f = fract(pixelCoords) + vec2(1e-4);
vec2 isFractionInside = isInside(f, 0.5 * inverseScale, 1.0 - 0.5 * inverseScale);
vec2 iPixelCoords = floor(PixelCoords);
vec2 coordAtPixelCenter = iPixelCoords + vec2(0.5);
vec2 coordBetweenPixels = round(PixelCoords);
vec2 f = fract(PixelCoords) + vec2(1e-3);
vec2 isFractionInside = isInside(f, inverseScaleHalf, 1.0 - inverseScaleHalf);
/*
Equivalent:
@ -67,7 +67,7 @@ void main()
*/
vec2 newCoord = isFractionInside * coordAtPixelCenter + (1 - isFractionInside) * coordBetweenPixels;
vec2 newTexCoord = newCoord / params.SourceSize.xy;
vec2 newTexCoord = newCoord * params.SourceSize.zw;
FragColor = texture(Source, newTexCoord);
#ifdef DEBUG_DRAW_EDGES

View File

@ -0,0 +1,74 @@
#version 450
// Insert a configurable count (1, 2, 3...) of interpolated display (high-res)
// pixel rows between each pair of adjacent source (low-res) pixels.
// by decavoid
#pragma parameter PixelCount "Pixel Count" 2.0 1.0 8.0 1.0
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float PixelCount;
} params;
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 PixelCoords;
void main()
{
gl_Position = global.MVP * Position;
PixelCoords = TexCoord * params.SourceSize.xy; // NES x: [0; 256], y: [0; 240]
}
#pragma stage fragment
layout(location = 0) in vec2 PixelCoords;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
// uncomment to see a red grid of modified pixels
//#define DEBUG_DRAW_EDGES
vec4 sizeScale = params.OutputSize / params.OriginalSize;
vec2 interpolationRangeHalf = params.PixelCount * 0.5 * sizeScale.zw;
float stepPerRow = 1.0 / (params.PixelCount + 1.0);
void main()
{
vec2 coordAtPixelCenter = (floor(PixelCoords) + vec2(0.5));
vec2 coordBetweenPixels = round(PixelCoords);
vec2 origOffset = PixelCoords - coordBetweenPixels + 1e-3; // [-0.5; 0.5]
vec2 needInterpolate = step(abs(origOffset), interpolationRangeHalf);
// if needInterpolate == 0, disable interpolation by choosing coordAtPixelCenter.
//
// if needInterpolate == 1, transform origOffset.x
// from range [-interpolationRangeHalf.x; interpolationRangeHalf.x]
// to range (-0.5; 0.5)
vec2 segmentIndex = floor((origOffset + interpolationRangeHalf) * sizeScale.xy);
vec2 transformedOffset = stepPerRow * (segmentIndex + 1) - 0.5;
vec2 interpolatedCoord = coordBetweenPixels + transformedOffset;
vec2 newCoord = (1 - needInterpolate) * coordAtPixelCenter + needInterpolate * interpolatedCoord;
vec2 newTexCoord = newCoord * params.SourceSize.zw;
FragColor = texture(Source, newTexCoord);
#ifdef DEBUG_DRAW_EDGES
if (needInterpolate.x + needInterpolate.y > 0)
FragColor.r = 1;
#endif
}