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

#version 450
#extension GL_KHR_shader_subgroup_shuffle : require

// NOTE: Current subgroup utilization is suboptimal on most GPUs, so
// it will be nice to process two tiles at once here.
layout (local_size_x = 16, 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 sizes[16];
} info;

#define MICRO_TILE_DIM      8
#define TEXELS_PER_ELEMENT  4

void main() {
    uint p0 = in_data[gl_GlobalInvocationID.x];
    uint p1 = subgroupShuffleXor(p0, 1);
    uint hword = gl_LocalInvocationID.x & 1;
    uint dst_tx = (hword == 1)
        ? (p0 & 0xffff0000) | (p1 >> 16)
        : (p0 & 0x0000ffff) | (p1 << 16);

    uint col = (gl_LocalInvocationID.x >> 2) & 1;
    uint row = (gl_LocalInvocationID.x % TEXELS_PER_ELEMENT)
                + TEXELS_PER_ELEMENT * (gl_LocalInvocationID.x >> 3);

    uint mip = 0;
    for (int m = 0; m < info.num_levels; ++m) {
        mip += (gl_GlobalInvocationID.x * 4) >= info.sizes[m] ? 1 : 0;
    }

    uint tiles_per_pitch = max((info.pitch >> mip) / 8, 1);
    uint target_tile_x = gl_WorkGroupID.x % tiles_per_pitch;
    uint target_tile_y = gl_WorkGroupID.x / tiles_per_pitch;
    uint dw_ofs_x = target_tile_x * 2 + col; // 2 = uints
    uint dw_ofs_y = (target_tile_y * MICRO_TILE_DIM + row) * tiles_per_pitch * 2; // 2 = uints
    out_data[dw_ofs_x + dw_ofs_y] = dst_tx;
}
