簡體   English   中英

計算着色器 - 如何全局同步線程?

[英]Compute shaders - how to globally synchronize threads?

編輯:我已經改寫了這個問題,使其更加通用並簡化了代碼。

我可能在計算着色器中缺少線程同步的東西。 我有一個簡單的計算着色器,可以對某些數字進行並行縮減,然后我需要修改最終的總和:

#version 430 core
#define SIZE 256
#define CLUSTERS 5

layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;

struct Cluster {
    vec3 cntr;
    uint size;
};
coherent restrict layout(std430, binding = 0) buffer destBuffer {
    Cluster clusters[CLUSTERS];
};
shared uint sizeCache[SIZE];

void main() {
    const ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
    const uint id = pos.y * (gl_WorkGroupSize.x + gl_NumWorkGroups.x) + pos.x;

    if(id < CLUSTERS) {
        clusters[id].size = 0;
    }

    memoryBarrierShared();
    barrier();
    sizeCache[gl_LocalInvocationIndex] = 1;
    int stepv = (SIZE >> 1); 
    while(stepv > 0) { //reduction over data in each working group
        if (gl_LocalInvocationIndex < stepv) {
            sizeCache[gl_LocalInvocationIndex] += sizeCache[gl_LocalInvocationIndex + stepv];
        }
        memoryBarrierShared();
        barrier();
        stepv = (stepv >> 1);
    }
    if (gl_LocalInvocationIndex == 0) {
        atomicAdd(clusters[0].size, sizeCache[0]);
    }

    memoryBarrier();
    barrier();

    if(id == 0) {
        clusters[0].size = 23; //this doesn't do what I would expect
        clusters[1].size = 13; //this works
    }
}

減少工作並產生正確的結果 如果我評論最后一個條件, clusters[0].size的值是262144,這是正確的(它是線程數)。 如果我取消注釋它,我希望得到值23,因為根據我的理解, barrier()之后的線程應該同步,並且在memoryBarrier()所有先前的內存更改都應該是可見的。 但是它不起作用,它產生的結果如259095.I我猜測值23由之前的另一個線程的atomicAdd重寫,但我不明白為什么。

這是我在CPU上讀取結果的方式:

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, resultBuffer);

//currently it dispatches 262144 threads
glDispatchCompute(32, 32, 1);
glCheckError();

glMemoryBarrier(GL_ALL_BARRIER_BITS); //for debug

struct Cl {
    glm::vec3 cntr;
    uint size;
};

glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, resultBuffer);

std::vector<Cl> data(5);
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeOfresult, &data[0]);

我有NVIDIA GT630M卡和linux與nvidia專有驅動程序(331.49)。

您無法全局同步線程,即跨工作組。 GuyRT的評論指出了這一點。 在您的代碼中,一個工作組可以命中

clusters[0].size = 23;

而另一個工作組正在愉快地進行原子增量。 因為它只是第一個工作組的第一個線程進入if(id==0)塊,並且大多數GPU按順序調度工作組,然后該值將被寫入一次,然后由其他值增加很多次(大多數)工作組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM