Scaling filters in Metal
This commit is contained in:
parent
4466a55de6
commit
cd045fde15
@ -54,10 +54,11 @@ static const vector_float2 rect[] =
|
|||||||
length:sizeof(default_mix_value)
|
length:sizeof(default_mix_value)
|
||||||
options:MTLResourceStorageModeShared];
|
options:MTLResourceStorageModeShared];
|
||||||
|
|
||||||
output_resolution_buffer = [device newBufferWithBytes:&default_mix_value
|
output_resolution_buffer = [device newBufferWithBytes:&output_resolution
|
||||||
length:sizeof(default_mix_value)
|
length:sizeof(output_resolution)
|
||||||
options:MTLResourceStorageModeShared];
|
options:MTLResourceStorageModeShared];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadShader) name:@"GBFilterChanged" object:nil];
|
||||||
[self loadShader];
|
[self loadShader];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,11 +70,25 @@ static const vector_float2 rect[] =
|
|||||||
inDirectory:@"Shaders"]
|
inDirectory:@"Shaders"]
|
||||||
encoding:NSUTF8StringEncoding
|
encoding:NSUTF8StringEncoding
|
||||||
error:nil];
|
error:nil];
|
||||||
|
|
||||||
|
NSString *shader_name = [[NSUserDefaults standardUserDefaults] objectForKey:@"GBFilter"];
|
||||||
|
NSString *scaler_source = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:shader_name
|
||||||
|
ofType:@"fsh"
|
||||||
|
inDirectory:@"Shaders"]
|
||||||
|
encoding:NSUTF8StringEncoding
|
||||||
|
error:nil];
|
||||||
|
|
||||||
|
shader_source = [shader_source stringByReplacingOccurrencesOfString:@"{filter}"
|
||||||
|
withString:scaler_source];
|
||||||
|
|
||||||
id<MTLLibrary> library = [device newLibraryWithSource:shader_source
|
id<MTLLibrary> library = [device newLibraryWithSource:shader_source
|
||||||
options:nil
|
options:nil
|
||||||
error:&error];
|
error:&error];
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(@"Error: %@", error);
|
NSLog(@"Error: %@", error);
|
||||||
|
if (!library) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
id<MTLFunction> vertex_function = [library newFunctionWithName:@"vertex_shader"];
|
id<MTLFunction> vertex_function = [library newFunctionWithName:@"vertex_shader"];
|
||||||
@ -90,6 +105,7 @@ static const vector_float2 rect[] =
|
|||||||
error:&error];
|
error:&error];
|
||||||
if (error) {
|
if (error) {
|
||||||
NSLog(@"Failed to created pipeline state, error %@", error);
|
NSLog(@"Failed to created pipeline state, error %@", error);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
command_queue = [device newCommandQueue];
|
command_queue = [device newCommandQueue];
|
||||||
|
@ -18,16 +18,16 @@ vec4 omniScale(sampler2D image, vec2 position, vec2 input_resolution, vec2 outpu
|
|||||||
/* Special handling for diaonals */
|
/* Special handling for diaonals */
|
||||||
bool hasDownDiagonal = false;
|
bool hasDownDiagonal = false;
|
||||||
bool hasUpDiagonal = false;
|
bool hasUpDiagonal = false;
|
||||||
if (q12 == q21 && q11 != q22) hasUpDiagonal = true;
|
if (equal(q12, q21) && inequal(q11, q22)) hasUpDiagonal = true;
|
||||||
else if (q12 != q21 && q11 == q22) hasDownDiagonal = true;
|
else if (inequal(q12, q21) && equal(q11, q22)) hasDownDiagonal = true;
|
||||||
else if (q12 == q21 && q11 == q22) {
|
else if (equal(q12, q21) && equal(q11, q22)) {
|
||||||
if (q11 == q12) return q11;
|
if (equal(q11, q12)) return q11;
|
||||||
int diagonalBias = 0;
|
int diagonalBias = 0;
|
||||||
for (float y = -1.0; y < 3.0; y++) {
|
for (float y = -1.0; y < 3.0; y++) {
|
||||||
for (float x = -1.0; x < 3.0; x++) {
|
for (float x = -1.0; x < 3.0; x++) {
|
||||||
vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution);
|
vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution);
|
||||||
if (color == q11) diagonalBias++;
|
if (equal(color, q11)) diagonalBias++;
|
||||||
if (color == q12) diagonalBias--;
|
if (equal(color, q12)) diagonalBias--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diagonalBias <= 0) {
|
if (diagonalBias <= 0) {
|
||||||
@ -89,15 +89,15 @@ vec4 omniScale(sampler2D image, vec2 position, vec2 input_resolution, vec2 outpu
|
|||||||
min(q12d,
|
min(q12d,
|
||||||
q22d)));
|
q22d)));
|
||||||
|
|
||||||
if (q11d == best) {
|
if (equal(q11d, best)) {
|
||||||
return q11;
|
return q11;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q21d == best) {
|
if (equal(q21d, best)) {
|
||||||
return q21;
|
return q21;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q12d == best) {
|
if (equal(q12d, best)) {
|
||||||
return q12;
|
return q12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +22,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
return B == F && B != D && F != H ? F : E;
|
return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
return H == F && D != H && B != F ? F : E;
|
return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
return D == B && B != F && D != H ? D : E;
|
return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
return D == H && D != B && H != F ? D : E;
|
return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,18 +21,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
return B == F && B != D && F != H ? F : E;
|
return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
return H == F && D != H && B != F ? F : E;
|
return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
return D == B && B != F && D != H ? D : E;
|
return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
return D == H && D != B && H != F ? D : E;
|
return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -67,18 +67,18 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
R = B == F && B != D && F != H ? F : E;
|
R = equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
R = H == F && D != H && B != F ? F : E;
|
R = equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
R = D == B && B != F && D != H ? D : E;
|
R = equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
R = D == H && D != B && H != F ? D : E;
|
R = equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ uniform vec2 output_resolution;
|
|||||||
uniform vec2 origin;
|
uniform vec2 origin;
|
||||||
const vec2 input_resolution = vec2(160, 144);
|
const vec2 input_resolution = vec2(160, 144);
|
||||||
|
|
||||||
|
#define equal(x, y) ((x) == (y))
|
||||||
|
#define inequal(x, y) ((x) != (y))
|
||||||
|
|
||||||
out vec4 frag_color;
|
out vec4 frag_color;
|
||||||
|
|
||||||
#line 1
|
#line 1
|
||||||
|
@ -9,6 +9,9 @@ constant float2 input_resolution = float2(160, 144);
|
|||||||
typedef float2 vec2;
|
typedef float2 vec2;
|
||||||
typedef float3 vec3;
|
typedef float3 vec3;
|
||||||
typedef float4 vec4;
|
typedef float4 vec4;
|
||||||
|
typedef texture2d<half> sampler2D;
|
||||||
|
#define equal(x, y) all((x) == (y))
|
||||||
|
#define inequal(x, y) any((x) != (y))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float4 position [[position]];
|
float4 position [[position]];
|
||||||
@ -36,6 +39,8 @@ static inline float4 texture(texture2d<half> texture, float2 pos)
|
|||||||
return float4(texture.sample(texture_sampler, pos));
|
return float4(texture.sample(texture_sampler, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#line 1
|
||||||
|
{filter}
|
||||||
|
|
||||||
fragment float4 fragment_shader(rasterizer_data in [[stage_in]],
|
fragment float4 fragment_shader(rasterizer_data in [[stage_in]],
|
||||||
texture2d<half> image [[ texture(0) ]],
|
texture2d<half> image [[ texture(0) ]],
|
||||||
@ -45,8 +50,9 @@ fragment float4 fragment_shader(rasterizer_data in [[stage_in]],
|
|||||||
{
|
{
|
||||||
in.texcoords.y = 1 - in.texcoords.y;
|
in.texcoords.y = 1 - in.texcoords.y;
|
||||||
if (*mix_previous) {
|
if (*mix_previous) {
|
||||||
return mix(texture(image, in.texcoords), texture(previous_image, in.texcoords), 0.5);
|
return mix(scale(image, in.texcoords, input_resolution, *output_resolution),
|
||||||
|
scale(previous_image, in.texcoords, input_resolution, *output_resolution), 0.5);
|
||||||
}
|
}
|
||||||
return texture(image, in.texcoords);
|
return scale(image, in.texcoords, input_resolution, *output_resolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
}
|
}
|
||||||
if (P(0xbf,0x37) || P(0xdb,0x13)) {
|
if (P(0xbf,0x37) || P(0xdb,0x13)) {
|
||||||
float dist = p.x - 2.0 * p.y;
|
float dist = p.x - 2.0 * p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
if (dist > pixel_size / 2) {
|
if (dist > pixel_size / 2) {
|
||||||
return w1;
|
return w1;
|
||||||
}
|
}
|
||||||
@ -111,7 +111,7 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
}
|
}
|
||||||
if (P(0xdb,0x49) || P(0xef,0x6d)) {
|
if (P(0xdb,0x49) || P(0xef,0x6d)) {
|
||||||
float dist = p.y - 2.0 * p.x;
|
float dist = p.y - 2.0 * p.x;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
if (p.y - 2.0 * p.x > pixel_size / 2) {
|
if (p.y - 2.0 * p.x > pixel_size / 2) {
|
||||||
return w3;
|
return w3;
|
||||||
}
|
}
|
||||||
@ -123,7 +123,7 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
}
|
}
|
||||||
if (P(0xbf,0x8f) || P(0x7e,0x0e)) {
|
if (P(0xbf,0x8f) || P(0x7e,0x0e)) {
|
||||||
float dist = p.x + 2.0 * p.y;
|
float dist = p.x + 2.0 * p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
|
|
||||||
if (dist > 1.0 + pixel_size / 2) {
|
if (dist > 1.0 + pixel_size / 2) {
|
||||||
return w4;
|
return w4;
|
||||||
@ -147,7 +147,7 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
|
|
||||||
if (P(0x7e,0x2a) || P(0xef,0xab)) {
|
if (P(0x7e,0x2a) || P(0xef,0xab)) {
|
||||||
float dist = p.y + 2.0 * p.x;
|
float dist = p.y + 2.0 * p.x;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
|
|
||||||
if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2) {
|
if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2) {
|
||||||
return w4;
|
return w4;
|
||||||
|
@ -18,16 +18,16 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
/* Special handling for diaonals */
|
/* Special handling for diaonals */
|
||||||
bool hasDownDiagonal = false;
|
bool hasDownDiagonal = false;
|
||||||
bool hasUpDiagonal = false;
|
bool hasUpDiagonal = false;
|
||||||
if (q12 == q21 && q11 != q22) hasUpDiagonal = true;
|
if (equal(q12, q21) && inequal(q11, q22)) hasUpDiagonal = true;
|
||||||
else if (q12 != q21 && q11 == q22) hasDownDiagonal = true;
|
else if (inequal(q12, q21) && equal(q11, q22)) hasDownDiagonal = true;
|
||||||
else if (q12 == q21 && q11 == q22) {
|
else if (equal(q12, q21) && equal(q11, q22)) {
|
||||||
if (q11 == q12) return q11;
|
if (equal(q11, q12)) return q11;
|
||||||
int diagonalBias = 0;
|
int diagonalBias = 0;
|
||||||
for (float y = -1.0; y < 3.0; y++) {
|
for (float y = -1.0; y < 3.0; y++) {
|
||||||
for (float x = -1.0; x < 3.0; x++) {
|
for (float x = -1.0; x < 3.0; x++) {
|
||||||
vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution);
|
vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution);
|
||||||
if (color == q11) diagonalBias++;
|
if (equal(color, q11)) diagonalBias++;
|
||||||
if (color == q12) diagonalBias--;
|
if (equal(color, q12)) diagonalBias--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diagonalBias <= 0) {
|
if (diagonalBias <= 0) {
|
||||||
@ -89,15 +89,15 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
min(q12d,
|
min(q12d,
|
||||||
q22d)));
|
q22d)));
|
||||||
|
|
||||||
if (q11d == best) {
|
if (equal(q11d, best)) {
|
||||||
return q11;
|
return q11;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q21d == best) {
|
if (equal(q21d, best)) {
|
||||||
return q21;
|
return q21;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q12d == best) {
|
if (equal(q12d, best)) {
|
||||||
return q12;
|
return q12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,18 +24,18 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
return B == F && B != D && F != H ? F : E;
|
return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
return H == F && D != H && B != F ? F : E;
|
return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
return D == B && B != F && D != H ? D : E;
|
return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
return D == H && D != B && H != F ? D : E;
|
return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,18 +22,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
return B == F && B != D && F != H ? F : E;
|
return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
return H == F && D != H && B != F ? F : E;
|
return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
return D == B && B != F && D != H ? D : E;
|
return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
return D == H && D != B && H != F ? D : E;
|
return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,18 +62,18 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re
|
|||||||
if (p.x > .5) {
|
if (p.x > .5) {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Right
|
// Top Right
|
||||||
return B == F && B != D && F != H ? F : E;
|
return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Right
|
// Bottom Right
|
||||||
return H == F && D != H && B != F ? F : E;
|
return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (p.y > .5) {
|
if (p.y > .5) {
|
||||||
// Top Left
|
// Top Left
|
||||||
return D == B && B != F && D != H ? D : E;
|
return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E;
|
||||||
} else {
|
} else {
|
||||||
// Bottom Left
|
// Bottom Left
|
||||||
return D == H && D != B && H != F ? D : E;
|
return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user