Files
2026-07-13 13:33:03 +08:00

153 lines
4.3 KiB
Plaintext

#version 440 core
layout(std430) buffer;
layout(set=0, binding=0) writeonly uniform image2D uOutValue;
layout(set=0, binding=1) writeonly uniform iimage2D uOutIndex;
layout(set=0, binding=2) uniform sampler2D uInput;
layout(set=0, binding=3) uniform constBuffer {
int rowSize;
int k;
int numRows;
int C4; // UP_DIV(rowSize, 4)
} uConst;
#define THREAD_NUMBER 128
#define LOCAL_K 8
#define CANDIDATE_NUMBER 1024
shared float sharedValue[CANDIDATE_NUMBER];
shared int sharedIndex[CANDIDATE_NUMBER];
layout(local_size_x = THREAD_NUMBER, local_size_y = 1, local_size_z = 1) in;
float readValue(int row, int idx) {
int c4 = idx >> 2;
int c = idx & 3;
vec4 v = texelFetch(uInput, ivec2(c4, row), 0);
if (c == 0) return v.x;
if (c == 1) return v.y;
if (c == 2) return v.z;
return v.w;
}
bool afterAsc(float aValue, int aIndex, float bValue, int bIndex) {
if (aValue > bValue) return true;
if (aValue < bValue) return false;
return aIndex > bIndex;
}
bool better(float aValue, int aIndex, float bValue, int bIndex) {
if (bIndex < 0) return true;
if (aIndex < 0) return false;
#ifdef SORT_DESC
if (aValue > bValue) return true;
if (aValue < bValue) return false;
#else
if (aValue < bValue) return true;
if (aValue > bValue) return false;
#endif
return aIndex < bIndex;
}
void main() {
int tid = int(gl_LocalInvocationID.x);
int row = int(gl_WorkGroupID.y);
if (tid >= THREAD_NUMBER || row >= uConst.numRows) {
return;
}
int rowSize = uConst.rowSize;
int k = uConst.k;
float initWorst = 3.402823466e+38;
float initBestWorst = -3.402823466e+38;
float localValue[LOCAL_K];
int localIndex[LOCAL_K];
#ifdef SORT_DESC
for (int i = 0; i < LOCAL_K; ++i) {
localValue[i] = initBestWorst;
localIndex[i] = -1;
}
#else
for (int i = 0; i < LOCAL_K; ++i) {
localValue[i] = initWorst;
localIndex[i] = -1;
}
#endif
for (int i = tid; i < rowSize; i += THREAD_NUMBER) {
float value = readValue(row, i);
if (!better(value, i, localValue[LOCAL_K - 1], localIndex[LOCAL_K - 1])) {
continue;
}
int insertPos = LOCAL_K;
for (int j = 0; j < LOCAL_K; ++j) {
if (better(value, i, localValue[j], localIndex[j])) {
insertPos = j;
break;
}
}
if (insertPos >= LOCAL_K) {
continue;
}
for (int j = LOCAL_K - 1; j > insertPos; --j) {
localValue[j] = localValue[j - 1];
localIndex[j] = localIndex[j - 1];
}
localValue[insertPos] = value;
localIndex[insertPos] = i;
}
int base = tid * LOCAL_K;
for (int i = 0; i < LOCAL_K; ++i) {
sharedValue[base + i] = localValue[i];
sharedIndex[base + i] = localIndex[i];
}
barrier();
for (int size = 2; size <= CANDIDATE_NUMBER; size <<= 1) {
for (int stride = size >> 1; stride > 0; stride >>= 1) {
for (int idx = tid; idx < CANDIDATE_NUMBER; idx += THREAD_NUMBER) {
int ixj = idx ^ stride;
if (ixj <= idx) {
continue;
}
bool up = ((idx & size) == 0);
#ifdef SORT_DESC
up = !up;
#endif
bool after = afterAsc(sharedValue[idx], sharedIndex[idx], sharedValue[ixj], sharedIndex[ixj]);
if (up == after) {
float tValue = sharedValue[idx];
sharedValue[idx] = sharedValue[ixj];
sharedValue[ixj] = tValue;
int tIndex = sharedIndex[idx];
sharedIndex[idx] = sharedIndex[ixj];
sharedIndex[ixj] = tIndex;
}
}
barrier();
}
}
if (tid == 0) {
int realK = min(k, rowSize);
for (int i = 0; i < realK; i += 4) {
vec4 values = vec4(0.0);
ivec4 indices = ivec4(0);
int count = min(4, realK - i);
for (int j = 0; j < count; ++j) {
values[j] = sharedValue[i + j];
indices[j] = sharedIndex[i + j];
}
imageStore(uOutValue, ivec2(i >> 2, row), values);
imageStore(uOutIndex, ivec2(i >> 2, row), indices);
}
}
}