2016-06-14 7 views
0

Как вычислительный шейдер разделяет задачи?Как задачи разделяются с помощью вычислительных шейдеров?

#version 430 core 
layout (local_size_x = 64) in; 


layout(std430, binding=4) buffer INFO 
{ 
     vec2 info[]; 
}; 


void main() 
{ 

    uint gid = gl_GlobalInvocationID.x; 
    info[gid].x += 1.0; 
    info[gid].y += 1.0; 
    memoryBarrier(); 
} 

в этом примере, путем указания local_size_x = 64, это означает, что, что каждая рабочая группа будет автоматически иметь 64 потоков, а так как вход массив vec2, он знает, что нужно просто пройти через главное с каждым vec2 на отдельный поток?

Кроме того, что бы я сделал, если бы шейдер должен был генерировать 10 vec2 для каждого входа vec2, а затем я хотел сделать что-то другое с каждым из них, каждый в отдельном потоке. Начальные 64 потока будут входить в 640. Может ли это быть сделано в этом же шейдере, или мне нужно сделать второй?

ответ

0

в этом примере, путем указания local_size_x = 64, это означает, что, что каждая рабочая группа будет автоматически иметь 64 потоков, а так как вход массив vec2, он знает, что нужно просто пройти через главное с каждым vec2 на А отдельный поток?

Да, вот как invocations within a work group are defined.

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

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

Назначение рабочих элементов в рабочей группе - разрешить этим локальным вызовам связываться друг с другом и помогать им что-то вычислять. Если у вас нет shared variables or barrier calls, то на самом деле не имеет значения, каков ваш локальный размер (ну, не с точки зрения функциональности. Локальный размер может повлиять на производительность).

Таким образом, вы должны выбрать свой местный размер в зависимости от того, какую работу вы намерены засунуть в конкретную операцию отправки. Прямо сейчас вы должны обработать vec2 с целыми кратными 64. Если многие вызовы одной и той же группы читают одни и те же значения, вам нужно переоценить, сколько будет работать полная группа.

Ограничение количества вызовов в рабочей группе зависит от оборудования, но будет равно 1024. Таким образом, у вас есть место для игры.

В вашей новой системе, если вы все еще хотите вызвать рабочую группу для обработки 64 входов, то, очевидно, рабочая группа должна иметь локальный размер, составляющий 640. Я бы предположил, что меньшая степень детализации, например 8, размер в общей сложности 80.

Какой бы размер вы ни выбрали, лучший способ на самом деле указать это, используя тот факт, что локальный размер имеет несколько измерений. Размер X должен относиться к входному индексу, причем размер Y является выходным индексом с входа X. Таким образом, размер Y будет равен 10, а размер X будет 8 или 64 или что угодно.

Поэтому, когда вы идете, чтобы принести свой вклад, индекс вам нужно это:

const uvec3 size_mult = {1, gl_NumWorkGroups.x, gl_NumWorkGroups.x * gl_NumWorkGroups.y}; 
const uint input_index = gl_WorkGroupSize.x * dot(gl_WorkGroupID, size_mult) + gl_LocalInvocationID.x; 

Индекс для вывода будет:

const uint output_index = gl_WorkGroupSize.y * input_index + gl_LocalInvocationID.y;