Skip to content

Instantly share code, notes, and snippets.

@SwooshyCueb
Created May 21, 2016 05:51
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SwooshyCueb/f8716456d93a1a21fb0bee376caddc3b to your computer and use it in GitHub Desktop.
Save SwooshyCueb/f8716456d93a1a21fb0bee376caddc3b to your computer and use it in GitHub Desktop.
Temporary location for glsl stuff
#version 420 compatibility
// Will insert lines here so make sure version is at the very top.
// No includes.
/******************************************************************************/
/* GLSL Fragment Shader implementation of the SuperEagle 2x upscaler filter */
/******************************************************************************/
/* Copyright (C) 2016 Markus Kitsinger (SwooshyCueb) <root@swooshalicio.us> */
/* */
/* This implementation of the SuperEagle filter is subject to the terms of */
/* Mozilla Public License, version 2.0. You can obtain a copy of this */
/* license at http://mozilla.org/MPL/2.0/. */
/******************************************************************************/
/* The original SuperEagle filter implementation was created by */
/* Derek Liauw Kie Fa (Kreed). It was released under the GPL license in 1999. */
/* It can be found at https://vdnoort.home.xs4all.nl/emulation/2xsai/. */
/******************************************************************************/
// Mesa recently got complete OpenGL 4.2 support on intel graphics
// So we'll target 4.2 plus extensions
/* TODO:
* Replace gl_TexCoord, and anything else depricated in 4.2
* Ensure shader works as intended when alpha values are used
*/
#extension GL_ARB_texture_rectangle : enable
#extension GL_ARB_shading_language_420pack: enable
#extension GL_EXT_shader_image_load_store : enable
#extension GL_EXT_bindable_uniform : enable
const uint colorMask = uint(0xF7DEF7DE);
const uint lowPixelMask = uint(0x08210821);
const uint qcolorMask = uint(0xE79CE79C);
const uint qlowpixelMask = uint(0x18631863);
#ifdef DEBUG
vec4 c_black = vec4(0.0, 0.0, 0.0, 1.0);
vec4 c_white = vec4(1.0, 1.0, 1.0, 1.0);
vec4 c_red = vec4(1.0, 0.0, 0.0, 1.0);
vec4 c_green = vec4(0.0, 1.0, 0.0, 1.0);
vec4 c_blue = vec4(0.0, 0.0, 1.0, 1.0);
vec4 c_yellow = vec4(1.0, 1.0, 0.0, 1.0);
vec4 c_purple = vec4(1.0, 0.0, 1.0, 1.0);
vec4 c_indigo = vec4(0.0, 1.0, 1.0, 1.0);
#endif
uniform uvec2 src_size;
uniform uvec2 dst_size;
uniform sampler2D src_tex;
coherent writeonly uniform image2D dst_tex;
// If the destination texture
// isn't twice the size of the
// source texture, this shader
// will not work as intended.
//layout(origin_upper_left)
in vec4 gl_FragCoord;
highp vec2 coord = gl_TexCoord[0].st;
highp vec2 dst_pos_f = gl_FragCoord.xy;
ivec2 dst_pos_i = ivec2(dst_pos_f);
ivec2 dst_pos_o = ivec2(dst_pos_i.x, dst_size.y-dst_pos_i.y-1);
highp vec2 src_pos_f = vec2(coord.x * src_size.x, coord.y * src_size.y);
ivec2 src_pos_t = ivec2(src_pos_f);
highp vec2 dst_inv_size = vec2(1.0/float(dst_size.x), 1.0/float(dst_size.y));
highp vec2 src_inv_size = vec2(1.0/float(src_size.x), 1.0/float(src_size.y));
int magicnumber(vec4 A, vec4 B, vec4 C, vec4 D) {
ivec3 tmp = ivec3(0, 0, 0);
if (A == C) {
tmp.x = tmp.x + 1;
} else if (B == C) {
tmp.y = tmp.y + 1;
}
if (A == D) {
tmp.x = tmp.x + 1;
} else if (B == D) {
tmp.y = tmp.y + 1;
}
if (tmp.x <= 1) {
tmp.z = tmp.z + 1;
}
if (tmp.y <= 1) {
tmp.z = tmp.z - 1;
}
return tmp.z;
}
// Turn a vec4 color into a uint
highp uint reduce(vec4 color) {
return (uint(color.a*255.0) << uint(24))
+ (uint(color.r*255.0) << uint(16))
+ (uint(color.g*255.0) << uint(8))
+ (uint(color.b*255.0));
}
// Turn a uint into a vec4 color
highp vec4 unpack(uint c) {
highp vec4 ret;
ret.a = float((c & uint(0xFF000000)) >> 24);
ret.r = float((c & uint(0x00FF0000)) >> 16);
ret.g = float((c & uint(0x0000FF00)) >> 8);
ret.b = float(c & uint(0x000000FF));
return ret/255.0;
}
highp vec4 smash2(vec4 A, vec4 B) {
if (A == B) {
return A;
}
uint rA = reduce(A);
uint rB = reduce(B);
return unpack(((rA & colorMask) >> 1) + ((rB & colorMask) >> 1) +
(rA & rB & lowPixelMask));
}
highp vec4 smash4(vec4 A, vec4 B, vec4 C, vec4 D) {
uint rA = reduce(A);
uint rB = reduce(B);
uint rC = reduce(C);
uint rD = reduce(D);
return unpack((((rA & qcolorMask) >> 2) + ((rB & qcolorMask) >> 2) +
((rC & qcolorMask) >> 2) + ((rD & qcolorMask) >> 2)) +
((((rA & qlowpixelMask) + (rB & qlowpixelMask) +
(rC & qlowpixelMask) + (rD & qlowpixelMask)) >> 2) & qlowpixelMask));
}
highp vec4 getpx(int x, int y) {
return texture2D(src_tex, coord + vec2(x * src_inv_size.x, -y * src_inv_size.y));
}
void main() {
// Don't do anything if the pixel we're looking at is already taken care of
if ((mod(dst_pos_i.x, 2) != 0) || (mod(dst_pos_i.y, 2) != 0)) {
discard;
}
#ifdef DEBUG // Shows a few useful borders
if (dst_pos_i.x == 0 || dst_pos_i.y == 0 ) {
imageStore(dst_tex, dst_pos_o, c_green);
discard;
} else if (dst_pos_i.x == src_size.x-2
|| dst_pos_i.y == src_size.y-2) {
imageStore(dst_tex, dst_pos_o, c_red);
discard;
} else if (dst_pos_i.x == dst_size.x-2
|| dst_pos_i.y == dst_size.y-2) {
imageStore(dst_tex, dst_pos_o, c_indigo);
discard;
}
#endif
highp vec4 dst_px;
highp vec4 dst_px_E;
highp vec4 dst_px_N;
highp vec4 dst_px_NE;
// Fetch pixels from source texture
highp vec4 src_px = getpx( 0, 0);
highp vec4 src_px_N = getpx( 0, 1);
highp vec4 src_px_E = getpx( 1, 0);
highp vec4 src_px_S = getpx( 0, -1);
highp vec4 src_px_W = getpx(-1, 0);
highp vec4 src_px_NE = getpx( 1, 1);
highp vec4 src_px_SE = getpx( 1, -1);
highp vec4 src_px_NW = getpx(-1, 1);
highp vec4 src_px_NN = getpx( 0, 2);
highp vec4 src_px_EE = getpx( 2, 0);
highp vec4 src_px_NNE = getpx( 1, 2);
highp vec4 src_px_ENE = getpx( 2, 1);
// Do magic
// (Don't ask me how this works; I barely understand it myself)
if ((src_px_N == src_px_E) && (src_px != src_px_NE)) {
dst_px_E = dst_px_N = src_px_N;
if ((src_px_NW == src_px_N) || (src_px_E == src_px_SE)) {
dst_px = smash2(src_px_N, smash2(src_px_N, src_px));
} else {
dst_px = smash2(src_px, src_px_E);
}
if ((src_px_E == src_px_EE) || (src_px_N == src_px_NN)) {
dst_px_NE = smash2(src_px_N, smash2(src_px_N, src_px_NE));
} else {
dst_px_NE = smash2 (src_px_N, src_px_NE);
}
} else if ((src_px == src_px_NE) && (src_px_N != src_px_E)) {
dst_px_NE = dst_px = src_px;
if ((src_px_S == src_px) || (src_px_NE == src_px_ENE)) {
dst_px_E = smash2 (src_px, smash2 (src_px, src_px_E));
} else {
dst_px_E = smash2 (src_px, src_px_E);
}
if ((src_px_NE == src_px_NNE) || (src_px_W == src_px)) {
dst_px_N = smash2 (src_px, smash2 (src_px, src_px_N));
} else {
dst_px_N = smash2 (src_px_N, src_px_NE);
}
} else if (src_px == src_px_NE && src_px_N == src_px_E) {
int r = 0;
r += magicnumber(src_px_E, src_px, src_px_NW, src_px_NN);
r += magicnumber(src_px_E, src_px, src_px_W, src_px_S);
r += magicnumber(src_px_E, src_px, src_px_NNE, src_px_ENE);
r += magicnumber(src_px_E, src_px, src_px_SE, src_px_EE);
if (r > 0) {
dst_px_E = dst_px_N = src_px_N;
dst_px = dst_px_NE = smash2(src_px, src_px_E);
} else if (r < 0) {
dst_px_NE = dst_px = src_px;
dst_px_E = dst_px_N = smash2(src_px, src_px_E);
} else {
dst_px_NE = dst_px = src_px;
dst_px_E = dst_px_N = src_px_N;
}
} else {
dst_px_NE = dst_px = smash2(src_px_N, src_px_E);
dst_px_NE = smash4(src_px_NE, src_px_NE, src_px_NE, dst_px_NE);
dst_px = smash4(src_px, src_px, src_px, dst_px);
dst_px_N = dst_px_E = smash2(src_px, src_px_NE);
dst_px_N = smash4(src_px_N, src_px_N, src_px_N, dst_px_N);
dst_px_E = smash4(src_px_E, src_px_E, src_px_E, dst_px_E);
}
// Write pixels to destination texture
imageStore(dst_tex, dst_pos_o, dst_px);
imageStore(dst_tex, ivec2(dst_pos_o.x, dst_pos_o.y+1), dst_px_N);
imageStore(dst_tex, ivec2(dst_pos_o.x+1, dst_pos_o.y), dst_px_E);
imageStore(dst_tex, ivec2(dst_pos_o.x+1, dst_pos_o.y+1), dst_px_NE);
// No fragments
discard;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment