mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-22 15:51:30 +11:00
Merge pull request #447 from fishcu/fishcu/update-average-fill-scaling
Update average fill
This commit is contained in:
commit
93dfa33afe
|
@ -10,6 +10,13 @@
|
|||
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 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
|
||||
the corner are available. Simply change the parameter for the "corner blend
|
||||
mode".
|
||||
|
@ -20,6 +27,7 @@
|
|||
3 = Smooth angle-based blending
|
||||
|
||||
Changelog:
|
||||
v1.1: Add extension modes from blur fill; Add average gamma adjustment.
|
||||
v1.0: Initial release.
|
||||
*/
|
||||
|
||||
|
@ -27,18 +35,26 @@
|
|||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 InputSize;
|
||||
vec4 OriginalSize;
|
||||
vec4 OutputSize;
|
||||
uint FrameCount;
|
||||
vec4 FinalViewportSize;
|
||||
float OS_CROP_TOP;
|
||||
float OS_CROP_BOTTOM;
|
||||
float OS_CROP_LEFT;
|
||||
float OS_CROP_RIGHT;
|
||||
float CORNER_BLEND_MODE;
|
||||
float CENTER_CROP;
|
||||
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;
|
||||
|
||||
#include "../blur_fill/scaling.slang"
|
||||
|
||||
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
||||
global;
|
||||
|
||||
|
@ -66,11 +82,11 @@ layout(set = 0, binding = 6) uniform sampler2D Right;
|
|||
// 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
|
||||
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 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
|
||||
|
@ -89,7 +105,7 @@ vec3 blend_corner(vec3 a, // The first color to blend
|
|||
case 3:
|
||||
default:
|
||||
// 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.
|
||||
// This makes the angle work out to be correct in all cases when
|
||||
// carefully choosing argument ordering.
|
||||
|
@ -100,90 +116,139 @@ vec3 blend_corner(vec3 a, // The first color to blend
|
|||
}
|
||||
|
||||
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 (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;
|
||||
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
|
||||
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 =
|
||||
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)),
|
||||
vTexCoord, content_corner,
|
||||
viewport_corner - content_corner),
|
||||
1.0);
|
||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
||||
// Left bar
|
||||
FragColor = vec4(left, 1.0);
|
||||
FragColor = vec4(pow(left, vec3(param.FILL_GAMMA)), 1.0);
|
||||
} else {
|
||||
if (param.EXTEND_V < 0.5) {
|
||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
const vec2 content_corner =
|
||||
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.OS_CROP_BOTTOM,
|
||||
param.InputSize.x - param.OS_CROP_LEFT -
|
||||
param.OS_CROP_RIGHT,
|
||||
vTexCoord, content_corner,
|
||||
viewport_corner - content_corner),
|
||||
1.0);
|
||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||
}
|
||||
} else if (pixel_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) {
|
||||
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
|
||||
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) {
|
||||
// Uncropped
|
||||
// Do a sharp (nearest neighbor) resampling.
|
||||
FragColor = vec4(
|
||||
texture(Input, (floor(vTexCoord * param.InputSize.xy) + 0.5) *
|
||||
param.InputSize.zw)
|
||||
texture(Input, (floor(pixel_coord) + 0.5) * param.InputSize.zw)
|
||||
.rgb,
|
||||
1.0);
|
||||
} else {
|
||||
if (param.EXTEND_V < 0.5) {
|
||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
// Bottom bar
|
||||
FragColor =
|
||||
vec4(textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb, 1.0);
|
||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||
}
|
||||
} 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;
|
||||
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
|
||||
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 =
|
||||
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)),
|
||||
vTexCoord, content_corner,
|
||||
viewport_corner - content_corner),
|
||||
1.0);
|
||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||
} else if (pixel_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
||||
// Right bar
|
||||
FragColor = vec4(right, 1.0);
|
||||
FragColor = vec4(pow(right, vec3(param.FILL_GAMMA)), 1.0);
|
||||
} else {
|
||||
if (param.EXTEND_V < 0.5) {
|
||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
const vec2 content_corner =
|
||||
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.OS_CROP_BOTTOM,
|
||||
param.InputSize.x - param.OS_CROP_LEFT -
|
||||
param.OS_CROP_RIGHT,
|
||||
vTexCoord, content_corner,
|
||||
viewport_corner - content_corner),
|
||||
1.0);
|
||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
// 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 AVERAGE_FILL_SETTINGS "=== Average fill v1.1 settings ===" 0.0 0.0 1.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" 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_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 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
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "parameters.slang"
|
||||
|
||||
// See compose.slang for copyright and other information.
|
||||
|
||||
// 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.
|
||||
vec2 scale_i2o() { return 1.0 / scale_o2i(); }
|
||||
|
||||
// Get adjusted center in input unit coordinate system.
|
||||
vec2 get_input_center() {
|
||||
return param.CENTER_CROP > 0.5
|
||||
? 0.5 * param.InputSize.zw *
|
||||
vec2(param.OS_CROP_LEFT + param.InputSize.x -
|
||||
param.OS_CROP_RIGHT,
|
||||
param.OS_CROP_TOP + param.InputSize.y -
|
||||
param.OS_CROP_BOTTOM)
|
||||
: vec2(0.49999);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
const vec2 center_in =
|
||||
param.CENTER_CROP > 0.5
|
||||
? 0.5 * param.InputSize.zw *
|
||||
vec2(param.OS_CROP_LEFT + param.InputSize.x -
|
||||
param.OS_CROP_RIGHT,
|
||||
param.OS_CROP_TOP + param.InputSize.y -
|
||||
param.OS_CROP_BOTTOM)
|
||||
: vec2(0.49999);
|
||||
return (x - 0.49999) * scale_o2i() + center_in;
|
||||
}
|
||||
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; }
|
||||
|
|
Loading…
Reference in a new issue