Я пытался написать общую реализацию вычислительного шейдера по Гауссу.
Он в основном работает, но содержит артефакты, которые меняют каждый кадр, даже когда сцена статична. Последние несколько часов я пытался отладить это. Я зашел так далеко, что убедился, что границы не превышены, развернул все циклы, заменил униформы константами, но артефакты остались.
Я протестировал исходный код с артефактами на 3 разных машинах / графических процессорах (2 NVIDIA, 1 Intel), и все они дали одинаковые результаты. Моделирование развернутой / постоянной версии выполнения кода с рабочими группами, выполняемыми вперед и назад с помощью простого кода C ++, не вызывает этих ошибок.
Выделив совместно используемый массив [96] [96] вместо [16] [48], я могу устранить большинство артефактов.
Это привело меня к мысли, что мне не хватает логической ошибки, поэтому мне удалось создать очень простой шейдер, который по-прежнему выдает ошибку в меньшем масштабе, я был бы признателен, если бы кто-нибудь мог указать причину. Я проверил много документации и не нашел ничего неправильного.
Выделяется общий массив размером 16x48 с плавающей запятой, это 3072 байта, примерно 10% минимального предела общей памяти.
Шейдер запускается в рабочих группах 16x16, поэтому каждый поток будет записывать в 3 уникальных места и читать обратно из одного уникального места.
Затем текстура визуализируется как HSV, при этом значения между 0–1 будут отображаться в оттенок 0–360 (красный-голубой-красный), а значения за пределами границ будут красными.
#version 430
//Execute in 16x16 sized thread blocks
layout(local_size_x=16,local_size_y=16) in;
uniform layout (r32f) restrict writeonly image2D _imageOut;
shared float hoz[16][48];
void main ()
{
//Init shared memory with a big out of bounds value we can identify
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = 20000.0f;
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y+16] = 20000.0f;
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y+32] = 20000.0f;
//Sync shared memory
memoryBarrierShared();
//Write the values we want to actually read back
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y] = 0.5f;
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y+16] = 0.5f;
hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y+32] = 0.5f;
//Sync shared memory
memoryBarrierShared();
//i=0,8,16 work
//i=1-7,9-5,17 don't work (haven't bothered testing further
const int i = 17;
imageStore(_imageOut, ivec2(gl_GlobalInvocationID.xy), vec4(hoz[gl_LocalInvocationID.x][gl_LocalInvocationID.y+i]));
//Sync shared memory (can't hurt)
memoryBarrierShared();
}
Запуск этого шейдера с размерами запуска больше 8x8 приводит к появлению артефактов в затронутой области изображения.
glDispatchCompute(9, 9, 0);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
Мне пришлось установить точку останова и пошаговые кадры, чтобы захватить это, потребовалось около 14 кадров < img src = "https://i.stack.imgur.com/M1RaQ.png" alt = "введите описание изображения здесь">
glDispatchCompute(512/16, 512/16, 0);//Full image is 512x512
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
Мне снова пришлось устанавливать точку останова и шагать кадры, чтобы захватить это, при работе со скоростью 60FPS (vsync) артефакты появлялись чаще / одновременно.