mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-22 15:51:30 +11:00
Correctly account for screen rotation in several shaders (#478)
* Refactor scaling into include library Add separate H and V integer scale forcing Fix blur_fill; average fill still TODO Clean up and fix blur_fill; Initial docs; Avg fill TODO Mostly fix avg. fill; sampling TODO; Bump versions, add docs Fix H/V extension; Tweak default params Fix avg. fill Remove defines, create functions Reorder params Clean up Fix pixel_aa subpx sampling with rotation * Minor docs fix
This commit is contained in:
parent
eca36c3b04
commit
e366c7524c
|
@ -1,7 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Average fill v1.5 by fishku
|
Average fill v1.6 by fishku
|
||||||
Copyright (C) 2023
|
Copyright (C) 2023
|
||||||
Public domain license (CC0)
|
Public domain license (CC0)
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
3 = Smooth angle-based blending
|
3 = Smooth angle-based blending
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
v1.6: Refactor for new scaling library. Add rotation support.
|
||||||
v1.5: Optimize. Update to new Pixel AA version.
|
v1.5: Optimize. Update to new Pixel AA version.
|
||||||
v1.4: Add anti-aliased interpolation for non-integer scaling.
|
v1.4: Add anti-aliased interpolation for non-integer scaling.
|
||||||
v1.3: Fix scaling bugs.
|
v1.3: Fix scaling bugs.
|
||||||
|
@ -37,17 +38,21 @@
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include "parameters.slang"
|
#include "parameters.slang"
|
||||||
#include "../../../pixel-art-scaling/shaders/pixel_aa/shared.slang"
|
#include "../../../pixel-art-scaling/shaders/pixel_aa/parameters.slang"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
#include "../../../misc/shaders/scaling.slang"
|
||||||
|
#include "../../../pixel-art-scaling/shaders/pixel_aa/shared.slang"
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
vec4 InputSize;
|
vec4 InputSize;
|
||||||
vec4 FinalViewportSize;
|
vec4 OutputSize;
|
||||||
|
uint Rotation;
|
||||||
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 CENTER_CROP;
|
float CENTER_AFTER_CROPPING;
|
||||||
float SAMPLE_SIZE;
|
float SAMPLE_SIZE;
|
||||||
float EXTEND_H;
|
float EXTEND_H;
|
||||||
float EXTEND_V;
|
float EXTEND_V;
|
||||||
|
@ -55,7 +60,8 @@ layout(push_constant) uniform Push {
|
||||||
float FORCE_ASPECT_RATIO;
|
float FORCE_ASPECT_RATIO;
|
||||||
float ASPECT_H;
|
float ASPECT_H;
|
||||||
float ASPECT_V;
|
float ASPECT_V;
|
||||||
float FORCE_INTEGER_SCALING;
|
float FORCE_INTEGER_SCALING_H;
|
||||||
|
float FORCE_INTEGER_SCALING_V;
|
||||||
float FILL_GAMMA;
|
float FILL_GAMMA;
|
||||||
// From pixel AA
|
// From pixel AA
|
||||||
float PIX_AA_SHARP;
|
float PIX_AA_SHARP;
|
||||||
|
@ -64,8 +70,6 @@ layout(push_constant) uniform Push {
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
|
||||||
|
@ -73,24 +77,46 @@ global;
|
||||||
layout(location = 0) in vec4 Position;
|
layout(location = 0) in vec4 Position;
|
||||||
layout(location = 1) in vec2 TexCoord;
|
layout(location = 1) in vec2 TexCoord;
|
||||||
layout(location = 0) out vec2 vTexCoord;
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
layout(location = 1) out vec2 tx_coord;
|
layout(location = 1) out vec2 scale_o2i;
|
||||||
layout(location = 2) out vec2 tx_per_px;
|
layout(location = 2) out vec4 crop;
|
||||||
layout(location = 3) out vec2 tx_to_uv;
|
layout(location = 3) out vec2 tx_coord;
|
||||||
|
layout(location = 4) out vec2 tx_per_px;
|
||||||
|
layout(location = 5) out vec2 tx_to_uv;
|
||||||
|
layout(location = 6) out vec4 input_corners;
|
||||||
|
layout(location = 7) out vec2 cropped_input_size;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = global.MVP * Position;
|
gl_Position = global.MVP * Position;
|
||||||
vTexCoord = TexCoord;
|
vTexCoord = TexCoord;
|
||||||
const vec2 scale_o2i = scale_o2i();
|
crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT, param.OS_CROP_BOTTOM,
|
||||||
tx_coord = (vTexCoord - 0.49999) * scale_o2i + get_input_center();
|
param.OS_CROP_RIGHT);
|
||||||
tx_per_px = scale_o2i * param.FinalViewportSize.zw;
|
scale_o2i = get_scale_o2i(
|
||||||
|
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),
|
||||||
|
/* output_size_is_final_viewport_size = */ false);
|
||||||
|
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
|
tx_per_px = scale_o2i * param.OutputSize.zw;
|
||||||
tx_to_uv = param.InputSize.zw;
|
tx_to_uv = param.InputSize.zw;
|
||||||
|
|
||||||
|
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||||
|
const vec4 rotated_crop = get_rotated_crop(crop, param.Rotation);
|
||||||
|
cropped_input_size =
|
||||||
|
param.InputSize.xy -
|
||||||
|
vec2(rotated_crop.y + rotated_crop.w, rotated_crop.x + rotated_crop.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma stage fragment
|
#pragma stage fragment
|
||||||
layout(location = 0) in vec2 vTexCoord;
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
layout(location = 1) in vec2 tx_coord;
|
layout(location = 1) in vec2 scale_o2i;
|
||||||
layout(location = 2) in vec2 tx_per_px;
|
layout(location = 2) in vec4 crop;
|
||||||
layout(location = 3) in vec2 tx_to_uv;
|
layout(location = 3) in vec2 tx_coord;
|
||||||
|
layout(location = 4) in vec2 tx_per_px;
|
||||||
|
layout(location = 5) in vec2 tx_to_uv;
|
||||||
|
layout(location = 6) in vec4 input_corners;
|
||||||
|
layout(location = 7) in vec2 cropped_input_size;
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
layout(set = 0, binding = 2) uniform sampler2D Input;
|
layout(set = 0, binding = 2) uniform sampler2D Input;
|
||||||
layout(set = 0, binding = 3) uniform sampler2D Top;
|
layout(set = 0, binding = 3) uniform sampler2D Top;
|
||||||
|
@ -137,68 +163,65 @@ vec3 blend_corner(vec3 a, // The first color to blend
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (tx_coord.x < param.OS_CROP_LEFT) {
|
const vec2 extend_fill =
|
||||||
if (param.EXTEND_H < 0.5) {
|
get_rotated_size(vec2(param.EXTEND_H, param.EXTEND_V), param.Rotation);
|
||||||
|
if (tx_coord.x < input_corners.x) {
|
||||||
|
if (extend_fill.x < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb;
|
const vec3 left = textureLod(Left, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
if (tx_coord.y < param.OS_CROP_TOP) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
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 =
|
const vec2 content_corner =
|
||||||
i2o(vec2(param.OS_CROP_LEFT, param.OS_CROP_TOP));
|
i2o(input_corners.xy, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
const vec2 viewport_corner = vec2(0.0, 0.0);
|
const vec2 viewport_corner = vec2(0.0, 0.0);
|
||||||
FragColor =
|
FragColor = vec4(
|
||||||
vec4(blend_corner(left, top,
|
blend_corner(left, top, cropped_input_size.y,
|
||||||
param.InputSize.y - param.OS_CROP_TOP -
|
cropped_input_size.x, vTexCoord, content_corner,
|
||||||
param.OS_CROP_BOTTOM,
|
viewport_corner - content_corner),
|
||||||
param.InputSize.x - param.OS_CROP_LEFT -
|
1.0);
|
||||||
param.OS_CROP_RIGHT,
|
|
||||||
vTexCoord, content_corner,
|
|
||||||
viewport_corner - content_corner),
|
|
||||||
1.0);
|
|
||||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
} else if (tx_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
// Left bar
|
// Left bar
|
||||||
FragColor = vec4(pow(left, vec3(param.FILL_GAMMA)), 1.0);
|
FragColor = vec4(pow(left, vec3(param.FILL_GAMMA)), 1.0);
|
||||||
} else {
|
} else {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
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;
|
||||||
const vec2 content_corner = i2o(vec2(
|
const vec2 content_corner =
|
||||||
param.OS_CROP_LEFT, param.InputSize.y - param.OS_CROP_BOTTOM));
|
i2o(input_corners.xw, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
const vec2 viewport_corner = vec2(0.0, 1.0);
|
const vec2 viewport_corner = vec2(0.0, 1.0);
|
||||||
FragColor =
|
FragColor = vec4(
|
||||||
vec4(blend_corner(left, bottom,
|
blend_corner(left, bottom, cropped_input_size.y,
|
||||||
param.InputSize.y - param.OS_CROP_TOP -
|
cropped_input_size.x, vTexCoord, content_corner,
|
||||||
param.OS_CROP_BOTTOM,
|
viewport_corner - content_corner),
|
||||||
param.InputSize.x - param.OS_CROP_LEFT -
|
1.0);
|
||||||
param.OS_CROP_RIGHT,
|
|
||||||
vTexCoord, content_corner,
|
|
||||||
viewport_corner - content_corner),
|
|
||||||
1.0);
|
|
||||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
}
|
}
|
||||||
} else if (tx_coord.x < param.InputSize.x - param.OS_CROP_RIGHT) {
|
} else if (tx_coord.x < input_corners.z) {
|
||||||
if (tx_coord.y < param.OS_CROP_TOP) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
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));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
} else if (tx_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
// Uncropped
|
// Uncropped
|
||||||
if (param.FORCE_INTEGER_SCALING > 0.5) {
|
if (param.FORCE_INTEGER_SCALING_H > 0.5 &&
|
||||||
|
param.FORCE_INTEGER_SCALING_V > 0.5) {
|
||||||
// Do a perfectly sharp (nearest neighbor) sampling.
|
// Do a perfectly sharp (nearest neighbor) sampling.
|
||||||
FragColor = vec4(
|
FragColor = vec4(
|
||||||
texture(Input, (floor(tx_coord) + 0.5) * param.InputSize.zw)
|
texture(Input, (floor(tx_coord) + 0.5) * param.InputSize.zw)
|
||||||
|
@ -211,10 +234,10 @@ void main() {
|
||||||
FragColor = pixel_aa(
|
FragColor = pixel_aa(
|
||||||
Input, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
Input, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
||||||
/* gamma_correct = */ false, param.PIX_AA_SUBPX > 0.5,
|
/* gamma_correct = */ false, param.PIX_AA_SUBPX > 0.5,
|
||||||
param.PIX_AA_SUBPX_BGR > 0.5);
|
param.PIX_AA_SUBPX_BGR > 0.5, param.Rotation);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -224,54 +247,47 @@ void main() {
|
||||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (param.EXTEND_H < 0.5) {
|
if (extend_fill.x < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb;
|
const vec3 right = textureLod(Right, vec2(0.5), BIG_NUMBER).rgb;
|
||||||
if (tx_coord.y < param.OS_CROP_TOP) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
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(
|
const vec2 content_corner =
|
||||||
param.InputSize.x - param.OS_CROP_RIGHT, param.OS_CROP_TOP));
|
i2o(input_corners.zy, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
const vec2 viewport_corner = vec2(1.0, 0.0);
|
const vec2 viewport_corner = vec2(1.0, 0.0);
|
||||||
FragColor =
|
FragColor = vec4(
|
||||||
vec4(blend_corner(right, top,
|
blend_corner(right, top, cropped_input_size.y,
|
||||||
param.InputSize.y - param.OS_CROP_TOP -
|
cropped_input_size.x, vTexCoord, content_corner,
|
||||||
param.OS_CROP_BOTTOM,
|
viewport_corner - content_corner),
|
||||||
param.InputSize.x - param.OS_CROP_LEFT -
|
1.0);
|
||||||
param.OS_CROP_RIGHT,
|
|
||||||
vTexCoord, content_corner,
|
|
||||||
viewport_corner - content_corner),
|
|
||||||
1.0);
|
|
||||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
} else if (tx_coord.y < param.InputSize.y - param.OS_CROP_BOTTOM) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
// Right bar
|
// Right bar
|
||||||
FragColor = vec4(pow(right, vec3(param.FILL_GAMMA)), 1.0);
|
FragColor = vec4(pow(right, vec3(param.FILL_GAMMA)), 1.0);
|
||||||
} else {
|
} else {
|
||||||
if (param.EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
FragColor = vec4(0.0, 0.0, 0.0, 1.0);
|
||||||
return;
|
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;
|
||||||
const vec2 content_corner =
|
const vec2 content_corner =
|
||||||
i2o(vec2(param.InputSize.x - param.OS_CROP_RIGHT,
|
i2o(input_corners.zw, param.InputSize.xy, crop, param.Rotation,
|
||||||
param.InputSize.y - param.OS_CROP_BOTTOM));
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
const vec2 viewport_corner = vec2(1.0, 1.0);
|
const vec2 viewport_corner = vec2(1.0, 1.0);
|
||||||
FragColor =
|
FragColor = vec4(
|
||||||
vec4(blend_corner(right, bottom,
|
blend_corner(right, bottom, cropped_input_size.y,
|
||||||
param.InputSize.y - param.OS_CROP_TOP -
|
cropped_input_size.x, vTexCoord, content_corner,
|
||||||
param.OS_CROP_BOTTOM,
|
viewport_corner - content_corner),
|
||||||
param.InputSize.x - param.OS_CROP_LEFT -
|
1.0);
|
||||||
param.OS_CROP_RIGHT,
|
|
||||||
vTexCoord, content_corner,
|
|
||||||
viewport_corner - content_corner),
|
|
||||||
1.0);
|
|
||||||
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
FragColor.rgb = pow(FragColor.rgb, vec3(param.FILL_GAMMA));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
#include "parameters.slang"
|
// Crop is rotated already.
|
||||||
|
vec4 get_effective_corners(vec4 crop, vec4 input_size, float sample_size) {
|
||||||
// clang-format off
|
return input_size.zwzw * vec4(crop.y, //
|
||||||
#define EFF_CROP_TOP (param.InputSize.y - param.OS_CROP_BOTTOM - param.SAMPLE_SIZE)
|
input_size.y - crop.z - sample_size, //
|
||||||
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
input_size.x - crop.w, //
|
||||||
#define EFF_CROP_LEFT (param.OS_CROP_LEFT)
|
input_size.y - crop.z);
|
||||||
#define EFF_CROP_RIGHT (param.OS_CROP_RIGHT)
|
}
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
#include "crop_and_sample_common.slang"
|
#include "crop_and_sample_common.slang"
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "../../../misc/shaders/scaling.slang"
|
||||||
|
#include "parameters.slang"
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
vec4 InputSize;
|
vec4 InputSize;
|
||||||
vec4 OriginalSize;
|
uint Rotation;
|
||||||
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;
|
||||||
|
@ -23,10 +24,13 @@ layout(location = 0) out vec2 vTexCoord;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = global.MVP * Position;
|
gl_Position = global.MVP * Position;
|
||||||
vTexCoord =
|
const vec4 rotated_crop =
|
||||||
mix(vec2(EFF_CROP_LEFT, EFF_CROP_TOP) * param.InputSize.zw,
|
get_rotated_crop(vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||||
1.0 - vec2(EFF_CROP_RIGHT, EFF_CROP_BOTTOM) * param.InputSize.zw,
|
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT),
|
||||||
TexCoord);
|
param.Rotation);
|
||||||
|
const vec4 effective_corners =
|
||||||
|
get_effective_corners(rotated_crop, param.InputSize, param.SAMPLE_SIZE);
|
||||||
|
vTexCoord = mix(effective_corners.xy, effective_corners.zw, TexCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma stage fragment
|
#pragma stage fragment
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
#include "parameters.slang"
|
vec4 get_effective_corners(vec4 crop, vec4 input_size, float sample_size) {
|
||||||
|
return input_size.zwzw * vec4(crop.y, //
|
||||||
// clang-format off
|
crop.x, //
|
||||||
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
crop.y + sample_size, //
|
||||||
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
input_size.y - crop.z);
|
||||||
#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"
|
#include "crop_and_sample_common.slang"
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
#include "parameters.slang"
|
vec4 get_effective_corners(vec4 crop, vec4 input_size, float sample_size) {
|
||||||
|
return input_size.zwzw * vec4(input_size.x - crop.w - sample_size, //
|
||||||
// clang-format off
|
crop.x, //
|
||||||
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
input_size.x - crop.w, //
|
||||||
#define EFF_CROP_BOTTOM (param.OS_CROP_BOTTOM)
|
input_size.y - crop.z);
|
||||||
#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"
|
#include "crop_and_sample_common.slang"
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
|
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
#include "parameters.slang"
|
vec4 get_effective_corners(vec4 crop, vec4 input_size, float sample_size) {
|
||||||
|
return input_size.zwzw * vec4(crop.y, //
|
||||||
// clang-format off
|
crop.x, //
|
||||||
#define EFF_CROP_TOP (param.OS_CROP_TOP)
|
input_size.x - crop.w, //
|
||||||
#define EFF_CROP_BOTTOM (param.InputSize.y - param.OS_CROP_TOP - param.SAMPLE_SIZE)
|
crop.x + 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"
|
#include "crop_and_sample_common.slang"
|
||||||
|
|
|
@ -1,25 +1,30 @@
|
||||||
// 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.5 settings ===" 0.0 0.0 1.0 1.0
|
#pragma parameter AVERAGE_FILL_SETTINGS "=== Average fill v1.6 settings ===" 0.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
#pragma parameter SCALING_SETTINGS "= Scaling parameters =" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter FORCE_ASPECT_RATIO "Force aspect ratio" 1.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter ASPECT_H "Horizontal aspect ratio before crop (0 = unchanged)" 0.0 0.0 256.0 1.0
|
||||||
|
#pragma parameter ASPECT_V "Vertical aspect ratio before crop (0 = unchanged)" 0.0 0.0 256.0 1.0
|
||||||
|
#pragma parameter FORCE_INTEGER_SCALING_H "Force integer scaling horizontally" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter FORCE_INTEGER_SCALING_V "Force integer scaling vertically" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
#pragma parameter CROPPING_SETTINGS "= Cropping parameters =" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter OS_CROP_TOP "Overscan crop top" 0.0 0.0 1024.0 1.0
|
#pragma parameter OS_CROP_TOP "Overscan crop top" 0.0 0.0 1024.0 1.0
|
||||||
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 0.0 0.0 1024.0 1.0
|
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 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_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 CENTER_CROP "Center cropped area" 1.0 0.0 1.0 1.0
|
#pragma parameter CENTER_AFTER_CROPPING "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 OTHER_SETTINGS "= Other parameters =" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter EXTEND_H "Extend the fill horizontally" 1.0 0.0 1.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 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 CORNER_BLEND_MODE "Cropped corner blend mode" 0.0 0.0 3.0 1.0
|
||||||
|
|
||||||
#pragma parameter FORCE_ASPECT_RATIO "Force aspect ratio" 1.0 0.0 1.0 1.0
|
|
||||||
#pragma parameter ASPECT_H "Horizontal aspect ratio before crop (0 = original)" 0.0 0.0 256.0 1.0
|
|
||||||
#pragma parameter ASPECT_V "Vertical aspect ratio before crop (0 = original)" 0.0 0.0 256.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
|
#pragma parameter FILL_GAMMA "Background fill gamma adjustment" 1.0 0.5 2.0 0.1
|
||||||
|
|
||||||
|
#pragma parameter SAMPLE_SIZE "No. of lines for calculating the average" 8.0 1.0 64.0 1.0
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Blur fill v1.6 by fishku
|
Blur fill v1.7 by fishku
|
||||||
Copyright (C) 2023
|
Copyright (C) 2023
|
||||||
Public domain license (CC0)
|
Public domain license (CC0)
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
strength of the blur.
|
strength of the blur.
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
v1.7: Refactor for new scaling library. Add rotation support.
|
||||||
v1.6: Optimize. Update to new Pixel AA version. Tune default blur strength.
|
v1.6: Optimize. Update to new Pixel AA version. Tune default blur strength.
|
||||||
v1.5: Add anti-aliased interpolation for non-integer scaling.
|
v1.5: Add anti-aliased interpolation for non-integer scaling.
|
||||||
v1.4: Fix scaling bugs.
|
v1.4: Fix scaling bugs.
|
||||||
|
@ -39,23 +40,28 @@
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#include "parameters.slang"
|
#include "parameters.slang"
|
||||||
#include "../../../blurs/shaders/dual_filter/parameters.slang"
|
#include "../../../blurs/shaders/dual_filter/parameters.slang"
|
||||||
#include "../../../pixel-art-scaling/shaders/pixel_aa/shared.slang"
|
#include "../../../pixel-art-scaling/shaders/pixel_aa/parameters.slang"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
#include "../../../misc/shaders/scaling.slang"
|
||||||
|
#include "../../../pixel-art-scaling/shaders/pixel_aa/shared.slang"
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
vec4 InputSize;
|
vec4 InputSize;
|
||||||
vec4 TiledSize;
|
vec4 TiledSize;
|
||||||
vec4 FinalViewportSize;
|
vec4 OutputSize;
|
||||||
|
uint Rotation;
|
||||||
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 CENTER_CROP;
|
float CENTER_AFTER_CROPPING;
|
||||||
float SAMPLE_SIZE;
|
float SAMPLE_SIZE;
|
||||||
float FORCE_ASPECT_RATIO;
|
float FORCE_ASPECT_RATIO;
|
||||||
float ASPECT_H;
|
float ASPECT_H;
|
||||||
float ASPECT_V;
|
float ASPECT_V;
|
||||||
float FORCE_INTEGER_SCALING;
|
float FORCE_INTEGER_SCALING_H;
|
||||||
|
float FORCE_INTEGER_SCALING_V;
|
||||||
float FILL_GAMMA;
|
float FILL_GAMMA;
|
||||||
// From dual filter blur
|
// From dual filter blur
|
||||||
float BLUR_RADIUS;
|
float BLUR_RADIUS;
|
||||||
|
@ -66,8 +72,6 @@ layout(push_constant) uniform Push {
|
||||||
}
|
}
|
||||||
param;
|
param;
|
||||||
|
|
||||||
#include "scaling.slang"
|
|
||||||
|
|
||||||
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
||||||
global;
|
global;
|
||||||
|
|
||||||
|
@ -78,18 +82,24 @@ layout(location = 0) out vec2 vTexCoord;
|
||||||
layout(location = 1) out vec2 tx_coord;
|
layout(location = 1) out vec2 tx_coord;
|
||||||
layout(location = 2) out vec2 tx_per_px;
|
layout(location = 2) out vec2 tx_per_px;
|
||||||
layout(location = 3) out vec2 tx_to_uv;
|
layout(location = 3) out vec2 tx_to_uv;
|
||||||
layout(location = 4) out vec4 input_extrema;
|
layout(location = 4) out vec4 input_corners;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = global.MVP * Position;
|
gl_Position = global.MVP * Position;
|
||||||
vTexCoord = TexCoord;
|
vTexCoord = TexCoord;
|
||||||
const vec2 scale_o2i = scale_o2i();
|
const vec4 crop = vec4(param.OS_CROP_TOP, param.OS_CROP_LEFT,
|
||||||
tx_coord = (vTexCoord - 0.49999) * scale_o2i + get_input_center();
|
param.OS_CROP_BOTTOM, param.OS_CROP_RIGHT);
|
||||||
tx_per_px = scale_o2i * param.FinalViewportSize.zw;
|
const vec2 scale_o2i = get_scale_o2i(
|
||||||
|
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),
|
||||||
|
/* output_size_is_final_viewport_size = */ false);
|
||||||
|
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
|
tx_per_px = scale_o2i * param.OutputSize.zw;
|
||||||
tx_to_uv = param.InputSize.zw;
|
tx_to_uv = param.InputSize.zw;
|
||||||
input_extrema = vec4(param.OS_CROP_LEFT, param.OS_CROP_TOP,
|
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||||
param.InputSize.x - param.OS_CROP_RIGHT,
|
|
||||||
param.InputSize.y - param.OS_CROP_BOTTOM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma stage fragment
|
#pragma stage fragment
|
||||||
|
@ -97,15 +107,15 @@ layout(location = 0) in vec2 vTexCoord;
|
||||||
layout(location = 1) in vec2 tx_coord;
|
layout(location = 1) in vec2 tx_coord;
|
||||||
layout(location = 2) in vec2 tx_per_px;
|
layout(location = 2) in vec2 tx_per_px;
|
||||||
layout(location = 3) in vec2 tx_to_uv;
|
layout(location = 3) in vec2 tx_to_uv;
|
||||||
layout(location = 4) in vec4 input_extrema;
|
layout(location = 4) in vec4 input_corners;
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
layout(set = 0, binding = 2) uniform sampler2D Input;
|
layout(set = 0, binding = 2) uniform sampler2D Input;
|
||||||
layout(set = 0, binding = 3) uniform sampler2D Tiled;
|
layout(set = 0, binding = 3) uniform sampler2D Tiled;
|
||||||
layout(set = 0, binding = 4) uniform sampler2D Blurred;
|
layout(set = 0, binding = 4) uniform sampler2D Blurred;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
if (any(lessThan(tx_coord, input_extrema.xy)) ||
|
if (any(lessThan(tx_coord, input_corners.xy)) ||
|
||||||
any(greaterThanEqual(tx_coord, input_extrema.zw))) {
|
any(greaterThanEqual(tx_coord, input_corners.zw))) {
|
||||||
if (param.BLUR_RADIUS > 0.0) {
|
if (param.BLUR_RADIUS > 0.0) {
|
||||||
// Sample blur.
|
// Sample blur.
|
||||||
FragColor = vec4(
|
FragColor = vec4(
|
||||||
|
@ -113,7 +123,7 @@ void main() {
|
||||||
1.0);
|
1.0);
|
||||||
} else {
|
} else {
|
||||||
// Sample tiled pattern.
|
// Sample tiled pattern.
|
||||||
// Do a sharp (nearest neighbor) resampling.
|
// Do a perfectly sharp (nearest neighbor) resampling.
|
||||||
FragColor =
|
FragColor =
|
||||||
vec4(pow(texture(Tiled,
|
vec4(pow(texture(Tiled,
|
||||||
(floor(vTexCoord * param.TiledSize.xy) + 0.5) *
|
(floor(vTexCoord * param.TiledSize.xy) + 0.5) *
|
||||||
|
@ -124,7 +134,8 @@ void main() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Sample original.
|
// Sample original.
|
||||||
if (param.FORCE_INTEGER_SCALING > 0.5) {
|
if (param.FORCE_INTEGER_SCALING_H > 0.5 &&
|
||||||
|
param.FORCE_INTEGER_SCALING_V > 0.5) {
|
||||||
// Do a perfectly sharp (nearest neighbor) sampling.
|
// Do a perfectly sharp (nearest neighbor) sampling.
|
||||||
FragColor = vec4(
|
FragColor = vec4(
|
||||||
texture(Input, (floor(tx_coord) + 0.5) * param.InputSize.zw)
|
texture(Input, (floor(tx_coord) + 0.5) * param.InputSize.zw)
|
||||||
|
@ -137,7 +148,7 @@ void main() {
|
||||||
FragColor = pixel_aa(
|
FragColor = pixel_aa(
|
||||||
Input, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
Input, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
||||||
/* gamma_correct = */ false, param.PIX_AA_SUBPX > 0.5,
|
/* gamma_correct = */ false, param.PIX_AA_SUBPX > 0.5,
|
||||||
param.PIX_AA_SUBPX_BGR > 0.5);
|
param.PIX_AA_SUBPX_BGR > 0.5, param.Rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,30 @@
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#pragma parameter BLUR_FILL_SETTINGS "=== Blur fill v1.6 settings ===" 0.0 0.0 1.0 1.0
|
#pragma parameter BLUR_FILL_SETTINGS "=== Blur fill v1.7 settings ===" 0.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
#pragma parameter SCALING_SETTINGS "= Scaling parameters =" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter FORCE_ASPECT_RATIO "Force aspect ratio" 1.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter ASPECT_H "Horizontal aspect ratio before crop (0 = unchanged)" 0.0 0.0 256.0 1.0
|
||||||
|
#pragma parameter ASPECT_V "Vertical aspect ratio before crop (0 = unchanged)" 0.0 0.0 256.0 1.0
|
||||||
|
#pragma parameter FORCE_INTEGER_SCALING_H "Force integer scaling horizontally" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter FORCE_INTEGER_SCALING_V "Force integer scaling vertically" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
|
#pragma parameter CROPPING_SETTINGS "= Cropping parameters =" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter OS_CROP_TOP "Overscan crop top" 0.0 0.0 1024.0 1.0
|
#pragma parameter OS_CROP_TOP "Overscan crop top" 0.0 0.0 1024.0 1.0
|
||||||
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 0.0 0.0 1024.0 1.0
|
#pragma parameter OS_CROP_BOTTOM "Overscan crop bottom" 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_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 CENTER_CROP "Center cropped area" 1.0 0.0 1.0 1.0
|
#pragma parameter CENTER_AFTER_CROPPING "Center cropped area" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
#pragma parameter SAMPLE_SIZE "No. of lines for rendering the blur" 16.0 1.0 1024.0 1.0
|
#pragma parameter OTHER_SETTINGS "= Other parameters =" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter EXTEND_H "Extend the fill horizontally" 0.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 BLUR_EXTEND_H "Extend the blur horizontally" 1.0 0.0 1.0 1.0
|
|
||||||
#pragma parameter BLUR_EXTEND_V "Extend the blur vertically" 1.0 0.0 1.0 1.0
|
|
||||||
#pragma parameter MIRROR_BLUR "Mirror the blur" 0.0 0.0 1.0 1.0
|
#pragma parameter MIRROR_BLUR "Mirror the blur" 0.0 0.0 1.0 1.0
|
||||||
|
|
||||||
#pragma parameter FORCE_ASPECT_RATIO "Force aspect ratio" 1.0 0.0 1.0 1.0
|
|
||||||
#pragma parameter ASPECT_H "Horizontal aspect ratio before crop (0 = original)" 0.0 0.0 256.0 1.0
|
|
||||||
#pragma parameter ASPECT_V "Vertical aspect ratio before crop (0 = original)" 0.0 0.0 256.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.4 0.5 2.0 0.1
|
#pragma parameter FILL_GAMMA "Background fill gamma adjustment" 1.4 0.5 2.0 0.1
|
||||||
|
|
||||||
|
#pragma parameter SAMPLE_SIZE "No. of lines for rendering the blur" 16.0 1.0 1024.0 1.0
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -2,29 +2,30 @@
|
||||||
|
|
||||||
// See compose.slang for copyright and other information.
|
// See compose.slang for copyright and other information.
|
||||||
|
|
||||||
|
#include "../../../misc/shaders/scaling.slang"
|
||||||
#include "parameters.slang"
|
#include "parameters.slang"
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
vec4 InputSize;
|
vec4 InputSize;
|
||||||
vec4 FinalViewportSize;
|
vec4 FinalViewportSize;
|
||||||
|
uint Rotation;
|
||||||
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 CENTER_CROP;
|
float CENTER_AFTER_CROPPING;
|
||||||
float SAMPLE_SIZE;
|
float SAMPLE_SIZE;
|
||||||
float BLUR_EXTEND_H;
|
float EXTEND_H;
|
||||||
float BLUR_EXTEND_V;
|
float EXTEND_V;
|
||||||
float MIRROR_BLUR;
|
float MIRROR_BLUR;
|
||||||
float FORCE_ASPECT_RATIO;
|
float FORCE_ASPECT_RATIO;
|
||||||
float ASPECT_H;
|
float ASPECT_H;
|
||||||
float ASPECT_V;
|
float ASPECT_V;
|
||||||
float FORCE_INTEGER_SCALING;
|
float FORCE_INTEGER_SCALING_H;
|
||||||
|
float FORCE_INTEGER_SCALING_V;
|
||||||
}
|
}
|
||||||
param;
|
param;
|
||||||
|
|
||||||
#include "scaling.slang"
|
|
||||||
|
|
||||||
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; }
|
||||||
global;
|
global;
|
||||||
|
|
||||||
|
@ -32,14 +33,29 @@ global;
|
||||||
layout(location = 0) in vec4 Position;
|
layout(location = 0) in vec4 Position;
|
||||||
layout(location = 1) in vec2 TexCoord;
|
layout(location = 1) in vec2 TexCoord;
|
||||||
layout(location = 0) out vec2 vTexCoord;
|
layout(location = 0) out vec2 vTexCoord;
|
||||||
|
layout(location = 1) out vec2 tx_coord;
|
||||||
|
layout(location = 2) out vec4 input_corners;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = global.MVP * Position;
|
gl_Position = global.MVP * Position;
|
||||||
vTexCoord = TexCoord;
|
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,
|
||||||
|
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),
|
||||||
|
/* output_size_is_final_viewport_size = */ true);
|
||||||
|
tx_coord = o2i(vTexCoord, param.InputSize.xy, crop, param.Rotation,
|
||||||
|
param.CENTER_AFTER_CROPPING, scale_o2i);
|
||||||
|
input_corners = get_input_corners(param.InputSize.xy, crop, param.Rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma stage fragment
|
#pragma stage fragment
|
||||||
layout(location = 0) in vec2 vTexCoord;
|
layout(location = 0) in vec2 vTexCoord;
|
||||||
|
layout(location = 1) in vec2 tx_coord;
|
||||||
|
layout(location = 2) in vec4 input_corners;
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
layout(set = 0, binding = 2) uniform sampler2D Source;
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
|
||||||
|
@ -62,24 +78,24 @@ float mirrored_repeat(float w, float x) {
|
||||||
return period % 2 == 1 != x > 0.0 ? phase : w - phase;
|
return period % 2 == 1 != x > 0.0 ? phase : w - phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
float extend_left(vec2 coord, vec4 input_extrema) {
|
float extend_left(vec2 coord, vec4 input_corners) {
|
||||||
return input_extrema.x +
|
return input_corners.x +
|
||||||
mirrored_repeat(param.SAMPLE_SIZE, coord.x - input_extrema.x);
|
mirrored_repeat(param.SAMPLE_SIZE, coord.x - input_corners.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
float extend_right(vec2 coord, vec4 input_extrema) {
|
float extend_right(vec2 coord, vec4 input_corners) {
|
||||||
return input_extrema.z -
|
return input_corners.z -
|
||||||
mirrored_repeat(param.SAMPLE_SIZE, input_extrema.z - coord.x);
|
mirrored_repeat(param.SAMPLE_SIZE, input_corners.z - coord.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
float extend_top(vec2 coord, vec4 input_extrema) {
|
float extend_top(vec2 coord, vec4 input_corners) {
|
||||||
return input_extrema.y +
|
return input_corners.y +
|
||||||
mirrored_repeat(param.SAMPLE_SIZE, coord.y - input_extrema.y);
|
mirrored_repeat(param.SAMPLE_SIZE, coord.y - input_corners.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
float extend_bottom(vec2 coord, vec4 input_extrema) {
|
float extend_bottom(vec2 coord, vec4 input_corners) {
|
||||||
return input_extrema.w -
|
return input_corners.w -
|
||||||
mirrored_repeat(param.SAMPLE_SIZE, input_extrema.w - coord.y);
|
mirrored_repeat(param.SAMPLE_SIZE, input_corners.w - coord.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function samples in a very specific way which is the foundation for
|
// This function samples in a very specific way which is the foundation for
|
||||||
|
@ -92,123 +108,128 @@ float extend_bottom(vec2 coord, vec4 input_extrema) {
|
||||||
// - If the coordinate is further inside than the frame band, a mirrored
|
// - If the coordinate is further inside than the frame band, a mirrored
|
||||||
// repeating sample is returned. The side of the frame that is sampled is given
|
// repeating sample is returned. The side of the frame that is sampled is given
|
||||||
// by the one that is closest to the sampled point.
|
// by the one that is closest to the sampled point.
|
||||||
vec3 sample_mirrored_frame(sampler2D tex, vec2 coord, vec4 input_extrema) {
|
vec3 sample_mirrored_frame(sampler2D tex, vec2 tx_coord, vec4 input_corners) {
|
||||||
if (coord.x < input_extrema.x) {
|
const vec2 extend_fill =
|
||||||
if (param.BLUR_EXTEND_H < 0.5) {
|
get_rotated_size(vec2(param.EXTEND_H, param.EXTEND_V), param.Rotation);
|
||||||
|
if (tx_coord.x < input_corners.x) {
|
||||||
|
if (extend_fill.x < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
if (coord.y < input_extrema.y) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
// Top left corner extension
|
// Top left corner extension
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
return texture(tex, vec2(extend_left(coord, input_extrema),
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
||||||
extend_top(coord, input_extrema)) *
|
extend_top(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
} else if (coord.y < input_extrema.w) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
// Left extension
|
// Left extension
|
||||||
return texture(tex,
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
||||||
vec2(extend_left(coord, input_extrema), coord.y) *
|
tx_coord.y) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
} else {
|
} else {
|
||||||
// Bottom left corner extension
|
// Bottom left corner extension
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
return texture(tex, vec2(extend_left(coord, input_extrema),
|
return texture(tex, vec2(extend_left(tx_coord, input_corners),
|
||||||
extend_bottom(coord, input_extrema)) *
|
extend_bottom(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
}
|
}
|
||||||
} else if (coord.x < input_extrema.z) {
|
} else if (tx_coord.x < input_corners.z) {
|
||||||
if (coord.y < input_extrema.y) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
// Top extension
|
// Top extension
|
||||||
return texture(tex,
|
return texture(tex, vec2(tx_coord.x,
|
||||||
vec2(coord.x, extend_top(coord, input_extrema)) *
|
extend_top(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
} else if (coord.y < input_extrema.w) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
const vec4 inner_extrema =
|
const vec4 inner_corners =
|
||||||
input_extrema + vec4(param.SAMPLE_SIZE, param.SAMPLE_SIZE,
|
input_corners + vec4(param.SAMPLE_SIZE, param.SAMPLE_SIZE,
|
||||||
-param.SAMPLE_SIZE, -param.SAMPLE_SIZE);
|
-param.SAMPLE_SIZE, -param.SAMPLE_SIZE);
|
||||||
if (any(lessThan(coord, inner_extrema.xy)) ||
|
if (any(lessThan(tx_coord, inner_corners.xy)) ||
|
||||||
any(greaterThanEqual(coord, inner_extrema.zw))) {
|
any(greaterThanEqual(tx_coord, inner_corners.zw))) {
|
||||||
// In frame band
|
// In frame band
|
||||||
return texture(tex, coord * param.InputSize.zw).rgb;
|
return texture(tex, tx_coord * param.InputSize.zw).rgb;
|
||||||
}
|
}
|
||||||
// Innermost -- mirrored repeat sampling from nearest side
|
// Innermost -- mirrored repeat sampling from nearest side
|
||||||
const vec4 distances =
|
const vec4 distances = vec4(
|
||||||
vec4(coord.x - inner_extrema.x, inner_extrema.z - coord.x,
|
tx_coord.x - inner_corners.x, inner_corners.z - tx_coord.x,
|
||||||
coord.y - inner_extrema.y, inner_extrema.w - coord.y);
|
tx_coord.y - inner_corners.y, inner_corners.w - tx_coord.y);
|
||||||
switch (argmin(distances)) {
|
switch (argmin(distances)) {
|
||||||
case 0:
|
case 0:
|
||||||
// left
|
// left
|
||||||
return texture(tex, vec2(extend_left(coord, input_extrema),
|
return texture(tex,
|
||||||
coord.y) *
|
vec2(extend_left(tx_coord, input_corners),
|
||||||
param.InputSize.zw)
|
tx_coord.y) *
|
||||||
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
case 1:
|
case 1:
|
||||||
// right
|
// right
|
||||||
return texture(tex, vec2(extend_right(coord, input_extrema),
|
return texture(tex,
|
||||||
coord.y) *
|
vec2(extend_right(tx_coord, input_corners),
|
||||||
param.InputSize.zw)
|
tx_coord.y) *
|
||||||
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
case 2:
|
case 2:
|
||||||
// top
|
// top
|
||||||
return texture(tex, vec2(coord.x,
|
return texture(tex,
|
||||||
extend_top(coord, input_extrema)) *
|
vec2(tx_coord.x,
|
||||||
param.InputSize.zw)
|
extend_top(tx_coord, input_corners)) *
|
||||||
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
case 3:
|
case 3:
|
||||||
default:
|
default:
|
||||||
// bottom
|
// bottom
|
||||||
return texture(tex,
|
return texture(tex, vec2(tx_coord.x,
|
||||||
vec2(coord.x,
|
extend_bottom(tx_coord,
|
||||||
extend_bottom(coord, input_extrema)) *
|
input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
// Bottom extension
|
// Bottom extension
|
||||||
return texture(tex,
|
return texture(tex, vec2(tx_coord.x,
|
||||||
vec2(coord.x, extend_bottom(coord, input_extrema)) *
|
extend_bottom(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (param.BLUR_EXTEND_H < 0.5) {
|
if (extend_fill.x < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
if (coord.y < input_extrema.y) {
|
if (tx_coord.y < input_corners.y) {
|
||||||
// Top right corner extension
|
// Top right corner extension
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
return texture(tex, vec2(extend_right(coord, input_extrema),
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
||||||
extend_top(coord, input_extrema)) *
|
extend_top(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
} else if (coord.y < input_extrema.w) {
|
} else if (tx_coord.y < input_corners.w) {
|
||||||
// Right extension
|
// Right extension
|
||||||
return texture(tex,
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
||||||
vec2(extend_right(coord, input_extrema), coord.y) *
|
tx_coord.y) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
} else {
|
} else {
|
||||||
// Bottom right corner extension
|
// Bottom right corner extension
|
||||||
if (param.BLUR_EXTEND_V < 0.5) {
|
if (extend_fill.y < 0.5) {
|
||||||
return vec3(0.0);
|
return vec3(0.0);
|
||||||
}
|
}
|
||||||
return texture(tex, vec2(extend_right(coord, input_extrema),
|
return texture(tex, vec2(extend_right(tx_coord, input_corners),
|
||||||
extend_bottom(coord, input_extrema)) *
|
extend_bottom(tx_coord, input_corners)) *
|
||||||
param.InputSize.zw)
|
param.InputSize.zw)
|
||||||
.rgb;
|
.rgb;
|
||||||
}
|
}
|
||||||
|
@ -216,11 +237,6 @@ vec3 sample_mirrored_frame(sampler2D tex, vec2 coord, vec4 input_extrema) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const vec2 pixel_coord = o2i(vTexCoord);
|
FragColor =
|
||||||
FragColor = vec4(
|
vec4(sample_mirrored_frame(Source, tx_coord, input_corners), 1.0);
|
||||||
sample_mirrored_frame(Source, pixel_coord,
|
|
||||||
vec4(param.OS_CROP_LEFT, param.OS_CROP_TOP,
|
|
||||||
param.InputSize.x - param.OS_CROP_RIGHT,
|
|
||||||
param.InputSize.y - param.OS_CROP_BOTTOM)),
|
|
||||||
1.0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
// See compose.slang for copyright and other information.
|
|
||||||
|
|
||||||
void apply_integer_scaling(inout float x) {
|
|
||||||
if (param.FORCE_INTEGER_SCALING > 0.5 && x > 1.0) {
|
|
||||||
x = floor(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scaling from unit output to pixel input space.
|
|
||||||
vec2 scale_o2i() {
|
|
||||||
// Pixels in input coord. space, after cropping.
|
|
||||||
const vec2 eff_input_res =
|
|
||||||
param.InputSize.xy -
|
|
||||||
(param.CENTER_CROP > 0.5
|
|
||||||
? vec2(param.OS_CROP_LEFT + param.OS_CROP_RIGHT,
|
|
||||||
param.OS_CROP_TOP + param.OS_CROP_BOTTOM)
|
|
||||||
: 2 * vec2(min(param.OS_CROP_LEFT, param.OS_CROP_RIGHT),
|
|
||||||
min(param.OS_CROP_TOP, param.OS_CROP_BOTTOM)));
|
|
||||||
// Aspect ratio before cropping.
|
|
||||||
// lambda_1 * input_pixels.x, lambda_2 * input_pixels.y,
|
|
||||||
// possibly corrected for forced aspect ratio
|
|
||||||
const vec2 eff_aspect =
|
|
||||||
(param.FORCE_ASPECT_RATIO < 0.5
|
|
||||||
? param.FinalViewportSize.xy * param.InputSize.yx
|
|
||||||
: (param.ASPECT_H < 0.5 || param.ASPECT_V < 0.5
|
|
||||||
? vec2(1.0)
|
|
||||||
: vec2(param.ASPECT_H, param.ASPECT_V) *
|
|
||||||
param.InputSize.yx));
|
|
||||||
float scale_x, scale_y;
|
|
||||||
if (param.FinalViewportSize.x / (eff_input_res.x * eff_aspect.x) <
|
|
||||||
param.FinalViewportSize.y / (eff_input_res.y * eff_aspect.y)) {
|
|
||||||
// Scale will be limited by width. Calc x scale, then derive y scale
|
|
||||||
// using aspect ratio.
|
|
||||||
scale_x = param.FinalViewportSize.x / eff_input_res.x;
|
|
||||||
apply_integer_scaling(scale_x);
|
|
||||||
scale_y = scale_x * eff_aspect.y / eff_aspect.x;
|
|
||||||
apply_integer_scaling(scale_y);
|
|
||||||
} else {
|
|
||||||
// Scale will be limited by height.
|
|
||||||
scale_y = param.FinalViewportSize.y / eff_input_res.y;
|
|
||||||
apply_integer_scaling(scale_y);
|
|
||||||
scale_x = scale_y * eff_aspect.x / eff_aspect.y;
|
|
||||||
apply_integer_scaling(scale_x);
|
|
||||||
}
|
|
||||||
return param.FinalViewportSize.xy / vec2(scale_x, scale_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get adjusted center in input pixel coordinate system.
|
|
||||||
vec2 get_input_center() {
|
|
||||||
return param.CENTER_CROP > 0.5
|
|
||||||
? 0.5 * 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) * param.InputSize.xy;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
vec2 o2i(vec2 x) { return (x - 0.49999) * scale_o2i() + get_input_center(); }
|
|
||||||
|
|
||||||
// From pixel input to unit output space.
|
|
||||||
vec2 i2o(vec2 x) { return (x - get_input_center()) / scale_o2i() + 0.49999; }
|
|
163
misc/shaders/scaling.slang
Normal file
163
misc/shaders/scaling.slang
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
Scaling library v1.0 by fishku
|
||||||
|
Copyright (C) 2023
|
||||||
|
Public domain license (CC0)
|
||||||
|
|
||||||
|
This file acts like a library and should be included in another shader to be
|
||||||
|
used. For example usages, see the border/blur_fill shaders.
|
||||||
|
|
||||||
|
It's recommended to use these functions in the vertex shader pass, and pass
|
||||||
|
the data to the fragment pass.
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- Cropping on each side
|
||||||
|
- Centering of image after crop has been applied
|
||||||
|
- Forcing of a certain aspect ratio
|
||||||
|
- Forcing of either vert. or horiz. integer scaling, or both
|
||||||
|
- Rotation support (0, 90, 180, 270 degrees).
|
||||||
|
|
||||||
|
Refactored from the version that used to be in the blur_fill shader.
|
||||||
|
|
||||||
|
Changelog:
|
||||||
|
v1.0: Initial conversion from blur_fill release. Add rotation support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
vec4 get_rotated_crop(vec4 crop, uint rotation) {
|
||||||
|
switch (rotation) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return crop;
|
||||||
|
case 1:
|
||||||
|
return crop.yzwx;
|
||||||
|
case 2:
|
||||||
|
return crop.zwxy;
|
||||||
|
case 3:
|
||||||
|
return crop.wxyz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 get_rotated_size(vec2 x, uint rotation) {
|
||||||
|
switch (rotation) {
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
default:
|
||||||
|
return x;
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
return x.yx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 2 corners of input in texel space, spanning the input image.
|
||||||
|
// corners.x and .y define the top-left corner, corners.z and .w define the
|
||||||
|
// bottom-right corner.
|
||||||
|
vec4 get_input_corners(vec2 input_size, vec4 crop, uint rotation) {
|
||||||
|
crop = get_rotated_crop(crop, 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, uint rotation,
|
||||||
|
float center_after_cropping) {
|
||||||
|
crop = get_rotated_crop(crop, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scaling from unit output to pixel input space.
|
||||||
|
vec2 get_scale_o2i(vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||||
|
float center_after_cropping, float force_aspect_ratio,
|
||||||
|
vec2 aspect, vec2 force_integer_scaling,
|
||||||
|
bool output_size_is_final_viewport_size) {
|
||||||
|
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
|
||||||
|
aspect = (force_aspect_ratio < 0.5
|
||||||
|
? output_size * input_size.yx
|
||||||
|
: (aspect.x < 0.5 || aspect.y < 0.5
|
||||||
|
? vec2(1.0)
|
||||||
|
: vec2(aspect.x, aspect.y) * input_size.yx));
|
||||||
|
// Pixels in input coord. space, after cropping.
|
||||||
|
input_size = input_size -
|
||||||
|
(center_after_cropping > 0.5
|
||||||
|
? vec2(crop.y + crop.w, crop.x + crop.z)
|
||||||
|
: 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;
|
||||||
|
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 = output_size.x / input_size.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);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Scale will be limited by height.
|
||||||
|
scale_y = output_size.y / input_size.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output_size.xy / vec2(scale_x, scale_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, uint rotation,
|
||||||
|
float center_after_cropping, vec2 scale_o2i) {
|
||||||
|
return (x - 0.49999) * scale_o2i +
|
||||||
|
get_input_center(input_size, crop, rotation, center_after_cropping);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version that computes scale.
|
||||||
|
vec2 o2i(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||||
|
float center_after_cropping, float force_aspect_ratio, vec2 aspect,
|
||||||
|
vec2 force_integer_scaling, bool output_size_is_final_viewport_size) {
|
||||||
|
return o2i(x, input_size, crop, rotation, center_after_cropping,
|
||||||
|
get_scale_o2i(input_size, output_size, crop, rotation,
|
||||||
|
center_after_cropping, force_aspect_ratio, aspect,
|
||||||
|
force_integer_scaling,
|
||||||
|
output_size_is_final_viewport_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
// From pixel input to unit output space.
|
||||||
|
// Version where scale is passed in.
|
||||||
|
vec2 i2o(vec2 x, vec2 input_size, vec4 crop, uint rotation,
|
||||||
|
float center_after_cropping, vec2 scale_o2i) {
|
||||||
|
return (x - get_input_center(input_size, crop, rotation,
|
||||||
|
center_after_cropping)) /
|
||||||
|
scale_o2i +
|
||||||
|
0.49999;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version that computes scale.
|
||||||
|
vec2 i2o(vec2 x, vec2 input_size, vec2 output_size, vec4 crop, uint rotation,
|
||||||
|
float center_after_cropping, float force_aspect_ratio, vec2 aspect,
|
||||||
|
vec2 force_integer_scaling, bool output_size_is_final_viewport_size) {
|
||||||
|
return (x - get_input_center(input_size, crop, rotation,
|
||||||
|
center_after_cropping)) /
|
||||||
|
get_scale_o2i(input_size, output_size, crop, rotation,
|
||||||
|
center_after_cropping, force_aspect_ratio, aspect,
|
||||||
|
force_integer_scaling,
|
||||||
|
output_size_is_final_viewport_size) +
|
||||||
|
0.49999;
|
||||||
|
}
|
9
pixel-art-scaling/shaders/pixel_aa/parameters.slang
Normal file
9
pixel-art-scaling/shaders/pixel_aa/parameters.slang
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
// See pixel_aa.slang for copyright and other information.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#pragma parameter PIX_AA_SETTINGS "=== Pixel AA v1.3 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
|
||||||
|
#pragma parameter PIX_AA_SUBPX_BGR "Use BGR subpx. instead of RGB" 0.0 0.0 1.0 1.0
|
||||||
|
// clang-format on
|
|
@ -1,7 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Pixel AA v1.2 by fishku
|
Pixel AA v1.3 by fishku
|
||||||
Copyright (C) 2023
|
Copyright (C) 2023
|
||||||
Public domain license (CC0)
|
Public domain license (CC0)
|
||||||
|
|
||||||
|
@ -24,15 +24,20 @@
|
||||||
subpixel anti-aliasing, results are identical to the "pixellate" shader.
|
subpixel anti-aliasing, results are identical to the "pixellate" shader.
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
v1.3: Account for screen rotation in subpixel sampling.
|
||||||
v1.2: Optimize and simplify algorithm. Enable sharpness < 1.0. Fix subpixel
|
v1.2: Optimize and simplify algorithm. Enable sharpness < 1.0. Fix subpixel
|
||||||
sampling bug.
|
sampling bug.
|
||||||
v1.1: Better subpixel sampling.
|
v1.1: Better subpixel sampling.
|
||||||
v1.0: Initial release.
|
v1.0: Initial release.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "parameters.slang"
|
||||||
|
#include "shared.slang"
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
vec4 SourceSize;
|
vec4 SourceSize;
|
||||||
vec4 OutputSize;
|
vec4 OutputSize;
|
||||||
|
uint Rotation;
|
||||||
float PIX_AA_SHARP;
|
float PIX_AA_SHARP;
|
||||||
float PIX_AA_GAMMA;
|
float PIX_AA_GAMMA;
|
||||||
float PIX_AA_SUBPX;
|
float PIX_AA_SUBPX;
|
||||||
|
@ -64,11 +69,9 @@ layout(location = 2) in vec2 tx_to_uv;
|
||||||
layout(location = 0) out vec4 FragColor;
|
layout(location = 0) out vec4 FragColor;
|
||||||
layout(set = 0, binding = 2) uniform sampler2D Source;
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
|
||||||
#include "shared.slang"
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FragColor =
|
FragColor =
|
||||||
pixel_aa(Source, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
pixel_aa(Source, tx_per_px, tx_to_uv, tx_coord, param.PIX_AA_SHARP,
|
||||||
param.PIX_AA_GAMMA > 0.5, param.PIX_AA_SUBPX > 0.5,
|
param.PIX_AA_GAMMA > 0.5, param.PIX_AA_SUBPX > 0.5,
|
||||||
param.PIX_AA_SUBPX_BGR > 0.5);
|
param.PIX_AA_SUBPX_BGR > 0.5, param.Rotation);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
// See pixel_aa.slang for copyright and other information.
|
// See pixel_aa.slang for copyright and other information.
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#pragma parameter PIX_AA_SETTINGS "=== Pixel AA v1.2 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
|
|
||||||
#pragma parameter PIX_AA_SUBPX_BGR "Use BGR subpx. instead of RGB" 0.0 0.0 1.0 1.0
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
// Similar to smoothstep, but has a configurable slope at x = 0.5.
|
// Similar to smoothstep, but has a configurable slope at x = 0.5.
|
||||||
// Original smoothstep has a slope of 1.5 at x = 0.5
|
// Original smoothstep has a slope of 1.5 at x = 0.5
|
||||||
#define INSTANTIATE_SLOPESTEP(T) \
|
#define INSTANTIATE_SLOPESTEP(T) \
|
||||||
|
@ -66,13 +58,17 @@ vec3 sample_aa(sampler2D tex, vec2 tx_per_px, vec2 tx_to_uv, vec2 tx_coord,
|
||||||
// interpolation.
|
// interpolation.
|
||||||
vec4 pixel_aa(sampler2D tex, vec2 tx_per_px, vec2 tx_to_uv, vec2 tx_coord,
|
vec4 pixel_aa(sampler2D tex, vec2 tx_per_px, vec2 tx_to_uv, vec2 tx_coord,
|
||||||
float sharpness, bool gamma_correct, bool sample_subpx,
|
float sharpness, bool gamma_correct, bool sample_subpx,
|
||||||
bool subpx_bgr) {
|
bool subpx_bgr, uint rotation) {
|
||||||
if (sample_subpx) {
|
if (sample_subpx) {
|
||||||
// Subpixel sampling: Shift the sampling by 1/3rd of an output pixel for
|
// Subpixel sampling: Shift the sampling by 1/3rd of an output pixel for
|
||||||
// each subpixel, assuming that the output size is at monitor
|
// each subpixel, assuming that the output size is at monitor
|
||||||
// resolution.
|
// resolution.
|
||||||
|
// Compensate for possible rotation of the screen in certain cores.
|
||||||
|
const vec2 rotation_correction[] = {vec2(1.0, 0.0), vec2(0.0, 1.0),
|
||||||
|
vec2(-1.0, 0.0), vec2(0.0, -1.0)};
|
||||||
const vec2 sub_tx_offset =
|
const vec2 sub_tx_offset =
|
||||||
vec2(tx_per_px.x / 3.0 * (subpx_bgr ? -1.0 : 1.0), 0.0);
|
tx_per_px / 3.0 *
|
||||||
|
rotation_correction[(rotation + int(subpx_bgr) * 2) % 4];
|
||||||
vec3 res;
|
vec3 res;
|
||||||
for (int i = -1; i < 2; ++i) {
|
for (int i = -1; i < 2; ++i) {
|
||||||
res[i + 1] = sample_aa(tex, tx_per_px, tx_to_uv,
|
res[i + 1] = sample_aa(tex, tx_per_px, tx_to_uv,
|
||||||
|
|
Loading…
Reference in a new issue