#version 450 layout(local_size_x = 16, local_size_y = 16) in; layout(binding = 0) readonly buffer V210Data { uint data[]; } v210; layout(binding = 1, rgba8) uniform writeonly image2D dstImage; layout(push_constant) uniform PushConstants { uint srcWidth; uint srcHeight; uint srcStrideBytes; uint dstWidth; uint dstHeight; }; void main() { ivec2 dstPos = ivec2(gl_GlobalInvocationID.xy); if (dstPos.x >= int(dstWidth) || dstPos.y >= int(dstHeight)) return; uint sx = uint(dstPos.x) * srcWidth / dstWidth; uint sy = uint(dstPos.y) * srcHeight / dstHeight; uint group = sx / 6; uint pos = sx % 6; uint strideWords = srcStrideBytes / 4; uint lineOffset = sy * strideWords; uint groupOffset = lineOffset + group * 4; uint w0 = v210.data[groupOffset + 0]; uint w1 = v210.data[groupOffset + 1]; uint w2 = v210.data[groupOffset + 2]; uint w3 = v210.data[groupOffset + 3]; uint cb0 = (w0 >> 0) & 0x3FFu; uint y0 = (w0 >> 10) & 0x3FFu; uint cr0 = (w0 >> 20) & 0x3FFu; uint y1 = (w1 >> 0) & 0x3FFu; uint cb2 = (w1 >> 10) & 0x3FFu; uint y2 = (w1 >> 20) & 0x3FFu; uint cr2 = (w2 >> 0) & 0x3FFu; uint y3 = (w2 >> 10) & 0x3FFu; uint cb4 = (w2 >> 20) & 0x3FFu; uint y4 = (w3 >> 0) & 0x3FFu; uint cr4 = (w3 >> 10) & 0x3FFu; uint y5 = (w3 >> 20) & 0x3FFu; uint y10, cb10, cr10; switch (pos) { case 0u: y10 = y0; cb10 = cb0; cr10 = cr0; break; case 1u: y10 = y1; cb10 = cb0; cr10 = cr0; break; case 2u: y10 = y2; cb10 = cb2; cr10 = cr2; break; case 3u: y10 = y3; cb10 = cb2; cr10 = cr2; break; case 4u: y10 = y4; cb10 = cb4; cr10 = cr4; break; default: y10 = y5; cb10 = cb4; cr10 = cr4; break; } int yp = int(y10) - 64; int cbp = int(cb10) - 512; int crp = int(cr10) - 512; int yp8 = yp >> 2; int cbp8 = cbp >> 2; int crp8 = crp >> 2; int r = (298 * yp8 + 459 * crp8 + 128) >> 8; int g = (298 * yp8 - 137 * crp8 - 55 * cbp8 + 128) >> 8; int b = (298 * yp8 + 541 * cbp8 + 128) >> 8; r = clamp(r, 0, 255); g = clamp(g, 0, 255); b = clamp(b, 0, 255); imageStore(dstImage, dstPos, vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0)); }