From d0524545351ab18beb48a764547ea828129c2afc Mon Sep 17 00:00:00 2001 From: hunterk Date: Wed, 13 Oct 2021 19:20:23 -0500 Subject: [PATCH] update bob-deinterlacing and remove now-redundant bob-and-ghost --- misc/bob-and-ghost-deinterlacing.slang | 63 -------------------------- misc/bob-deinterlacing.slang | 54 ++++++++++++++++++---- 2 files changed, 45 insertions(+), 72 deletions(-) delete mode 100644 misc/bob-and-ghost-deinterlacing.slang diff --git a/misc/bob-and-ghost-deinterlacing.slang b/misc/bob-and-ghost-deinterlacing.slang deleted file mode 100644 index ed92486..0000000 --- a/misc/bob-and-ghost-deinterlacing.slang +++ /dev/null @@ -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))); -} diff --git a/misc/bob-deinterlacing.slang b/misc/bob-deinterlacing.slang index 9f7af57..a1dd1e8 100644 --- a/misc/bob-deinterlacing.slang +++ b/misc/bob-deinterlacing.slang @@ -5,8 +5,11 @@ 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. + 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 @@ -15,6 +18,7 @@ layout(push_constant) uniform Push vec4 OriginalSize; vec4 OutputSize; uint FrameCount; + float scale, ghost; } params; layout(std140, set = 0, binding = 0) uniform UBO @@ -22,30 +26,62 @@ layout(std140, set = 0, binding = 0) uniform UBO mat4 MVP; } 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 layout(location = 0) in vec4 Position; layout(location = 1) in vec2 TexCoord; layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out float is_interlaced; void main() { gl_Position = global.MVP * Position; vTexCoord = TexCoord; + is_interlaced = float(params.OriginalSize.y > 400.0 * params.scale); } #pragma stage fragment layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in float is_interlaced; layout(location = 0) out vec4 FragColor; layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D OriginalHistory1; void main() { - 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 + float(params.FrameCount); - else y = 2.000001 * params.SourceSize.y * vTexCoord.y; + // snap to the center of the underlying texel + vec2 uv = vTexCoord * params.SourceSize.xy - 0.5; + uv = (floor(uv) + 0.5) * params.SourceSize.zw; + + // go ahead and sample the texture and early return if not interlaced + vec4 current = texture(Source, uv); + FragColor = current; + if(!bool(is_interlaced)) return; + + float scale = params.scale; - if (mod(y, 2.0) > 0.99999) FragColor = vec4(texture(Source, vTexCoord + vec2(0.0, params.SourceSize.w))); - else - FragColor = vec4(texture(Source, vTexCoord).rgb, 1.0); + // 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); }