From cd045fde1541b425f24ba847b09fbdcde3199612 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Fri, 15 Jun 2018 19:11:06 +0300 Subject: [PATCH] Scaling filters in Metal --- Cocoa/GBViewMetal.m | 20 ++++++++++++++++++-- Shaders/AAOmniScaleLegacy.fsh | 18 +++++++++--------- Shaders/AAScale2x.fsh | 8 ++++---- Shaders/AAScale4x.fsh | 16 ++++++++-------- Shaders/MasterShader.fsh | 3 +++ Shaders/MasterShader.metal | 10 ++++++++-- Shaders/OmniScale.fsh | 8 ++++---- Shaders/OmniScaleLegacy.fsh | 18 +++++++++--------- Shaders/Scale2x.fsh | 8 ++++---- Shaders/Scale4x.fsh | 16 ++++++++-------- 10 files changed, 75 insertions(+), 50 deletions(-) diff --git a/Cocoa/GBViewMetal.m b/Cocoa/GBViewMetal.m index a4bca88..2bd69fe 100644 --- a/Cocoa/GBViewMetal.m +++ b/Cocoa/GBViewMetal.m @@ -54,10 +54,11 @@ static const vector_float2 rect[] = length:sizeof(default_mix_value) options:MTLResourceStorageModeShared]; - output_resolution_buffer = [device newBufferWithBytes:&default_mix_value - length:sizeof(default_mix_value) + output_resolution_buffer = [device newBufferWithBytes:&output_resolution + length:sizeof(output_resolution) options:MTLResourceStorageModeShared]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadShader) name:@"GBFilterChanged" object:nil]; [self loadShader]; } @@ -69,11 +70,25 @@ static const vector_float2 rect[] = inDirectory:@"Shaders"] encoding:NSUTF8StringEncoding 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 library = [device newLibraryWithSource:shader_source options:nil error:&error]; if (error) { NSLog(@"Error: %@", error); + if (!library) { + return; + } } id vertex_function = [library newFunctionWithName:@"vertex_shader"]; @@ -90,6 +105,7 @@ static const vector_float2 rect[] = error:&error]; if (error) { NSLog(@"Failed to created pipeline state, error %@", error); + return; } command_queue = [device newCommandQueue]; diff --git a/Shaders/AAOmniScaleLegacy.fsh b/Shaders/AAOmniScaleLegacy.fsh index f8d50d2..5bfddb9 100644 --- a/Shaders/AAOmniScaleLegacy.fsh +++ b/Shaders/AAOmniScaleLegacy.fsh @@ -18,16 +18,16 @@ vec4 omniScale(sampler2D image, vec2 position, vec2 input_resolution, vec2 outpu /* Special handling for diaonals */ bool hasDownDiagonal = false; bool hasUpDiagonal = false; - if (q12 == q21 && q11 != q22) hasUpDiagonal = true; - else if (q12 != q21 && q11 == q22) hasDownDiagonal = true; - else if (q12 == q21 && q11 == q22) { - if (q11 == q12) return q11; + if (equal(q12, q21) && inequal(q11, q22)) hasUpDiagonal = true; + else if (inequal(q12, q21) && equal(q11, q22)) hasDownDiagonal = true; + else if (equal(q12, q21) && equal(q11, q22)) { + if (equal(q11, q12)) return q11; int diagonalBias = 0; for (float y = -1.0; y < 3.0; y++) { for (float x = -1.0; x < 3.0; x++) { vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution); - if (color == q11) diagonalBias++; - if (color == q12) diagonalBias--; + if (equal(color, q11)) diagonalBias++; + if (equal(color, q12)) diagonalBias--; } } if (diagonalBias <= 0) { @@ -89,15 +89,15 @@ vec4 omniScale(sampler2D image, vec2 position, vec2 input_resolution, vec2 outpu min(q12d, q22d))); - if (q11d == best) { + if (equal(q11d, best)) { return q11; } - if (q21d == best) { + if (equal(q21d, best)) { return q21; } - if (q12d == best) { + if (equal(q12d, best)) { return q12; } diff --git a/Shaders/AAScale2x.fsh b/Shaders/AAScale2x.fsh index 1801805..220e14b 100644 --- a/Shaders/AAScale2x.fsh +++ b/Shaders/AAScale2x.fsh @@ -22,18 +22,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_ if (p.x > .5) { if (p.y > .5) { // Top Right - return B == F && B != D && F != H ? F : E; + return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - return H == F && D != H && B != F ? F : E; + return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - return D == B && B != F && D != H ? D : E; + return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // Bottom Left - return D == H && D != B && H != F ? D : E; + return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E; } } } diff --git a/Shaders/AAScale4x.fsh b/Shaders/AAScale4x.fsh index 7e9ab72..9f37862 100644 --- a/Shaders/AAScale4x.fsh +++ b/Shaders/AAScale4x.fsh @@ -21,18 +21,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_ if (p.x > .5) { if (p.y > .5) { // Top Right - return B == F && B != D && F != H ? F : E; + return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - return H == F && D != H && B != F ? F : E; + return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - return D == B && B != F && D != H ? D : E; + return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // 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.y > .5) { // Top Right - R = B == F && B != D && F != H ? F : E; + R = equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - R = H == F && D != H && B != F ? F : E; + R = equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - R = D == B && B != F && D != H ? D : E; + R = equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // Bottom Left - R = D == H && D != B && H != F ? D : E; + R = equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E; } } diff --git a/Shaders/MasterShader.fsh b/Shaders/MasterShader.fsh index 90c6b1a..61a08db 100644 --- a/Shaders/MasterShader.fsh +++ b/Shaders/MasterShader.fsh @@ -7,6 +7,9 @@ uniform vec2 output_resolution; uniform vec2 origin; const vec2 input_resolution = vec2(160, 144); +#define equal(x, y) ((x) == (y)) +#define inequal(x, y) ((x) != (y)) + out vec4 frag_color; #line 1 diff --git a/Shaders/MasterShader.metal b/Shaders/MasterShader.metal index 5c2b8d9..8353094 100644 --- a/Shaders/MasterShader.metal +++ b/Shaders/MasterShader.metal @@ -9,6 +9,9 @@ constant float2 input_resolution = float2(160, 144); typedef float2 vec2; typedef float3 vec3; typedef float4 vec4; +typedef texture2d sampler2D; +#define equal(x, y) all((x) == (y)) +#define inequal(x, y) any((x) != (y)) typedef struct { float4 position [[position]]; @@ -36,6 +39,8 @@ static inline float4 texture(texture2d texture, float2 pos) return float4(texture.sample(texture_sampler, pos)); } +#line 1 +{filter} fragment float4 fragment_shader(rasterizer_data in [[stage_in]], texture2d image [[ texture(0) ]], @@ -45,8 +50,9 @@ fragment float4 fragment_shader(rasterizer_data in [[stage_in]], { in.texcoords.y = 1 - in.texcoords.y; 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); } diff --git a/Shaders/OmniScale.fsh b/Shaders/OmniScale.fsh index 21a5c1d..985fc98 100644 --- a/Shaders/OmniScale.fsh +++ b/Shaders/OmniScale.fsh @@ -99,7 +99,7 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re } if (P(0xbf,0x37) || P(0xdb,0x13)) { 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) { 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)) { 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) { 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)) { 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) { 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)) { 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) { return w4; diff --git a/Shaders/OmniScaleLegacy.fsh b/Shaders/OmniScaleLegacy.fsh index dfeb3a0..90ace69 100644 --- a/Shaders/OmniScaleLegacy.fsh +++ b/Shaders/OmniScaleLegacy.fsh @@ -18,16 +18,16 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re /* Special handling for diaonals */ bool hasDownDiagonal = false; bool hasUpDiagonal = false; - if (q12 == q21 && q11 != q22) hasUpDiagonal = true; - else if (q12 != q21 && q11 == q22) hasDownDiagonal = true; - else if (q12 == q21 && q11 == q22) { - if (q11 == q12) return q11; + if (equal(q12, q21) && inequal(q11, q22)) hasUpDiagonal = true; + else if (inequal(q12, q21) && equal(q11, q22)) hasDownDiagonal = true; + else if (equal(q12, q21) && equal(q11, q22)) { + if (equal(q11, q12)) return q11; int diagonalBias = 0; for (float y = -1.0; y < 3.0; y++) { for (float x = -1.0; x < 3.0; x++) { vec4 color = texture(image, (pixel + vec2(x, y)) / input_resolution); - if (color == q11) diagonalBias++; - if (color == q12) diagonalBias--; + if (equal(color, q11)) diagonalBias++; + if (equal(color, q12)) diagonalBias--; } } if (diagonalBias <= 0) { @@ -89,15 +89,15 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re min(q12d, q22d))); - if (q11d == best) { + if (equal(q11d, best)) { return q11; } - if (q21d == best) { + if (equal(q21d, best)) { return q21; } - if (q12d == best) { + if (equal(q12d, best)) { return q12; } diff --git a/Shaders/Scale2x.fsh b/Shaders/Scale2x.fsh index 439b1fa..ff77440 100644 --- a/Shaders/Scale2x.fsh +++ b/Shaders/Scale2x.fsh @@ -24,18 +24,18 @@ vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_re if (p.x > .5) { if (p.y > .5) { // Top Right - return B == F && B != D && F != H ? F : E; + return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - return H == F && D != H && B != F ? F : E; + return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - return D == B && B != F && D != H ? D : E; + return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // Bottom Left - return D == H && D != B && H != F ? D : E; + return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E; } } } diff --git a/Shaders/Scale4x.fsh b/Shaders/Scale4x.fsh index 4e3b3f1..1edf800 100644 --- a/Shaders/Scale4x.fsh +++ b/Shaders/Scale4x.fsh @@ -22,18 +22,18 @@ vec4 scale2x(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_ if (p.x > .5) { if (p.y > .5) { // Top Right - return B == F && B != D && F != H ? F : E; + return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - return H == F && D != H && B != F ? F : E; + return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - return D == B && B != F && D != H ? D : E; + return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // 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.y > .5) { // Top Right - return B == F && B != D && F != H ? F : E; + return equal(B, F) && inequal(B, D) && inequal(F, H) ? F : E; } else { // Bottom Right - return H == F && D != H && B != F ? F : E; + return equal(H, F) && inequal(D, H) && inequal(B, F) ? F : E; } } else { if (p.y > .5) { // Top Left - return D == B && B != F && D != H ? D : E; + return equal(D, B) && inequal(B, F) && inequal(D, H) ? D : E; } else { // Bottom Left - return D == H && D != B && H != F ? D : E; + return equal(D, H) && inequal(D, B) && inequal(H, F) ? D : E; } } }