Add average fill (#443)

* Implement average fill

* Implement corner blend modes

* Add copyright; Change defaults; Add some polish

* Add settings delimiter

* Fix settings name
This commit is contained in:
fishcu 2023-06-11 22:57:38 +02:00 committed by GitHub
parent 407b93da55
commit 77b6ca6bed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 352 additions and 0 deletions

View file

@ -0,0 +1,59 @@
shaders = 7
shader0 = ../blurs/shaders/kawase/linearize.slang
scale_type0 = source
scale_x0 = 1.0
scale_y0 = 1.0
float_framebuffer0 = true
alias0 = "Input"
shader1 = shaders/average_fill/crop_and_sample_top.slang
filter_linear1 = true
scale_type1 = absolute
scale_x1 = 512
scale_y1 = 64
float_framebuffer1 = true
wrap_mode1 = mirrored_repeat
alias1 = "Top"
shader2 = shaders/average_fill/crop_and_sample_bottom.slang
filter_linear2 = true
scale_type2 = absolute
scale_x2 = 512
scale_y2 = 64
float_framebuffer2 = true
mipmap_input2 = true
alias2 = "Bottom"
shader3 = shaders/average_fill/crop_and_sample_left.slang
filter_linear3 = true
scale_type3 = absolute
scale_x3 = 64
scale_y3 = 512
float_framebuffer3 = true
mipmap_input3 = true
alias3 = "Left"
shader4 = shaders/average_fill/crop_and_sample_right.slang
filter_linear4 = true
scale_type4 = absolute
scale_x4 = 64
scale_y4 = 512
float_framebuffer4 = true
mipmap_input4 = true
alias4 = "Right"
shader5 = shaders/average_fill/compose.slang
filter_linear5 = true
scale_type5 = viewport
scale_x5 = 1.0
scale_y5 = 1.0
float_framebuffer5 = true
mipmap_input5 = true
shader6 = ../blurs/shaders/kawase/delinearize.slang
filter_linear6 = true
scale_type6 = viewport
scale_x6 = 1.0
scale_y6 = 1.0
float_framebuffer6 = true

View file

@ -0,0 +1,189 @@
#version 450
/*
Average fill v1.0 by fishku
Copyright (C) 2023
Public domain license (CC0)
This shader preset allows cropping the image on any side, and filling the
cropped area with the average color of an adjustable area next to it.
This is useful for certain games that do not render a full image to maintain
the overall aspect ratio and to avoid burn-in.
In case the image is cropped on multiple sides, different blend modes for
the corner are available. Simply change the parameter for the "corner blend
mode".
The available corner blend modes are:
0 = Draw horizontal bars on top
1 = Draw vertical bars on top
2 = Blend bars by weighted averaging
3 = Smooth angle-based blending
Changelog:
v1.0: Initial release.
*/
#include "parameters.slang"
layout(push_constant) uniform Push {
vec4 InputSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float OS_CROP_TOP;
float OS_CROP_BOTTOM;
float OS_CROP_LEFT;
float OS_CROP_RIGHT;
float CORNER_BLEND_MODE;
float SAMPLE_SIZE;
}
param;
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 Input;
layout(set = 0, binding = 3) uniform sampler2D Top;
layout(set = 0, binding = 4) uniform sampler2D Bottom;
layout(set = 0, binding = 5) uniform sampler2D Left;
layout(set = 0, binding = 6) uniform sampler2D Right;
#define PI 3.1415926538
// For mipmap sampling, use a big offset to get the average of a PoT input.
#define BIG_NUMBER 9000.1
vec3 blend_corner(vec3 a, // The first color to blend
vec3 b, // The second color to blend
float wa, // The weight of the first color
float wb, // The weight of the second color
vec2 pixel_coord, // The coordinate to evaluate the blend for
vec2 corner_coord, // The coordinate of the corner of the
// content after cropping
vec2 gap_size // The component-wise distance from the corner
// of the content to the corner of the viewport
) {
switch (int(param.CORNER_BLEND_MODE)) {
case 0:
// Horizontal bars on top
return b;
case 1:
// Vertical bars on top
return a;
case 2:
// Weighted average of averages
return mix(a, b, wa / (wa + wb));
case 3:
default:
// Angle blend
const vec2 delta = (pixel_coord - corner_coord) / gap_size;
// Use absolutes to always operate in 1st quadrant.
// This makes the angle work out to be correct in all cases when
// carefully choosing argument ordering.
const float angle = atan(abs(delta.y), abs(delta.x)) / (PI * 0.5);
// Smoothstep makes the transition perceptually smoother.
return mix(a, b, smoothstep(0.0, 1.0, angle));
}
}
void main() {
const vec2 pixel_coord = vTexCoord * param.InputSize.xy;
if (pixel_coord.x < param.OS_CROP_LEFT) {
const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb;
if (pixel_coord.y < param.OS_CROP_TOP) {
// Top left corner
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
FragColor =
vec4(blend_corner(left, top,
param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT,
pixel_coord,
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP),
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP)),
1.0);
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Left bar
FragColor = vec4(left, 1.0);
} else {
// Bottom left corner
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
FragColor = vec4(
blend_corner(left, bottom,
param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT,
pixel_coord,
vec2(param.OS_CROP_LEFT,
param.InputSize.y - param.OS_CROP_BOTTOM),
vec2(param.OS_CROP_LEFT, param.OS_CROP_BOTTOM)),
1.0);
}
} else if (pixel_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) {
if (pixel_coord.y < param.OS_CROP_TOP) {
// Top bar
FragColor = vec4(textureLod(Top, vec2(0.5), BIG_NUMBER).rgb, 1.0);
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Uncropped
// Do a sharp (nearest neighbor) resampling.
FragColor = vec4(
texture(Input, (floor(vTexCoord * param.InputSize.xy) + 0.5) *
param.InputSize.zw)
.rgb,
1.0);
} else {
// Bottom bar
FragColor =
vec4(textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb, 1.0);
}
} else {
const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb;
if (pixel_coord.y < param.OS_CROP_TOP) {
// Top right corner
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
FragColor =
vec4(blend_corner(right, top,
param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT,
pixel_coord,
vec2(param.InputSize.x - param.OS_CROP_RIGHT,
param.OS_CROP_TOP),
vec2(param.OS_CROP_RIGHT, param.OS_CROP_TOP)),
1.0);
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Right bar
FragColor = vec4(right, 1.0);
} else {
// Bottom right corner
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
FragColor = vec4(
blend_corner(right, bottom,
param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT,
pixel_coord,
vec2(param.InputSize.x - param.OS_CROP_RIGHT,
param.InputSize.y - param.OS_CROP_BOTTOM),
vec2(param.OS_CROP_RIGHT, param.OS_CROP_BOTTOM)),
1.0);
}
}
}

View file

@ -0,0 +1,14 @@
#version 450
// See compose.slang for copyright and other information.
#include "parameters.slang"
// clang-format off
#define EFF_CROP_TOP (param.InputSize.y - param.OS_CROP_BOTTOM - param.SAMPLE_SIZE)
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
// clang-format on
#include "crop_and_sample_common.slang"

View file

@ -0,0 +1,37 @@
// See compose.slang for copyright and other information.
layout(push_constant) uniform Push {
vec4 InputSize;
vec4 OriginalSize;
vec4 OutputSize;
uint FrameCount;
float OS_CROP_TOP;
float OS_CROP_BOTTOM;
float OS_CROP_LEFT;
float OS_CROP_RIGHT;
float SAMPLE_SIZE;
}
param;
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 =
mix(vec2(EFF_CROP_LEFT, EFF_CROP_TOP) * param.InputSize.zw,
1.0 - vec2(EFF_CROP_RIGHT, EFF_CROP_BOTTOM) * param.InputSize.zw,
TexCoord);
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
layout(set = 0, binding = 2) uniform sampler2D Input;
void main() { FragColor = vec4(texture(Input, vTexCoord).rgb, 1.0); }

View file

@ -0,0 +1,14 @@
#version 450
// See compose.slang for copyright and other information.
#include "parameters.slang"
// clang-format off
#define EFF_CROP_TOP (param.OS_CROP_TOP)
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
#define EFF_CROP_RIGHT (param.InputSize.x - param.OS_CROP_LEFT - param.SAMPLE_SIZE)
// clang-format on
#include "crop_and_sample_common.slang"

View file

@ -0,0 +1,14 @@
#version 450
// See compose.slang for copyright and other information.
#include "parameters.slang"
// clang-format off
#define EFF_CROP_TOP (param.OS_CROP_TOP)
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
#define EFF_CROP_LEFT (param.InputSize.x - param.OS_CROP_RIGHT - param.SAMPLE_SIZE)
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
// clang-format on
#include "crop_and_sample_common.slang"

View file

@ -0,0 +1,14 @@
#version 450
// See compose.slang for copyright and other information.
#include "parameters.slang"
// clang-format off
#define EFF_CROP_TOP (param.OS_CROP_TOP)
#define EFF_CROP_BOTTOM (param.InputSize.y - param.OS_CROP_TOP - param.SAMPLE_SIZE)
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
// clang-format on
#include "crop_and_sample_common.slang"

View file

@ -0,0 +1,11 @@
// See compose.slang for copyright and other information.
// clang-format off
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.0 settings ===" 0.0 0.0 1.0 1.0
#pragma parameter OS_CROP_TOP "Overscan crop top" 16.0 0.0 1024.0 1.0
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 16.0 0.0 1024.0 1.0
#pragma parameter OS_CROP_LEFT "Overscan crop left" 0.0 0.0 1024.0 1.0
#pragma parameter OS_CROP_RIGHT "Overscan crop right" 0.0 0.0 1024.0 1.0
#pragma parameter CORNER_BLEND_MODE "Cropped corner blend mode" 0.0 0.0 3.0 1.0
#pragma parameter SAMPLE_SIZE "No. of lines for calculating the average" 4.0 1.0 64.0 1.0
// clang-format on