// EBU 100% bars, Rec.709, 10-bit Y'CbCr, packed as v210 (4:2:2). // One work-item per 16-byte block = 6 pixels (6 Y + 3 Cb + 3 Cr). struct Params { width: u32, height: u32, frame: u32, // animation tick (0,1,2,... per generated frame), NOT the raw grain index _pad0: u32, }; @group(0) @binding(0) var out: array; @group(0) @binding(1) var params: Params; fn bar_index(px: u32) -> u32 { return min((px * 8u) / params.width, 7u); } @compute @workgroup_size(64) fn main(@builtin(global_invocation_id) gid: vec3) { let block = gid.x; let total = (params.width * params.height) / 6u; if (block >= total) { return; } let x = (block * 6u) % params.width; let py = (block * 6u) / params.width; // Bar order: 100% white, yellow, cyan, green, magenta, red, blue, black let y_tab = array(940u, 877u, 754u, 691u, 313u, 250u, 127u, 64u); let cb_tab = array(512u, 64u, 615u, 167u, 857u, 409u, 960u, 512u); let cr_tab = array(512u, 553u, 64u, 105u, 919u, 960u, 471u, 512u); // Moving square: horizontal oscillation around screen center. // frame is a small tick; converting the huge raw grain index here // would destroy f32 precision and freeze the motion. let centerX = f32(params.width) / 2.0; let centerY = f32(params.height) / 2.0; let fps = 25.0; let t = f32(params.frame) / fps; const squareSize = 150u; let half = f32(squareSize) / 2.0; let offsetPixels = sin(t * 0.5) * (centerX - half); let sq_x_min = centerX - half + offsetPixels; let sq_x_max = centerX + half + offsetPixels; let sq_y_min = centerY - half; let sq_y_max = centerY + half; let py_f = f32(py); var y: array; var cb: array; var cr: array; for (var i = 0u; i < 6u; i++) { let px = f32(x + i); let b = bar_index(x + i); if (px >= sq_x_min && px < sq_x_max && py_f >= sq_y_min && py_f < sq_y_max) { // inverted bar: luma mirrored across studio range (64..940), // chroma mirrored across neutral 512 y[i] = 1004u - y_tab[b]; cb[i] = 1024u - cb_tab[b]; cr[i] = 1024u - cr_tab[b]; } else { y[i] = y_tab[b]; cb[i] = cb_tab[b]; cr[i] = cr_tab[b]; } } // v210 word layout, chroma co-sited with luma samples 0/2/4: // w0 = Cb0|Y0<<10|Cr0<<20; w1 = Y1|Cb2<<10|Y2<<20; // w2 = Cr2|Y3<<10|Cb4<<20; w3 = Y4|Cr4<<10|Y5<<20 out[block * 4u + 0u] = (cb[0] & 0x3FFu) | ((y[0] & 0x3FFu) << 10u) | ((cr[0] & 0x3FFu) << 20u); out[block * 4u + 1u] = (y[1] & 0x3FFu) | ((cb[2] & 0x3FFu) << 10u) | ((y[2] & 0x3FFu) << 20u); out[block * 4u + 2u] = (cr[2] & 0x3FFu) | ((y[3] & 0x3FFu) << 10u) | ((cb[4] & 0x3FFu) << 20u); out[block * 4u + 3u] = (y[4] & 0x3FFu) | ((cr[4] & 0x3FFu) << 10u) | ((y[5] & 0x3FFu) << 20u); }