Merge pull request #447 from fishcu/fishcu/update-average-fill-scaling

Update average fill
This commit is contained in:
hizzlekizzle 2023-06-14 19:54:49 -05:00 committed by GitHub
commit 93dfa33afe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 146 additions and 62 deletions

View file

@ -10,6 +10,13 @@
This is useful for certain games that do not render a full image to maintain This is useful for certain games that do not render a full image to maintain
the overall aspect ratio and to avoid burn-in. the overall aspect ratio and to avoid burn-in.
The preset also allows you to extend the original content to a larger
screen. It's recommended to set the video scaling options as follows:
- Turn integer scaling OFF
- Set aspect ratio to FULL
The shader will then take over and handle the proper scaling and aspect
ratio of the input.
In case the image is cropped on multiple sides, different blend modes for 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 the corner are available. Simply change the parameter for the "corner blend
mode". mode".
@ -20,6 +27,7 @@
3 = Smooth angle-based blending 3 = Smooth angle-based blending
Changelog: Changelog:
v1.1: Add extension modes from blur fill; Add average gamma adjustment.
v1.0: Initial release. v1.0: Initial release.
*/ */
@ -27,18 +35,26 @@
layout(push_constant) uniform Push { layout(push_constant) uniform Push {
vec4 InputSize; vec4 InputSize;
vec4 OriginalSize; vec4 FinalViewportSize;
vec4 OutputSize;
uint FrameCount;
float OS_CROP_TOP; float OS_CROP_TOP;
float OS_CROP_BOTTOM; float OS_CROP_BOTTOM;
float OS_CROP_LEFT; float OS_CROP_LEFT;
float OS_CROP_RIGHT; float OS_CROP_RIGHT;
float CORNER_BLEND_MODE; float CENTER_CROP;
float SAMPLE_SIZE; float SAMPLE_SIZE;
float EXTEND_H;
float EXTEND_V;
float CORNER_BLEND_MODE;
float FORCE_ASPECT_RATIO;
float ASPECT_H;
float ASPECT_V;
float FORCE_INTEGER_SCALING;
float FILL_GAMMA;
} }
param; param;
#include "../blur_fill/scaling.slang"
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; } layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
global; global;
@ -70,7 +86,7 @@ vec3 blend_corner(vec3 a, // The first color to blend
vec3 b, // The second color to blend vec3 b, // The second color to blend
float wa, // The weight of the first color float wa, // The weight of the first color
float wb, // The weight of the second color float wb, // The weight of the second color
vec2 pixel_coord, // The coordinate to evaluate the blend for vec2 coord, // The coordinate to evaluate the blend for
vec2 corner_coord, // The coordinate of the corner of the vec2 corner_coord, // The coordinate of the corner of the
// content after cropping // content after cropping
vec2 gap_size // The component-wise distance from the corner vec2 gap_size // The component-wise distance from the corner
@ -89,7 +105,7 @@ vec3 blend_corner(vec3 a, // The first color to blend
case 3: case 3:
default: default:
// Angle blend // Angle blend
const vec2 delta = (pixel_coord - corner_coord) / gap_size; const vec2 delta = (coord - corner_coord) / gap_size;
// Use absolutes to always operate in 1st quadrant. // Use absolutes to always operate in 1st quadrant.
// This makes the angle work out to be correct in all cases when // This makes the angle work out to be correct in all cases when
// carefully choosing argument ordering. // carefully choosing argument ordering.
@ -100,90 +116,139 @@ vec3 blend_corner(vec3 a, // The first color to blend
} }
void main() { void main() {
const vec2 pixel_coord = vTexCoord * param.InputSize.xy; const vec2 pixel_coord = o2i(vTexCoord) * param.InputSize.xy;
if (pixel_coord.x < param.OS_CROP_LEFT) { if (pixel_coord.x < param.OS_CROP_LEFT) {
if (param.EXTEND_H < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb; const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb;
if (pixel_coord.y < param.OS_CROP_TOP) { if (pixel_coord.y < param.OS_CROP_TOP) {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Top left corner // Top left corner
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb; const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
const vec2 content_corner =
i2o(vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP) *
param.InputSize.zw);
const vec2 viewport_corner = vec2(0.0, 0.0);
FragColor = FragColor =
vec4(blend_corner(left, top, vec4(blend_corner(left, top,
param.InputSize.y - param.OS_CROP_TOP - param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM, param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT - param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT, param.OS_CROP_RIGHT,
pixel_coord, vTexCoord, content_corner,
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP), viewport_corner - content_corner),
vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP)),
1.0); 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) { } else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Left bar // Left bar
FragColor = vec4(left, 1.0); FragColor = vec4(pow(left, vec3(param.FILL_GAMMA)), 1.0);
} else { } else {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Bottom left corner // Bottom left corner
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb; const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
FragColor = vec4( const vec2 content_corner =
blend_corner(left, bottom, i2o(vec2(param.OS_CROP_LEFT,
param.InputSize.y - param.OS_CROP_BOTTOM) *
param.InputSize.zw);
const vec2 viewport_corner = vec2(0.0, 1.0);
FragColor =
vec4(blend_corner(left, bottom,
param.InputSize.y - param.OS_CROP_TOP - param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM, param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT - param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT, param.OS_CROP_RIGHT,
pixel_coord, vTexCoord, content_corner,
vec2(param.OS_CROP_LEFT, viewport_corner - content_corner),
param.InputSize.y - param.OS_CROP_BOTTOM),
vec2(param.OS_CROP_LEFT, param.OS_CROP_BOTTOM)),
1.0); 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} }
} else if (pixel_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) { } else if (pixel_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) {
if (pixel_coord.y < param.OS_CROP_TOP) { if (pixel_coord.y < param.OS_CROP_TOP) {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Top bar // Top bar
FragColor = vec4(textureLod(Top, vec2(0.5), BIG_NUMBER).rgb, 1.0); FragColor = vec4(textureLod(Top, vec2(0.5), BIG_NUMBER).rgb, 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) { } else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Uncropped // Uncropped
// Do a sharp (nearest neighbor) resampling. // Do a sharp (nearest neighbor) resampling.
FragColor = vec4( FragColor = vec4(
texture(Input, (floor(vTexCoord * param.InputSize.xy) + 0.5) * texture(Input, (floor(pixel_coord) + 0.5) * param.InputSize.zw)
param.InputSize.zw)
.rgb, .rgb,
1.0); 1.0);
} else { } else {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Bottom bar // Bottom bar
FragColor = FragColor =
vec4(textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb, 1.0); vec4(textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb, 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} }
} else { } else {
if (param.EXTEND_H < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb; const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb;
if (pixel_coord.y < param.OS_CROP_TOP) { if (pixel_coord.y < param.OS_CROP_TOP) {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Top right corner // Top right corner
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb; const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
const vec2 content_corner =
i2o(vec2(param.InputSize.x - param.OS_CROP_RIGHT,
param.OS_CROP_TOP) *
param.InputSize.zw);
const vec2 viewport_corner = vec2(1.0, 0.0);
FragColor = FragColor =
vec4(blend_corner(right, top, vec4(blend_corner(right, top,
param.InputSize.y - param.OS_CROP_TOP - param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM, param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT - param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT, param.OS_CROP_RIGHT,
pixel_coord, vTexCoord, content_corner,
vec2(param.InputSize.x - param.OS_CROP_RIGHT, viewport_corner - content_corner),
param.OS_CROP_TOP),
vec2(param.OS_CROP_RIGHT, param.OS_CROP_TOP)),
1.0); 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) { } else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
// Right bar // Right bar
FragColor = vec4(right, 1.0); FragColor = vec4(pow(right, vec3(param.FILL_GAMMA)), 1.0);
} else { } else {
if (param.EXTEND_V < 0.5) {
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
return;
}
// Bottom right corner // Bottom right corner
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb; const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
FragColor = vec4( const vec2 content_corner =
blend_corner(right, bottom, i2o(vec2(param.InputSize.x - param.OS_CROP_RIGHT,
param.InputSize.y - param.OS_CROP_BOTTOM) *
param.InputSize.zw);
const vec2 viewport_corner = vec2(1.0, 1.0);
FragColor =
vec4(blend_corner(right, bottom,
param.InputSize.y - param.OS_CROP_TOP - param.InputSize.y - param.OS_CROP_TOP -
param.OS_CROP_BOTTOM, param.OS_CROP_BOTTOM,
param.InputSize.x - param.OS_CROP_LEFT - param.InputSize.x - param.OS_CROP_LEFT -
param.OS_CROP_RIGHT, param.OS_CROP_RIGHT,
pixel_coord, vTexCoord, content_corner,
vec2(param.InputSize.x - param.OS_CROP_RIGHT, viewport_corner - content_corner),
param.InputSize.y - param.OS_CROP_BOTTOM),
vec2(param.OS_CROP_RIGHT, param.OS_CROP_BOTTOM)),
1.0); 1.0);
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
} }
} }
} }

View file

@ -1,11 +1,25 @@
// See compose.slang for copyright and other information. // See compose.slang for copyright and other information.
// clang-format off // clang-format off
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.0 settings ===" 0.0 0.0 1.0 1.0 #pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.1 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_TOP "Overscan crop top" 8.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_BOTTOM "Overscan crop bottom" 8.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_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 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 CENTER_CROP "Center cropped area" 1.0 0.0 1.0 1.0
#pragma parameter SAMPLE_SIZE "No. of lines for calculating the average" 4.0 1.0 64.0 1.0 #pragma parameter SAMPLE_SIZE "No. of lines for calculating the average" 4.0 1.0 64.0 1.0
#pragma parameter EXTEND_H "Extend the fill horizontally" 1.0 0.0 1.0 1.0
#pragma parameter EXTEND_V "Extend the fill vertically" 1.0 0.0 1.0 1.0
#pragma parameter CORNER_BLEND_MODE "Cropped corner blend mode" 0.0 0.0 3.0 1.0
#pragma parameter FORCE_ASPECT_RATIO "Force aspect ratio" 0.0 0.0 1.0 1.0
#pragma parameter ASPECT_H "Horizontal aspect ratio before crop" 4.0 1.0 100.0 1.0
#pragma parameter ASPECT_V "Vertical aspect ratio before crop" 3.0 1.0 100.0 1.0
#pragma parameter FORCE_INTEGER_SCALING "Force integer scaling" 1.0 0.0 1.0 1.0
#pragma parameter FILL_GAMMA "Background fill gamma adjustment" 1.0 0.5 2.0 0.1
// clang-format on // clang-format on

View file

@ -1,5 +1,3 @@
#include "parameters.slang"
// See compose.slang for copyright and other information. // See compose.slang for copyright and other information.
// Pixels in input coord. space // Pixels in input coord. space
@ -48,17 +46,24 @@ vec2 scale_o2i() {
} }
} }
// In unit space (output to input) // Input to output scaling, in unit coordinate systems.
// coord_in_input_space = o2i(coord_in_output_space) vec2 scale_i2o() { return 1.0 / scale_o2i(); }
// This is used to sample from the input texture in the output pass.
vec2 o2i(vec2 x) { // Get adjusted center in input unit coordinate system.
const vec2 center_in = vec2 get_input_center() {
param.CENTER_CROP > 0.5 return param.CENTER_CROP > 0.5
? 0.5 * param.InputSize.zw * ? 0.5 * param.InputSize.zw *
vec2(param.OS_CROP_LEFT + param.InputSize.x - vec2(param.OS_CROP_LEFT + param.InputSize.x -
param.OS_CROP_RIGHT, param.OS_CROP_RIGHT,
param.OS_CROP_TOP + param.InputSize.y - param.OS_CROP_TOP + param.InputSize.y -
param.OS_CROP_BOTTOM) param.OS_CROP_BOTTOM)
: vec2(0.49999); : vec2(0.49999);
return (x - 0.49999) * scale_o2i() + center_in;
} }
// In unit space (output to input).
// coord_in_input_space = o2i(coord_in_output_space)
// This is used to sample from the input texture in the output pass.
vec2 o2i(vec2 x) { return (x - 0.49999) * scale_o2i() + get_input_center(); }
// In unit coordinate systems.
vec2 i2o(vec2 x) { return (x - get_input_center()) * scale_i2o() + 0.49999; }