mirror of
https://github.com/libretro/slang-shaders.git
synced 2025-02-17 00:17:51 +00:00
Fix input TF bug & large refactoring; Add box filter AA (#613)
* Initial refactoring, pixel AA xform and bf xform still show the problem * Heavy refactoring and debugging; bf xform first working version * Clean up code * Fix pixel aa xform * Fix average fill; Slight cleanup * Remove special FinalViewportScaling handling in input_xf; Fix blur fill * Bump version
This commit is contained in:
parent
5e702cfdc6
commit
05a41341be
@ -1,8 +1,8 @@
|
||||
#version 450
|
||||
|
||||
/*
|
||||
Average fill v1.8 by fishku
|
||||
Copyright (C) 2023
|
||||
Average fill v1.9 by fishku
|
||||
Copyright (C) 2023-2024
|
||||
Public domain license (CC0)
|
||||
|
||||
This shader preset allows cropping the image on any side, and filling the
|
||||
@ -27,6 +27,7 @@
|
||||
3 = Smooth angle-based blending
|
||||
|
||||
Changelog:
|
||||
v1.9: Update input transform library.
|
||||
v1.8: Add shift option from input transform library.
|
||||
v1.7: Add overscale option from crop and scale library.
|
||||
v1.6: Refactor for new scaling library. Add rotation support.
|
||||
@ -85,32 +86,33 @@ global;
|
||||
#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 vec2 scale_o2i;
|
||||
layout(location = 2) out vec4 crop;
|
||||
layout(location = 3) out vec2 shift;
|
||||
layout(location = 0) out vec4 input_corners;
|
||||
layout(location = 1) out vec2 vTexCoord;
|
||||
layout(location = 2) out vec2 scale_i2o;
|
||||
layout(location = 3) out vec2 input_center;
|
||||
layout(location = 4) out vec2 tx_coord;
|
||||
layout(location = 5) out vec2 tx_per_px;
|
||||
layout(location = 6) out vec2 tx_to_uv;
|
||||
layout(location = 7) out vec4 input_corners;
|
||||
layout(location = 8) out vec2 cropped_input_size;
|
||||
layout(location = 7) out vec2 cropped_input_size;
|
||||
|
||||
void main() {
|
||||
gl_Position = global.MVP * Position;
|
||||
vTexCoord = TexCoord;
|
||||
crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT, param.OS_CROP_BOTTOM,
|
||||
param.OS_CROP_RIGHT);
|
||||
scale_o2i = get_scale_o2i(
|
||||
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||
scale_i2o = get_scale_i2o(
|
||||
param.InputSize.xy, param.OutputSize.xy, crop, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
||||
vec2(param.ASPECT_H, param.ASPECT_V),
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V),
|
||||
param.OVERSCALE,
|
||||
/* output_size_is_final_viewport_size = */ false);
|
||||
shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
tx_per_px = scale_o2i * param.OutputSize.zw;
|
||||
param.OVERSCALE);
|
||||
const vec2 shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
input_center = get_input_center(param.InputSize.xy, param.OutputSize.xy,
|
||||
scale_i2o, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING);
|
||||
tx_coord = transform(TexCoord, vec2(0.5), param.OutputSize.xy / scale_i2o,
|
||||
input_center);
|
||||
tx_per_px = 1.0 / scale_i2o;
|
||||
tx_to_uv = param.InputSize.zw;
|
||||
|
||||
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||
@ -121,15 +123,14 @@ void main() {
|
||||
}
|
||||
|
||||
#pragma stage fragment
|
||||
layout(location = 0) in vec2 vTexCoord;
|
||||
layout(location = 1) in vec2 scale_o2i;
|
||||
layout(location = 2) in vec4 crop;
|
||||
layout(location = 3) in vec2 shift;
|
||||
layout(location = 0) in vec4 input_corners;
|
||||
layout(location = 1) in vec2 vTexCoord;
|
||||
layout(location = 2) in vec2 scale_i2o;
|
||||
layout(location = 3) in vec2 input_center;
|
||||
layout(location = 4) in vec2 tx_coord;
|
||||
layout(location = 5) in vec2 tx_per_px;
|
||||
layout(location = 6) in vec2 tx_to_uv;
|
||||
layout(location = 7) in vec4 input_corners;
|
||||
layout(location = 8) in vec2 cropped_input_size;
|
||||
layout(location = 7) in vec2 cropped_input_size;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(set = 0, binding = 2) uniform sampler2D Input;
|
||||
layout(set = 0, binding = 3) uniform sampler2D Top;
|
||||
@ -192,8 +193,8 @@ void main() {
|
||||
// Top left corner
|
||||
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
|
||||
const vec2 content_corner =
|
||||
i2o(input_corners.xy, param.InputSize.xy, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
transform(input_corners.xy, input_center,
|
||||
scale_i2o / param.OutputSize.xy, vec2(0.5));
|
||||
const vec2 viewport_corner = vec2(0.0, 0.0);
|
||||
FragColor = vec4(
|
||||
blend_corner(left, top, cropped_input_size.y,
|
||||
@ -212,8 +213,8 @@ void main() {
|
||||
// Bottom left corner
|
||||
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
|
||||
const vec2 content_corner =
|
||||
i2o(input_corners.xw, param.InputSize.xy, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
transform(input_corners.xw, input_center,
|
||||
scale_i2o / param.OutputSize.xy, vec2(0.5));
|
||||
const vec2 viewport_corner = vec2(0.0, 1.0);
|
||||
FragColor = vec4(
|
||||
blend_corner(left, bottom, cropped_input_size.y,
|
||||
@ -273,8 +274,8 @@ void main() {
|
||||
// Top right corner
|
||||
const vec3 top = textureLod(Top, vec2(0.5), BIG_NUMBER).rgb;
|
||||
const vec2 content_corner =
|
||||
i2o(input_corners.zy, param.InputSize.xy, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
transform(input_corners.zy, input_center,
|
||||
scale_i2o / param.OutputSize.xy, vec2(0.5));
|
||||
const vec2 viewport_corner = vec2(1.0, 0.0);
|
||||
FragColor = vec4(
|
||||
blend_corner(right, top, cropped_input_size.y,
|
||||
@ -293,8 +294,8 @@ void main() {
|
||||
// Bottom right corner
|
||||
const vec3 bottom = textureLod(Bottom, vec2(0.5), BIG_NUMBER).rgb;
|
||||
const vec2 content_corner =
|
||||
i2o(input_corners.zw, param.InputSize.xy, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
transform(input_corners.zw, input_center,
|
||||
scale_i2o / param.OutputSize.xy, vec2(0.5));
|
||||
const vec2 viewport_corner = vec2(1.0, 1.0);
|
||||
FragColor = vec4(
|
||||
blend_corner(right, bottom, cropped_input_size.y,
|
||||
|
@ -1,7 +1,7 @@
|
||||
// See compose.slang for copyright and other information.
|
||||
|
||||
// clang-format off
|
||||
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.8 settings ===" 0.0 0.0 1.0 1.0
|
||||
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.9 settings ===" 0.0 0.0 1.0 1.0
|
||||
|
||||
#include "../../../misc/shaders/input_transform/parameters.inc"
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/*
|
||||
Blur fill v1.9 by fishku
|
||||
Copyright (C) 2023
|
||||
Copyright (C) 2023-2024
|
||||
Public domain license (CC0)
|
||||
|
||||
This shader preset allows cropping the image on any side, and filling the
|
||||
@ -27,6 +27,7 @@
|
||||
strength of the blur.
|
||||
|
||||
Changelog:
|
||||
v1.10: Update input transform library.
|
||||
v1.9: Add shift option from input transform library.
|
||||
v1.8: Add overscale option from crop and scale library.
|
||||
v1.7: Refactor for new scaling library. Add rotation support.
|
||||
@ -98,17 +99,19 @@ void main() {
|
||||
vTexCoord = TexCoord;
|
||||
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||
const vec2 scale_o2i = get_scale_o2i(
|
||||
const vec2 scale_i2o = get_scale_i2o(
|
||||
param.InputSize.xy, param.OutputSize.xy, crop, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
||||
vec2(param.ASPECT_H, param.ASPECT_V),
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V),
|
||||
param.OVERSCALE,
|
||||
/* output_size_is_final_viewport_size = */ false);
|
||||
param.OVERSCALE);
|
||||
const vec2 shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
tx_per_px = scale_o2i * param.OutputSize.zw;
|
||||
const vec2 input_center = get_input_center(
|
||||
param.InputSize.xy, param.OutputSize.xy, scale_i2o, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING);
|
||||
tx_coord = transform(TexCoord, vec2(0.5), param.OutputSize.xy / scale_i2o,
|
||||
input_center);
|
||||
tx_per_px = 1.0 / scale_i2o;
|
||||
tx_to_uv = param.InputSize.zw;
|
||||
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// See compose.slang for copyright and other information.
|
||||
|
||||
// clang-format off
|
||||
#pragma parameter BLUR_FILL_SETTINGS "=== Blur fill v1.9 settings ===" 0.0 0.0 1.0 1.0
|
||||
#pragma parameter BLUR_FILL_SETTINGS "=== Blur fill v1.10 settings ===" 0.0 0.0 1.0 1.0
|
||||
|
||||
#include "../../../misc/shaders/input_transform/parameters.inc"
|
||||
|
||||
|
@ -48,15 +48,24 @@ void main() {
|
||||
vTexCoord = TexCoord;
|
||||
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||
const vec2 scale_o2i = get_scale_o2i(
|
||||
param.InputSize.xy, param.FinalViewportSize.xy, crop, param.Rotation,
|
||||
// Because RA "rotates" the final viewport size on rotated cores, we need to
|
||||
// undo that rotation so that the math checks out. The 0 and 180 degree
|
||||
// rotations and the 90 and 270 rotations are symmetric for 2D sizes, which
|
||||
// is why we can use param.Rotation directly here.
|
||||
const vec2 final_viewport_size_rotated =
|
||||
get_rotated_size(param.FinalViewportSize.xy, param.Rotation);
|
||||
const vec2 scale_i2o = get_scale_i2o(
|
||||
param.InputSize.xy, final_viewport_size_rotated, crop, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
||||
vec2(param.ASPECT_H, param.ASPECT_V),
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V), param.OVERSCALE,
|
||||
/* output_size_is_final_viewport_size = */ true);
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V),
|
||||
param.OVERSCALE);
|
||||
const vec2 shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
const vec2 input_center = get_input_center(
|
||||
param.InputSize.xy, final_viewport_size_rotated, scale_i2o, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING);
|
||||
tx_coord = transform(TexCoord, vec2(0.5),
|
||||
final_viewport_size_rotated / scale_i2o, input_center);
|
||||
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,11 @@
|
||||
// See the main shader file for copyright and other information.
|
||||
|
||||
#include "../../../misc/shaders/coverage/coverage.inc"
|
||||
|
||||
// As determined by counting pixels on a photo.
|
||||
const vec2 subpx_ratio = vec2(0.296, 0.910);
|
||||
const vec2 notch_ratio = vec2(0.115, 0.166);
|
||||
|
||||
float rect_coverage(vec4 px_rect, vec4 rect) {
|
||||
const vec2 bl = max(rect.xy, px_rect.xy);
|
||||
const vec2 tr = min(rect.zw, px_rect.zw);
|
||||
const vec2 coverage = max(tr - bl, 0.0);
|
||||
return coverage.x * coverage.y;
|
||||
}
|
||||
|
||||
float subpx_coverage(vec4 px_rect, vec2 subpx_orig, vec2 subpx_size,
|
||||
vec2 notch_size) {
|
||||
return rect_coverage(px_rect, vec4(subpx_orig, subpx_orig + subpx_size)) -
|
||||
|
10
misc/shaders/coverage/coverage.inc
Normal file
10
misc/shaders/coverage/coverage.inc
Normal file
@ -0,0 +1,10 @@
|
||||
// Computes intersection area between pixels and geometric shapes for perfect
|
||||
// (analytical) anti-aliasing.
|
||||
// Assumes that the pixel rectangle has area 1 to avoid normalization.
|
||||
|
||||
float rect_coverage(vec4 px_rect, vec4 rect) {
|
||||
const vec2 bl = max(rect.xy, px_rect.xy);
|
||||
const vec2 tr = min(rect.zw, px_rect.zw);
|
||||
const vec2 coverage = max(tr - bl, 0.0);
|
||||
return coverage.x * coverage.y;
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
Input transformation library v1.2 by fishku
|
||||
Copyright (C) 2023
|
||||
Input transformation library v1.3 by fishku
|
||||
Copyright (C) 2023-2024
|
||||
Public domain license (CC0)
|
||||
|
||||
Apply cropping, scaling, and transformation operations to input viewport and
|
||||
@ -25,6 +25,7 @@
|
||||
Refactored from the version that used to be in the blur_fill shader.
|
||||
|
||||
Changelog:
|
||||
v1.3: Bug fixes and cleanup.
|
||||
v1.2: Rename to "input transform". Add translation option.
|
||||
v1.1: Add overscaling option. Unify parameters.
|
||||
v1.0: Initial conversion from blur_fill release. Add rotation support.
|
||||
@ -40,31 +41,30 @@ vec4 get_input_corners(vec2 input_size, vec4 crop, uint rotation) {
|
||||
return vec4(crop.y, crop.x, input_size.x - crop.w, input_size.y - crop.z);
|
||||
}
|
||||
|
||||
// Get adjusted center in input pixel coordinate system.
|
||||
vec2 get_input_center(vec2 input_size, vec4 crop, vec2 shift, uint rotation,
|
||||
// Get adjusted center in input pixel (texel) coordinate system.
|
||||
// Crop is in input pixels (texels).
|
||||
// Shift is in output pixels.
|
||||
vec2 get_input_center(vec2 input_size, vec2 output_size, vec2 scale_i2o,
|
||||
vec4 crop, vec2 shift, uint rotation,
|
||||
float center_after_cropping) {
|
||||
crop = get_rotated_crop(crop, rotation);
|
||||
shift = get_rotated_vector(shift, rotation);
|
||||
return (center_after_cropping > 0.5
|
||||
? 0.5 * vec2(crop.y + input_size.x - crop.w,
|
||||
crop.x + input_size.y - crop.z)
|
||||
: vec2(0.49999) * input_size) -
|
||||
shift;
|
||||
// If input and output sizes have different parity, shift by 1/2 of an
|
||||
// output pixel to avoid having input pixel (texel) edges on output pixel
|
||||
// centers, which leads to all sorts of issues.
|
||||
return 0.5 * (input_size + center_after_cropping *
|
||||
vec2(crop.y - crop.w, crop.x - crop.z)) +
|
||||
(0.5 * mod(input_size + output_size, 2.0) - shift) / scale_i2o;
|
||||
}
|
||||
|
||||
// Scaling from unit output to pixel input space.
|
||||
vec2 get_scale_o2i(vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||
// Scaling from input to output space.
|
||||
vec2 get_scale_i2o(vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||
float center_after_cropping, float force_aspect_ratio,
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale,
|
||||
bool output_size_is_final_viewport_size) {
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale) {
|
||||
crop = get_rotated_crop(crop, rotation);
|
||||
if (output_size_is_final_viewport_size) {
|
||||
output_size = get_rotated_size(output_size, rotation);
|
||||
}
|
||||
aspect = get_rotated_size(aspect, rotation);
|
||||
// Aspect ratio before cropping.
|
||||
// lambda_1 * input_pixels.x, lambda_2 * input_pixels.y,
|
||||
// possibly corrected for forced aspect ratio
|
||||
// Corrected for forced aspect ratio.
|
||||
aspect = (force_aspect_ratio < 0.5
|
||||
? output_size * input_size.yx
|
||||
: (aspect.x < 0.5 || aspect.y < 0.5
|
||||
@ -77,78 +77,60 @@ vec2 get_scale_o2i(vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||
: 2.0 * vec2(min(crop.y, crop.w), min(crop.x, crop.z)));
|
||||
|
||||
force_integer_scaling = get_rotated_size(force_integer_scaling, rotation);
|
||||
float scale_x, scale_y;
|
||||
vec2 scale;
|
||||
if (output_size.x / (input_size.x * aspect.x) <
|
||||
output_size.y / (input_size.y * aspect.y)) {
|
||||
// Scale will be limited by width. Calc x scale, then derive y scale
|
||||
// using aspect ratio.
|
||||
scale_x = mix(output_size.x / input_size.x,
|
||||
scale.x = mix(output_size.x / input_size.x,
|
||||
output_size.y * aspect.x / (input_size.y * aspect.y),
|
||||
overscale);
|
||||
if (force_integer_scaling.x > 0.5 && scale_x > 1.0) {
|
||||
scale_x = floor(scale_x);
|
||||
if (force_integer_scaling.x > 0.5 && scale.x > 1.0) {
|
||||
scale.x = floor(scale.x);
|
||||
}
|
||||
scale_y = scale_x * aspect.y / aspect.x;
|
||||
if (force_integer_scaling.y > 0.5 && scale_y > 1.0) {
|
||||
scale_y = floor(scale_y);
|
||||
scale.y = scale.x * aspect.y / aspect.x;
|
||||
if (force_integer_scaling.y > 0.5 && scale.y > 1.0) {
|
||||
scale.y = floor(scale.y);
|
||||
}
|
||||
} else {
|
||||
// Scale will be limited by height.
|
||||
scale_y = mix(output_size.y / input_size.y,
|
||||
scale.y = mix(output_size.y / input_size.y,
|
||||
output_size.x * aspect.y / (input_size.x * aspect.x),
|
||||
overscale);
|
||||
if (force_integer_scaling.y > 0.5 && scale_y > 1.0) {
|
||||
scale_y = floor(scale_y);
|
||||
if (force_integer_scaling.y > 0.5 && scale.y > 1.0) {
|
||||
scale.y = floor(scale.y);
|
||||
}
|
||||
scale_x = scale_y * aspect.x / aspect.y;
|
||||
if (force_integer_scaling.x > 0.5 && scale_x > 1.0) {
|
||||
scale_x = floor(scale_x);
|
||||
scale.x = scale.y * aspect.x / aspect.y;
|
||||
if (force_integer_scaling.x > 0.5 && scale.x > 1.0) {
|
||||
scale.x = floor(scale.x);
|
||||
}
|
||||
}
|
||||
return output_size / vec2(scale_x, scale_y);
|
||||
return scale;
|
||||
}
|
||||
|
||||
// From unit output to pixel input space.
|
||||
// coord_in_input_space = o2i(coord_in_output_space)
|
||||
// This is used to sample from the input texture in the output pass.
|
||||
// Version where scale is passed in.
|
||||
vec2 o2i(vec2 x, vec2 input_size, vec4 crop, vec2 shift, uint rotation,
|
||||
float center_after_cropping, vec2 scale_o2i) {
|
||||
return (x - 0.49999) * scale_o2i + get_input_center(input_size, crop, shift,
|
||||
rotation,
|
||||
center_after_cropping);
|
||||
vec2 transform(vec2 x, vec2 input_center, vec2 scale, vec2 output_center) {
|
||||
return (x - input_center) * scale + output_center;
|
||||
}
|
||||
|
||||
// Version that computes scale.
|
||||
vec2 o2i(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, vec2 shift,
|
||||
uint rotation, float center_after_cropping, float force_aspect_ratio,
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale,
|
||||
bool output_size_is_final_viewport_size) {
|
||||
return o2i(x, input_size, crop, shift, rotation, center_after_cropping,
|
||||
get_scale_o2i(input_size, output_size, crop, rotation,
|
||||
center_after_cropping, force_aspect_ratio, aspect,
|
||||
force_integer_scaling, overscale,
|
||||
output_size_is_final_viewport_size));
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale) {
|
||||
const vec2 scale_i2o = get_scale_i2o(
|
||||
input_size, output_size, crop, rotation, center_after_cropping,
|
||||
force_aspect_ratio, aspect, force_integer_scaling, overscale);
|
||||
return transform(x, vec2(0.5), output_size / scale_i2o,
|
||||
get_input_center(input_size, output_size, scale_i2o, crop,
|
||||
shift, rotation, center_after_cropping));
|
||||
}
|
||||
|
||||
// From pixel input to unit output space.
|
||||
// Version where scale is passed in.
|
||||
vec2 i2o(vec2 x, vec2 input_size, vec4 crop, vec2 shift, uint rotation,
|
||||
float center_after_cropping, vec2 scale_o2i) {
|
||||
return (x - get_input_center(input_size, crop, shift, rotation,
|
||||
center_after_cropping)) /
|
||||
scale_o2i +
|
||||
0.49999;
|
||||
}
|
||||
|
||||
// Version that computes scale.
|
||||
vec2 i2o(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, vec2 shift,
|
||||
uint rotation, float center_after_cropping, float force_aspect_ratio,
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale,
|
||||
bool output_size_is_final_viewport_size) {
|
||||
return i2o(x, input_size, crop, shift, rotation, center_after_cropping,
|
||||
get_scale_o2i(input_size, output_size, crop, rotation,
|
||||
center_after_cropping, force_aspect_ratio, aspect,
|
||||
force_integer_scaling, overscale,
|
||||
output_size_is_final_viewport_size));
|
||||
vec2 aspect, vec2 force_integer_scaling, float overscale) {
|
||||
const vec2 scale_i2o = get_scale_i2o(
|
||||
input_size, output_size, crop, rotation, center_after_cropping,
|
||||
force_aspect_ratio, aspect, force_integer_scaling, overscale);
|
||||
return transform(x,
|
||||
get_input_center(input_size, output_size, scale_i2o, crop,
|
||||
shift, rotation, center_after_cropping),
|
||||
scale_i2o / output_size, vec2(0.5));
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#pragma parameter OS_CROP_RIGHT "Overscan crop right" 0.0 0.0 1024.0 1.0
|
||||
|
||||
#pragma parameter MOVING_SETTINGS "= Moving parameters =" 0.0 0.0 1.0 1.0
|
||||
#pragma parameter SHIFT_H "Horizontal shift" 0.0 -1024.0 1024.0 0.5
|
||||
#pragma parameter SHIFT_V "Vertical shift" 0.0 -1024.0 1024.0 0.5
|
||||
#pragma parameter SHIFT_H "Horizontal shift" 0.0 -2048.0 2048.0 1.0
|
||||
#pragma parameter SHIFT_V "Vertical shift" 0.0 -2048.0 2048.0 1.0
|
||||
#pragma parameter CENTER_AFTER_CROPPING "Center cropped area" 1.0 0.0 1.0 1.0
|
||||
// clang-format on
|
||||
|
5
pixel-art-scaling/box_filter_aa_xform.slangp
Normal file
5
pixel-art-scaling/box_filter_aa_xform.slangp
Normal file
@ -0,0 +1,5 @@
|
||||
shaders = 1
|
||||
|
||||
shader0 = shaders/box_filter_aa/box_filter_aa_xform.slang
|
||||
filter_linear0 = false
|
||||
scale_type0 = viewport
|
@ -0,0 +1,136 @@
|
||||
#version 450
|
||||
|
||||
/*
|
||||
Box Filter AA v1.0 by fishku
|
||||
Copyright (C) 2024
|
||||
Public domain license (CC0)
|
||||
|
||||
Branching-free anti-aliasing using pixel coverage.
|
||||
|
||||
Changelog:
|
||||
v1.0: Initial release.
|
||||
*/
|
||||
|
||||
// clang-format off
|
||||
#include "../../../misc/shaders/input_transform/parameters.inc"
|
||||
|
||||
#include "../../../misc/shaders/coverage/coverage.inc"
|
||||
#include "../../../misc/shaders/input_transform/input_transform.inc"
|
||||
// clang-format on
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 SourceSize;
|
||||
vec4 OutputSize;
|
||||
uint Rotation;
|
||||
// From input transform library, scaling section
|
||||
float FORCE_ASPECT_RATIO;
|
||||
float ASPECT_H;
|
||||
float ASPECT_V;
|
||||
float FORCE_INTEGER_SCALING_H;
|
||||
float FORCE_INTEGER_SCALING_V;
|
||||
float OVERSCALE;
|
||||
// From input transform library, cropping section
|
||||
float OS_CROP_TOP;
|
||||
float OS_CROP_BOTTOM;
|
||||
float OS_CROP_LEFT;
|
||||
float OS_CROP_RIGHT;
|
||||
// From input transform library, moving section
|
||||
float SHIFT_H;
|
||||
float SHIFT_V;
|
||||
float CENTER_AFTER_CROPPING;
|
||||
}
|
||||
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 vec4 px_rect;
|
||||
layout(location = 1) out vec4 input_corners;
|
||||
layout(location = 2) out vec2 scale_i2o;
|
||||
layout(location = 3) out vec2 input_center;
|
||||
layout(location = 4) out vec2 output_center;
|
||||
layout(location = 5) out vec2 tx_coord;
|
||||
void main() {
|
||||
gl_Position = global.MVP * Position;
|
||||
|
||||
px_rect = vec4(TexCoord * param.OutputSize.xy - 0.5,
|
||||
TexCoord * param.OutputSize.xy + 0.5);
|
||||
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||
scale_i2o = get_scale_i2o(
|
||||
param.SourceSize.xy, param.OutputSize.xy, crop, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
||||
vec2(param.ASPECT_H, param.ASPECT_V),
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V),
|
||||
param.OVERSCALE);
|
||||
const vec2 shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
input_center = get_input_center(param.SourceSize.xy, param.OutputSize.xy,
|
||||
scale_i2o, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING);
|
||||
tx_coord = transform(TexCoord, vec2(0.5), param.OutputSize.xy / scale_i2o,
|
||||
input_center);
|
||||
output_center = 0.5 * param.OutputSize.xy;
|
||||
input_corners =
|
||||
get_input_corners(param.SourceSize.xy, crop, param.Rotation);
|
||||
}
|
||||
|
||||
#pragma stage fragment
|
||||
layout(location = 0) in vec4 px_rect;
|
||||
layout(location = 1) in vec4 input_corners;
|
||||
layout(location = 2) in vec2 scale_i2o;
|
||||
layout(location = 3) in vec2 input_center;
|
||||
layout(location = 4) in vec2 output_center;
|
||||
layout(location = 5) in vec2 tx_coord;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||
|
||||
void main() {
|
||||
// Figure out 4 nearest texels in source texture.
|
||||
// Clamp tx_coord for proper cropping.
|
||||
vec2 tx_coord_i;
|
||||
const vec2 tx_coord_f =
|
||||
modf(clamp(tx_coord, input_corners.xy, input_corners.zw), tx_coord_i);
|
||||
const vec2 tx_coord_off = step(vec2(0.5), tx_coord_f) * 2.0 - 1.0;
|
||||
vec2 tx_origins[] = {tx_coord_i, tx_coord_i + vec2(tx_coord_off.x, 0.0),
|
||||
tx_coord_i + vec2(0.0, tx_coord_off.y),
|
||||
tx_coord_i + tx_coord_off};
|
||||
|
||||
// Sample.
|
||||
// Apply square for fast "gamma correction".
|
||||
vec3 samples[] = {
|
||||
texture(Source, (tx_origins[0] + 0.5) * param.SourceSize.zw).rgb,
|
||||
texture(Source, (tx_origins[1] + 0.5) * param.SourceSize.zw).rgb,
|
||||
texture(Source, (tx_origins[2] + 0.5) * param.SourceSize.zw).rgb,
|
||||
texture(Source, (tx_origins[3] + 0.5) * param.SourceSize.zw).rgb};
|
||||
samples[0] *= samples[0];
|
||||
samples[1] *= samples[1];
|
||||
samples[2] *= samples[2];
|
||||
samples[3] *= samples[3];
|
||||
|
||||
// Apply shader.
|
||||
// Transform tx_origins into pixel output space.
|
||||
tx_origins[0] =
|
||||
transform(tx_origins[0], input_center, scale_i2o, output_center);
|
||||
tx_origins[1] =
|
||||
transform(tx_origins[1], input_center, scale_i2o, output_center);
|
||||
tx_origins[2] =
|
||||
transform(tx_origins[2], input_center, scale_i2o, output_center);
|
||||
tx_origins[3] =
|
||||
transform(tx_origins[3], input_center, scale_i2o, output_center);
|
||||
|
||||
const vec3 res =
|
||||
samples[0] * rect_coverage(px_rect, vec4(tx_origins[0],
|
||||
tx_origins[0] + scale_i2o)) +
|
||||
samples[1] * rect_coverage(px_rect, vec4(tx_origins[1],
|
||||
tx_origins[1] + scale_i2o)) +
|
||||
samples[2] * rect_coverage(px_rect, vec4(tx_origins[2],
|
||||
tx_origins[2] + scale_i2o)) +
|
||||
samples[3] * rect_coverage(px_rect, vec4(tx_origins[3],
|
||||
tx_origins[3] + scale_i2o));
|
||||
|
||||
// Apply sqrt for fast "gamma correction".
|
||||
FragColor = vec4(sqrt(res), 1.0);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
// See pixel_aa.slang for copyright and other information.
|
||||
|
||||
// clang-format off
|
||||
#pragma parameter PIX_AA_SETTINGS "=== Pixel AA v1.5 settings ===" 0.0 0.0 1.0 1.0
|
||||
#pragma parameter PIX_AA_SETTINGS "=== Pixel AA v1.6 settings ===" 0.0 0.0 1.0 1.0
|
||||
#pragma parameter PIX_AA_SHARP "Pixel AA sharpening amount" 1.5 0.0 2.0 0.05
|
||||
#pragma parameter PIX_AA_GAMMA "Enable gamma-correct blending" 1.0 0.0 1.0 1.0
|
||||
#pragma parameter PIX_AA_SUBPX "Enable subpixel AA" 0.0 0.0 1.0 1.0
|
||||
|
@ -1,8 +1,8 @@
|
||||
#version 450
|
||||
|
||||
/*
|
||||
Pixel AA v1.5 by fishku
|
||||
Copyright (C) 2023
|
||||
Pixel AA v1.6 by fishku
|
||||
Copyright (C) 2023-2024
|
||||
Public domain license (CC0)
|
||||
|
||||
Features:
|
||||
@ -24,6 +24,7 @@
|
||||
subpixel anti-aliasing, results are identical to the "pixellate" shader.
|
||||
|
||||
Changelog:
|
||||
v1.6: Update input transform library.
|
||||
v1.5: Upstream optimizations from GLSL port. Add free transform preset.
|
||||
v1.4: Enable subpixel sampling for all four pixel layout orientations,
|
||||
including rotated screens.
|
||||
|
@ -44,37 +44,39 @@ global;
|
||||
#pragma stage vertex
|
||||
layout(location = 0) in vec4 Position;
|
||||
layout(location = 1) in vec2 TexCoord;
|
||||
layout(location = 0) out vec2 tx_coord;
|
||||
layout(location = 1) out vec2 tx_per_px;
|
||||
layout(location = 2) out vec2 tx_to_uv;
|
||||
layout(location = 3) out vec4 input_corners;
|
||||
layout(location = 0) out vec4 input_corners;
|
||||
layout(location = 1) out vec2 tx_coord;
|
||||
layout(location = 2) out vec2 tx_per_px;
|
||||
layout(location = 3) out vec2 tx_to_uv;
|
||||
|
||||
void main() {
|
||||
gl_Position = global.MVP * Position;
|
||||
|
||||
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||
const vec2 scale_o2i = get_scale_o2i(
|
||||
const vec2 scale_i2o = get_scale_i2o(
|
||||
param.SourceSize.xy, param.OutputSize.xy, crop, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, param.FORCE_ASPECT_RATIO,
|
||||
vec2(param.ASPECT_H, param.ASPECT_V),
|
||||
vec2(param.FORCE_INTEGER_SCALING_H, param.FORCE_INTEGER_SCALING_V),
|
||||
param.OVERSCALE,
|
||||
/* output_size_is_final_viewport_size = */ false);
|
||||
param.OVERSCALE);
|
||||
const vec2 shift = vec2(param.SHIFT_H, param.SHIFT_V);
|
||||
tx_coord = o2i(TexCoord, param.SourceSize.xy, crop, shift, param.Rotation,
|
||||
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||
tx_per_px = scale_o2i * param.OutputSize.zw;
|
||||
const vec2 input_center = get_input_center(
|
||||
param.SourceSize.xy, param.OutputSize.xy, scale_i2o, crop, shift,
|
||||
param.Rotation, param.CENTER_AFTER_CROPPING);
|
||||
tx_coord = transform(TexCoord, vec2(0.5), param.OutputSize.xy / scale_i2o,
|
||||
input_center);
|
||||
tx_per_px = 1.0 / scale_i2o;
|
||||
tx_to_uv = param.SourceSize.zw;
|
||||
input_corners =
|
||||
get_input_corners(param.SourceSize.xy, crop, param.Rotation);
|
||||
}
|
||||
|
||||
#pragma stage fragment
|
||||
layout(location = 0) in vec2 tx_coord;
|
||||
layout(location = 1) in vec2 tx_per_px;
|
||||
layout(location = 2) in vec2 tx_to_uv;
|
||||
layout(location = 3) in vec4 input_corners;
|
||||
layout(location = 0) in vec4 input_corners;
|
||||
layout(location = 1) in vec2 tx_coord;
|
||||
layout(location = 2) in vec2 tx_per_px;
|
||||
layout(location = 3) in vec2 tx_to_uv;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user