Merge pull request #196 from hunterk/interlacing

update bob-deinterlacing and remove now-redundant bob-and-ghost
This commit is contained in:
hizzlekizzle 2021-10-15 08:49:00 -05:00 committed by GitHub
commit 33bf8f7e66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 72 deletions

View file

@ -1,63 +0,0 @@
#version 450
/*
Bob-and-ghost Deinterlacing
Author: hunterk
License: Public domain
Note: This shader is designed to work with the typical interlaced output from an emulator, which displays both even and odd fields twice.
As such, it is inappropriate for general video use unless the video has already been similarly woven beforehand.
*/
layout(push_constant) uniform Push
{
vec4 SourceSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
} 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 vTexCoord;
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = TexCoord;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Source;
void main()
{
vec4 current = pow(texture(Source, vTexCoord.xy), vec4(2.2));
vec4 prev = vec4(0.0);
float y = 0.0;
// assume anything with a vertical resolution greater than 400 lines is interlaced
if (params.SourceSize.y > 400.0){
y = params.SourceSize.y * vTexCoord.y + params.FrameCount;
current = pow(vec4(texture(Source, vTexCoord + vec2(0.0, params.SourceSize.w))), vec4(2.2));
vec4 evens = pow(vec4(texture(Source, vTexCoord - vec2(0.0, 0.5 * params.SourceSize.w))), vec4(2.2));
vec4 odds = pow(vec4(texture(Source, vTexCoord + vec2(0.0, 0.5 * params.SourceSize.w))), vec4(2.2));
prev = (evens + odds) / 2.0;
}
else
{
y = 2.000001 * params.SourceSize.y * vTexCoord.y;
prev = current;
}
if (mod(y, 2.0) > 0.99999) current = current;
else current = vec4(pow(texture(Source, vTexCoord), vec4(2.2)));
FragColor = vec4(pow((current + prev) / vec4(2.0), vec4(1.0 / 2.2)));
}

View file

@ -5,8 +5,11 @@
Author: hunterk Author: hunterk
License: Public domain License: Public domain
Note: This shader is designed to work with the typical interlaced output from an emulator, which displays both even and odd fields twice. Note: This shader is designed to work with the typical interlaced output from
As such, it is inappropriate for general video use unless the video has already been similarly woven beforehand. an emulator, which displays both even and odd fields twice.
As such, it is inappropriate for general video use unless the video has
already been similarly woven beforehand.
*/ */
layout(push_constant) uniform Push layout(push_constant) uniform Push
@ -15,6 +18,7 @@ layout(push_constant) uniform Push
vec4 OriginalSize; vec4 OriginalSize;
vec4 OutputSize; vec4 OutputSize;
uint FrameCount; uint FrameCount;
float scale, ghost;
} params; } params;
layout(std140, set = 0, binding = 0) uniform UBO layout(std140, set = 0, binding = 0) uniform UBO
@ -22,30 +26,62 @@ layout(std140, set = 0, binding = 0) uniform UBO
mat4 MVP; mat4 MVP;
} global; } global;
// I wish there were some way to make this automatic...
#pragma parameter scale "Deinterlacing Scale" 1.0 1.0 16.0 1.0
#pragma parameter ghost "Blend Frames to Hide Bobbing" 0.0 0.0 1.0 1.0
#pragma stage vertex #pragma stage vertex
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 = 1) out float is_interlaced;
void main() void main()
{ {
gl_Position = global.MVP * Position; gl_Position = global.MVP * Position;
vTexCoord = TexCoord; vTexCoord = TexCoord;
is_interlaced = float(params.OriginalSize.y > 400.0 * params.scale);
} }
#pragma stage fragment #pragma stage fragment
layout(location = 0) in vec2 vTexCoord; layout(location = 0) in vec2 vTexCoord;
layout(location = 1) in float is_interlaced;
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;
layout(set = 0, binding = 3) uniform sampler2D OriginalHistory1;
void main() void main()
{ {
float y = 0.0; // snap to the center of the underlying texel
// assume anything with a vertical resolution greater than 400 lines is interlaced vec2 uv = vTexCoord * params.SourceSize.xy - 0.5;
if (params.SourceSize.y > 400.0) y = params.SourceSize.y * vTexCoord.y + float(params.FrameCount); uv = (floor(uv) + 0.5) * params.SourceSize.zw;
else y = 2.000001 * params.SourceSize.y * vTexCoord.y;
if (mod(y, 2.0) > 0.99999) FragColor = vec4(texture(Source, vTexCoord + vec2(0.0, params.SourceSize.w))); // go ahead and sample the texture and early return if not interlaced
else vec4 current = texture(Source, uv);
FragColor = vec4(texture(Source, vTexCoord).rgb, 1.0); FragColor = current;
if(!bool(is_interlaced)) return;
float scale = params.scale;
// work our way down the vertical axis and skip up 1 pixel every other frame
float y = (params.SourceSize.y / scale) * uv.y + mod(float(params.FrameCount), 2.0);
// deinterlace the current frame
vec4 offset = texture(Source, uv + vec2(0.0, params.SourceSize.w * scale));
vec4 deint_current = (mod(y, 2.0) > 0.99999) ? offset : current;
FragColor = deint_current;
// early return if we don't want to do any frame-blending
if(!bool(params.ghost)) return;
// previous frame needs an opposite tick from the current frame
float y2 = (params.SourceSize.y / scale) * uv.y + clamp(1.0 - mod(float(params.FrameCount), 2.0), 0.0, 1.0);
// deinterlace previous frame
vec4 prev = texture(OriginalHistory1, uv);
vec4 prev_offset = texture(OriginalHistory1, uv + vec2(0.0, params.SourceSize.w * scale));
vec4 deint_prev = (mod(y2, 2.0) > 0.99999) ? prev_offset : prev;
FragColor = mix(deint_current, deint_prev, 0.5);
} }