// daedalus-fourier — H.264 luma qpel avg_mc01 (biprediction) (8x8, ¼-pel vertical), // V3D 7.1. Per H.264 §8.4.2.2.1 "d" position: // // dst[r,c] = ((clip255(mc02(s)[r,c]) + s[r,c] + 1) >> 1) // // Sibling of v3d_h264_qpel_mc02.comp with L2 step against src[r, c]. // // // avg_ variant for B-slice biprediction per H.264 §8.4.2.3.1: // dst[r,c] = avg(dst[r,c], mc01_value) // Caller pre-loads dst with the list0 prediction; this shader // folds in the list1 contribution. // // License: BSD-2-Clause. #version 450 #extension GL_EXT_shader_8bit_storage : require #extension GL_EXT_shader_explicit_arithmetic_types : require layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; layout(binding = 0) readonly buffer Src { uint8_t src[]; } u_src; layout(binding = 1) buffer Dst { uint8_t dst[]; } u_dst; layout(binding = 2) readonly buffer Meta { uvec4 meta[]; } u_meta; layout(push_constant) uniform PC { uint n_blocks, stride_u8, _p0, _p1; } pc; void main() { uint block_idx = gl_WorkGroupID.x; if (block_idx >= pc.n_blocks) return; uint lane = gl_LocalInvocationID.x; uint r = lane >> 3, c = lane & 7u; uint dst_off = u_meta.meta[block_idx].x; uint src_off = u_meta.meta[block_idx].y; uint stride = pc.stride_u8; uint col_base = src_off + c; int s_m2 = int(u_src.src[col_base + (r - 2u) * stride]); int s_m1 = int(u_src.src[col_base + (r - 1u) * stride]); int s_0 = int(u_src.src[col_base + r * stride]); int s_p1 = int(u_src.src[col_base + (r + 1u) * stride]); int s_p2 = int(u_src.src[col_base + (r + 2u) * stride]); int s_p3 = int(u_src.src[col_base + (r + 3u) * stride]); int v = s_m2 - 5 * s_m1 + 20 * s_0 + 20 * s_p1 - 5 * s_p2 + s_p3 + 16; int vp = clamp(v >> 5, 0, 255); int avg = (vp + s_0 + 1) >> 1; // L2 with src[r, c] uint final_off = dst_off + r * stride + c; int prev = int(u_dst.dst[final_off]); u_dst.dst[final_off] = uint8_t((prev + avg + 1) >> 1); }