449ec2ab07
Write out a 2-bit code per block and avoid loading the mask when it matches these two common cases. Apply this optimization when the mask is relatively large (i.e. prompt processing).
143 lines
4.8 KiB
Plaintext
143 lines
4.8 KiB
Plaintext
#version 450
|
|
|
|
#extension GL_EXT_control_flow_attributes : enable
|
|
#extension GL_EXT_shader_16bit_storage : enable
|
|
#extension GL_KHR_shader_subgroup_arithmetic : enable
|
|
|
|
layout (constant_id = 0) const uint BLOCK_SIZE = 128;
|
|
layout (constant_id = 1) const uint NUM_SUBGROUPS = 4;
|
|
layout (constant_id = 2) const uint Br = 32;
|
|
layout (constant_id = 3) const uint Bc = 32;
|
|
|
|
layout(local_size_x_id = 0, local_size_y = 1, local_size_z = 1) in;
|
|
|
|
layout (binding = 0) readonly buffer A {float16_t data_a[];};
|
|
layout (binding = 0) readonly buffer Av4 {f16vec4 data_av4[];};
|
|
layout (binding = 1) writeonly buffer D {uint data_d[];};
|
|
|
|
layout (push_constant) uniform parameter {
|
|
uint nem0;
|
|
uint nem1;
|
|
uint nem2;
|
|
uint nbm1;
|
|
uint nbm2;
|
|
uint nbm3;
|
|
uint nbd1;
|
|
uint nbd2;
|
|
uint nbd3;
|
|
};
|
|
|
|
#define MASK_OPT_ALL_NEG_INF 1
|
|
#define MASK_OPT_ALL_ZERO 2
|
|
|
|
shared float minsh[NUM_SUBGROUPS];
|
|
shared float maxsh[NUM_SUBGROUPS];
|
|
|
|
// For each Br x Bc block of the mask (input) buffer, read all values and check
|
|
// if it's all -inf or all zero. Write out a two-bit code indicating which it is
|
|
// (or zero for neither). Each workgroup processes 16 tiles and writes out a
|
|
// 32-bit result mask.
|
|
//
|
|
// TODO: This is a lot of work per workgroup, might make sense to split this into
|
|
// more workgroups in the future.
|
|
void main() {
|
|
// Each workgroup handles a row
|
|
const uint tid = gl_LocalInvocationIndex;
|
|
const uint i0 = gl_WorkGroupID.x;
|
|
const uint i1 = gl_WorkGroupID.y;
|
|
const uint i2 = gl_WorkGroupID.z % nem2;
|
|
const uint i3 = gl_WorkGroupID.z / nem2;
|
|
|
|
float FLT_MAX_OVER_2 = uintBitsToFloat(0x7EFFFFFF);
|
|
|
|
uint result = 0;
|
|
|
|
// Fast path for fully in-bounds blocks where we can do f16vec4 loads
|
|
if ((nem0 % Bc) == 0 && (nem1 % Br) == 0 &&
|
|
((Br * Bc) % (BLOCK_SIZE * 4)) == 0) {
|
|
[[unroll]] for (uint block_x = 0; block_x < 16; ++block_x) {
|
|
float min_v = FLT_MAX_OVER_2;
|
|
float max_v = -FLT_MAX_OVER_2;
|
|
[[unroll]] for (uint i = 0; i < Br * Bc / 4; i += BLOCK_SIZE) {
|
|
uint j0 = (i + tid) % (Bc / 4);
|
|
uint j1 = (i + tid) / (Bc / 4);
|
|
|
|
j0 *= 4;
|
|
j0 += (i0 * 16 + block_x) * Bc;
|
|
j1 += i1 * Br;
|
|
|
|
vec4 f = vec4(data_av4[(j0 + j1 * nbm1 + i2 * nbm2 + i3 * nbm3) / 4]);
|
|
[[unroll]] for (int c = 0; c < 4; ++c) {
|
|
min_v = min(min_v, f[c]);
|
|
max_v = max(max_v, f[c]);
|
|
}
|
|
}
|
|
min_v = subgroupMin(min_v);
|
|
max_v = subgroupMax(max_v);
|
|
if (gl_SubgroupInvocationID == 0) {
|
|
minsh[gl_SubgroupID] = min_v;
|
|
maxsh[gl_SubgroupID] = max_v;
|
|
}
|
|
barrier();
|
|
if (tid == 0) {
|
|
[[unroll]] for (uint i = 0; i < NUM_SUBGROUPS; ++i) {
|
|
min_v = min(min_v, minsh[i]);
|
|
max_v = max(max_v, maxsh[i]);
|
|
}
|
|
if (max_v <= -FLT_MAX_OVER_2) {
|
|
result |= 1 << (2*block_x);
|
|
}
|
|
if (min_v == 0.0f && max_v == 0.0f) {
|
|
result |= 2 << (2*block_x);
|
|
}
|
|
}
|
|
barrier();
|
|
}
|
|
} else {
|
|
[[unroll]] for (uint block_x = 0; block_x < 16; ++block_x) {
|
|
float min_v = FLT_MAX_OVER_2;
|
|
float max_v = -FLT_MAX_OVER_2;
|
|
[[unroll]] for (uint i = 0; i < Br * Bc; i += BLOCK_SIZE) {
|
|
if ((Br * Bc % BLOCK_SIZE) != 0 && i + tid >= Br * Bc) {
|
|
continue;
|
|
}
|
|
uint j0 = (i + tid) % Bc;
|
|
uint j1 = (i + tid) / Bc;
|
|
|
|
j0 += (i0 * 16 + block_x) * Bc;
|
|
j1 += i1 * Br;
|
|
|
|
if (j0 < nem0 && j1 < nem1) {
|
|
float f = float(data_a[j0 + j1 * nbm1 + i2 * nbm2 + i3 * nbm3]);
|
|
min_v = min(min_v, f);
|
|
max_v = max(max_v, f);
|
|
}
|
|
}
|
|
min_v = subgroupMin(min_v);
|
|
max_v = subgroupMax(max_v);
|
|
if (gl_SubgroupInvocationID == 0) {
|
|
minsh[gl_SubgroupID] = min_v;
|
|
maxsh[gl_SubgroupID] = max_v;
|
|
}
|
|
barrier();
|
|
if (tid == 0) {
|
|
[[unroll]] for (uint i = 0; i < NUM_SUBGROUPS; ++i) {
|
|
min_v = min(min_v, minsh[i]);
|
|
max_v = max(max_v, maxsh[i]);
|
|
}
|
|
if (max_v <= -FLT_MAX_OVER_2) {
|
|
result |= 1 << (2*block_x);
|
|
}
|
|
if (min_v == 0.0f && max_v == 0.0f) {
|
|
result |= 2 << (2*block_x);
|
|
}
|
|
}
|
|
barrier();
|
|
}
|
|
}
|
|
|
|
if (tid == 0) {
|
|
data_d[i0 + i1 * nbd1 + i2 * nbd2 + i3 * nbd3] = result;
|
|
}
|
|
}
|