Атомарные операции вычислительного шейдера GLES для float

Я использую компьютерный шейдер, чтобы получить значение суммы (тип float), например:

#version 320 es
layout(local_size_x = 640,local_size_y=480,local_size_z=1)
layout(binding = 0) buffer OutputData{
float sum[];
}output;
uniform sampler2D texture_1;
void main()
{
    vec2 texcoord(float(gl_LocalInvocationIndex.x)/640.0f,float(gl_LocalInvocationIndex.y)/480.0f);
    float val = textureLod(texture_1,texcoord,0.0).r;
//where need synchronize
    sum[0] = sum[0]+val;
//Here i want to get the sum of all val in texture_1 first channal
}

Я знаю, что есть атомарные операции, такие как atomicAdd(), но не поддерживают параметр float и барьер(), который, похоже, не решает мою проблему. Может быть, я могу записать поплавок в int или есть какой-то простой способ решить мою проблему?


person KaguyaSan    schedule 13.01.2020    source источник


Ответы (1)


Atomics, как правило, очень слабы с точки зрения производительности, особенно если им сильно мешает параллельный доступ из множества потоков, поэтому я бы не рекомендовал их для этого варианта использования.

Чтобы сохранить параллелизм, вам действительно нужна какая-то стратегия многопроходного сокращения. Псевдокод, что-то вроде этого:

array_size = N
data = input_array

while array_size > 1:
   spawn pass with M = array_size/2 threads.
   thread M: out[M] = data[2*M] + data[2*M+1]
   array_size = M
   data = out

Это простое сокращение 2:1, что дает производительность O(log2(N)), но вы можете сделать большее сокращение за проход, чтобы уменьшить пропускную способность памяти промежуточного хранилища. Для графического процессора, использующего текстуры в качестве входных данных, соотношение 4:1 вполне приемлемо (вы можете использовать textureGather или даже простой линейный фильтр для загрузки нескольких сэмплов в одной операции текстурирования).

person solidpixel    schedule 15.01.2020