У меня есть массив структур, содержащих два целых числа без знака.Я хочу отсортировать их в соответствии с первой информацией, используя Битоническую сортировку.Я реализовал этот код здесь , который был в DirectX (я преобразовал его в glsl).все работает, но производительность страдает.Сортировка процессора делает это в 10 раз быстрее (используя std :: sort), я что-то упустил ??
Примечание: это работает на 100%, единственная проблема - производительность.Я думаю, что-то делать с синхронизацией потоков и доступа к памяти.
Сортировка выполняется по первому элементу в структуре (Elem.c)
Битоновая сортировка (GLSL):
layout(local_size_x = 512) in;
struct Elem {
uint c;
uint p;
};
layout(std430, binding = 4) buffer IndexList {
Elem es[];
};
uniform uint u_Level;
uniform uint u_LevelMask;
shared Elem shared_data[512];
void main() {
// Load shared data
shared_data[gl_LocalInvocationIndex] = es[gl_GlobalInvocationID.x];
barrier();
// Sort the shared data
for (uint j = u_Level >> 1; j > 0; j >>= 1) {
Elem result = ((shared_data[gl_LocalInvocationIndex & ~j].c <= shared_data[gl_LocalInvocationIndex | j].c)
== bool(u_LevelMask & gl_GlobalInvocationID.x)) ?
shared_data[gl_LocalInvocationIndex ^ j] : shared_data[gl_LocalInvocationIndex];
barrier();
shared_data[gl_LocalInvocationIndex] = result;
barrier();
}
// Store shared data
es[gl_GlobalInvocationID.x] = shared_data[gl_LocalInvocationIndex];
}
и Транспонирование
#define XSIZE 16
#define YSIZE 16
layout(local_size_x = XSIZE ,local_size_y = YSIZE, local_size_z = 1) in;
struct Elem {
uint c;
uint p;
};
layout(std430, binding = 4) buffer InputBUF {
Elem inputElem[];
};
layout(std430, binding = 5) buffer OutputBUF {
Elem outputElem[];
};
uniform uint u_Width;
uniform uint u_Height;
shared Elem shared_data[XSIZE * YSIZE];
void main() {
shared_data[gl_LocalInvocationIndex] = inputElem[gl_GlobalInvocationID.y * u_Width + gl_GlobalInvocationID.x];
barrier();
uvec2 XY = gl_GlobalInvocationID.yx - gl_LocalInvocationID.yx + gl_LocalInvocationID.xy;
outputElem[XY.y * u_Height + XY.x] = shared_data[gl_LocalInvocationID.x * XSIZE + gl_LocalInvocationID.y];
}
#define BITONIC_BLOCK_SIZE 512
#define TRANSPOSE_BLOCK_SIZE 16
// The number of elements to sort is limited to an even power of 2
// At minimum 8,192 elements - BITONIC_BLOCK_SIZE * TRANSPOSE_BLOCK_SIZE
// At maximum 262,144 elements - BITONIC_BLOCK_SIZE * BITONIC_BLOCK_SIZE
const uint MATRIX_WIDTH = BITONIC_BLOCK_SIZE;
const uint MATRIX_HEIGHT = N / BITONIC_BLOCK_SIZE;
Bitonic->BindSSBO(*IndexList, "IndexList", 4);
for (uint level = 2; level <= BITONIC_BLOCK_SIZE; level <<= 1) {
Bitonic->SetUniform1ui("u_Level", level);
Bitonic->SetUniform1ui("u_LevelMask", level);
Bitonic->DispatchCompute(N / BITONIC_BLOCK_SIZE, 1, 1);
}
for (uint level = BITONIC_BLOCK_SIZE << 1; level <= N; level <<= 1) {
// Transpose the data from buffer 1 into buffer 2
Transposer->BindSSBO(*IndexList, "InputBUF", 4);
Transposer->BindSSBO(*SecondaryIndexList, "OutputBUF", 5);
Transposer->SetUniform1ui("u_Width", MATRIX_WIDTH);
Transposer->SetUniform1ui("u_Height", MATRIX_HEIGHT);
Transposer->DispatchCompute(MATRIX_WIDTH / TRANSPOSE_BLOCK_SIZE, MATRIX_HEIGHT / TRANSPOSE_BLOCK_SIZE, 1);
// Sort the transposed column data
Bitonic->BindSSBO(*SecondaryIndexList, "IndexList", 4);
Bitonic->SetUniform1ui("u_Level", level / BITONIC_BLOCK_SIZE);
Bitonic->SetUniform1ui("u_LevelMask", (level & ~N)/BITONIC_BLOCK_SIZE);
Bitonic->DispatchCompute(N / BITONIC_BLOCK_SIZE, 1, 1);
// Transpose the data from buffer 2 back into buffer 1
Transposer->BindSSBO(*SecondaryIndexList, "InputBUF", 4);
Transposer->BindSSBO(*IndexList, "OutputBUF", 5);
Transposer->SetUniform1ui("u_Width", MATRIX_HEIGHT);
Transposer->SetUniform1ui("u_Height", MATRIX_WIDTH);
Transposer->DispatchCompute(MATRIX_HEIGHT / TRANSPOSE_BLOCK_SIZE, MATRIX_WIDTH / TRANSPOSE_BLOCK_SIZE, 1);
// Sort the row data
Bitonic->BindSSBO(*IndexList, "IndexList", 4);
Bitonic->SetUniform1ui("u_Level", BITONIC_BLOCK_SIZE);
Bitonic->SetUniform1ui("u_LevelMask", level);
Bitonic->DispatchCompute(N / BITONIC_BLOCK_SIZE, 1, 1);
}