duckstation/data/resources/shaders/system/texscale-scale2x.comp

56 lines
1.5 KiB
Plaintext

#version 460 core
// EPX.glc
// Copyright 2020 Morgan McGuire & Mara Gagiu,
// provided under the Open Source MIT license https://opensource.org/licenses/MIT
// Implementation of Eric Johnston and Andrea Mazzoleni's
// EPX aka Scale2X algorithm based on https://www.scale2x.it/algorithm
#define ABGR8 uint
UNIFORM_BLOCK_LAYOUT uniform UBOBlock {
ivec2 src_size;
ivec2 dst_size;
};
TEXTURE_LAYOUT(0) uniform sampler2D samp0;
IMAGE_LAYOUT(0, rgba8) uniform restrict writeonly image2D dst_image;
ABGR8 src(int x, int y) {
return packUnorm4x8(texelFetch(samp0, ivec2(x, y), 0));
}
void dst(int x, int y, ABGR8 value) {
imageStore(dst_image, ivec2(x, y), unpackUnorm4x8(value));
}
layout(local_size_x = 8, local_size_y = 8) in;
void main () {
// EPX first falls back to Nearest Neighbour
int srcX = int(gl_GlobalInvocationID.x);
int srcY = int(gl_GlobalInvocationID.y);
if (srcX >= src_size.x || srcY >= src_size.y)
return;
ABGR8 E = src(srcX, srcY);
ABGR8 J = E, K = E, L = E, M = E;
ABGR8 B = src(srcX + 0, srcY - 1);
ABGR8 D = src(srcX - 1, srcY + 0);
ABGR8 F = src(srcX + 1, srcY + 0);
ABGR8 H = src(srcX + 0, srcY + 1);
if (D == B && B != F && D != H) J = D;
if (B == F && D != F && H != F) K = F;
if (H == D && F != D && B != D) L = D;
if (H == F && D != H && B != F) M = F;
// Write four pixels at once
dst(srcX * 2, srcY * 2, J);
dst(srcX * 2 + 1, srcY * 2, K);
dst(srcX * 2, srcY * 2 + 1, L);
dst(srcX * 2 + 1, srcY * 2 + 1, M);
}