Scaling filters in Metal

This commit is contained in:
Lior Halphon 2018-06-15 19:11:06 +03:00
parent 4466a55de6
commit cd045fde15
10 changed files with 75 additions and 50 deletions

View File

@ -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];

View File

@ -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;
} }

View File

@ -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;
} }
} }
} }

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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);
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;
} }
} }
} }

View File

@ -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;
} }
} }
} }