#version 450 #extension GL_EXT_shader_16bit_storage : require #extension GL_EXT_control_flow_attributes : require #include "types.glsl" layout (push_constant) uniform parameter { BDA_STORAGE_T dst_addr; uint batch_offset; uint offset_delta; uint IC; uint IW; uint IH; uint OW; uint OH; uint KW; uint KH; uint OH_batch; uint CHW; int s0; int s1; int p0; int p1; int d0; int d1; uint batch_IC; } p; layout(constant_id = 0) const uint BLOCK_SIZE = 32; const uint NUM_ITER = 512 / BLOCK_SIZE; layout(local_size_x_id = 0, local_size_y = 1, local_size_z = 1) in; layout (binding = 0) readonly buffer X {A_TYPE data_a[];}; layout (binding = 1) writeonly buffer D {D_TYPE data_d[];}; #if BDA layout (buffer_reference) buffer D_ptr {D_TYPE d;}; #endif void im2col(const uint ow, const uint z_idx) { const uint oh = z_idx % p.OH; const uint batch_idx = z_idx / p.OH; const uint gidx = gl_LocalInvocationID.x; const uint src_batch = batch_idx * p.batch_offset; const BDA_OFFSET_T dst_row = ((BDA_OFFSET_T(batch_idx) * p.OH + oh) * p.OW + ow) * p.CHW; const uint KHKW = p.KH * p.KW; // Precompute base input coordinates const int base_iw = int(ow * p.s0) - p.p0; const int base_ih = int(oh * p.s1) - p.p1; // Precompute step deltas const uint delta_ic = BLOCK_SIZE / KHKW; const uint delta_rem = BLOCK_SIZE % KHKW; const uint delta_ky = delta_rem / p.KW; const uint delta_kx = delta_rem % p.KW; const uint delta_ic_offset = delta_ic * p.offset_delta; // If using BDA mode, precompute the base pointer and step size #if BDA const BDA_STORAGE_T base_dst_addr = p.dst_addr + D_SIZE * dst_row; const uint bda_step = D_SIZE * BLOCK_SIZE; #endif uint wg_x = gl_WorkGroupID.x; do { const uint wg_offset = wg_x * 512; uint chw_idx = wg_offset + gidx; uint ic = chw_idx / KHKW; uint rem = chw_idx % KHKW; uint ky = rem / p.KW; uint kx = rem % p.KW; uint ic_offset = src_batch + ic * p.offset_delta; // Initialize running pointer/index for the destination buffer #if BDA BDA_STORAGE_T current_dst_addr = base_dst_addr + D_SIZE * chw_idx; #else uint current_dst_idx = dst_row + chw_idx; #endif [[unroll]] for (uint i = 0; i < NUM_ITER; ++i) { if (chw_idx >= p.CHW) { return; } const int iiw = base_iw + int(kx * p.d0); const int iih = base_ih + int(ky * p.d1); A_TYPE val = A_TYPE(0); if (uint(iih) < p.IH && uint(iiw) < p.IW) { val = data_a[ic_offset + uint(iih) * p.IW + uint(iiw)]; } #if BDA D_ptr(current_dst_addr).d = D_TYPE(val); current_dst_addr += bda_step; #else data_d[current_dst_idx] = D_TYPE(val); current_dst_idx += BLOCK_SIZE; #endif chw_idx += BLOCK_SIZE; ic_offset += delta_ic_offset; kx += delta_kx; ky += delta_ky; // Handle X axis wrap uint kx_wrap = uint(kx >= p.KW); kx -= kx_wrap * p.KW; ky += kx_wrap; // Handle Y axis wrap uint ky_wrap = uint(ky >= p.KH); ky -= ky_wrap * p.KH; ic_offset += ky_wrap * p.offset_delta; } wg_x += gl_NumWorkGroups.x; } while (wg_x * 512 < p.CHW); } void main() { uint ow = gl_GlobalInvocationID.y; while (ow < p.OW) { uint z = gl_GlobalInvocationID.z; while (z < p.OH_batch) { im2col(ow, z); z += gl_NumWorkGroups.z; } ow += gl_NumWorkGroups.y; } }