// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#version 450

layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;

layout(std430, binding = 0) buffer input_buf {
    uint in_data[];
};
layout(std430, binding = 1) buffer output_buf {
    uint out_data[];
};

layout(push_constant) uniform image_info {
    uint num_levels;
    uint pitch;
    uint height;
    uint c0;
    uint c1;
} info;

const uint lut_64bpp[][16] = {
    {
        0x09080100, 0x49484140, 
        0x0b0a0302, 0x4a4b4342,
        0x19181110, 0x59585150,
        0x1b1a1312, 0x5a5b5352,
        0x89888180, 0xc9c8c1c0,
        0x8b8a8382, 0xcacbc3c2,
        0x99989190, 0xd9d8d1d0,
        0x9b9a9392, 0xdbdad3d2,
    },
    {
        0x0d0c0504, 0x4d4c4544,
        0x0f0e0706, 0x4f4e4746,
        0x1d1c1514, 0x5d5c5554,
        0x1f1e1716, 0x5f5e5756,
        0x8d8c8584, 0xcdccc5c4,
        0x8f8e8786, 0xcfcec7c6,
        0x9d9c9594, 0xdddcd5d4,
        0x9f9e9796, 0xdfded7d6,
    },
    {
        0x29282120, 0x69686160,
        0x2b2a2322, 0x6b6a6362,
        0x39383130, 0x79787170,
        0x3b3a3332, 0x7b7a7372,
        0xa9a8a1a0, 0xe9e8e1e0,
        0xabaaa3a2, 0xebeae3e2,
        0xb9b8b1b0, 0xf9f8f1f0,
        0xbbbab3b2, 0xfbfaf3f2,
    },
    {
        0x2d2c2524, 0x6d6c6564,
        0x2f2e2726, 0x6f6e6766,
        0x3d3c3534, 0x7d7c7574,
        0x3f3e3736, 0x7f7e7776,
        0xadaca5a4, 0xedece5e4,
        0xafaea7a6, 0xefeee7e6,
        0xbdbcb5b4, 0xfdfcf5f4,
        0xbfbeb7b6, 0xfffef7f6,
    },
};

#define MICRO_TILE_DIM      8
#define MICRO_TILE_SZ       2048
#define TEXELS_PER_ELEMENT  1
#define BPP                 64

void main() {
    uint x =  gl_GlobalInvocationID.x % info.pitch;
    uint y = (gl_GlobalInvocationID.x / info.pitch) % info.height;
    uint z =  gl_GlobalInvocationID.x / (info.pitch * info.height);

    uint col = bitfieldExtract(x, 0, 3);
    uint row = bitfieldExtract(y, 0, 3);
    uint lut = bitfieldExtract(z, 0, 2);
    uint idx_dw = lut_64bpp[lut][(col + row * MICRO_TILE_DIM) >> 2u];
    uint byte_ofs = gl_LocalInvocationID.x & 3u;
    uint idx = bitfieldExtract(idx_dw >> (8 * byte_ofs), 0, 8);

    uint slice_offs = (z >> 2u) * info.c1 * MICRO_TILE_SZ;
    uint tile_row = y / MICRO_TILE_DIM;
    uint tile_column = x / MICRO_TILE_DIM;
    uint tile_offs = ((tile_row * info.c0) + tile_column) * MICRO_TILE_SZ;
    uint offs = slice_offs + tile_offs + (idx * BPP / 8);

    uint p0 = in_data[(offs >> 2) + 0];
    uint p1 = in_data[(offs >> 2) + 1];
    out_data[2 * gl_GlobalInvocationID.x + 0] = p0;
    out_data[2 * gl_GlobalInvocationID.x + 1] = p1;
}
