mirror of
https://github.com/libretro/slang-shaders.git
synced 2024-12-03 14:50:41 +00:00
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:
parent
407b93da55
commit
77b6ca6bed
59
border/average_fill.slangp
Normal file
59
border/average_fill.slangp
Normal 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
|
189
border/shaders/average_fill/compose.slang
Normal file
189
border/shaders/average_fill/compose.slang
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
14
border/shaders/average_fill/crop_and_sample_bottom.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_bottom.slang
Normal 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"
|
37
border/shaders/average_fill/crop_and_sample_common.slang
Normal file
37
border/shaders/average_fill/crop_and_sample_common.slang
Normal 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); }
|
14
border/shaders/average_fill/crop_and_sample_left.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_left.slang
Normal 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"
|
14
border/shaders/average_fill/crop_and_sample_right.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_right.slang
Normal 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"
|
14
border/shaders/average_fill/crop_and_sample_top.slang
Normal file
14
border/shaders/average_fill/crop_and_sample_top.slang
Normal 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"
|
11
border/shaders/average_fill/parameters.slang
Normal file
11
border/shaders/average_fill/parameters.slang
Normal 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
|
Loading…
Reference in New Issue
Block a user