簡體   English   中英

OpenGL計算着色器中的簡單原子計數器測試問題

[英]Issue with simple atomic counter test in OpenGL compute shader

我一直在嘗試通過一些瑣碎的示例來圍繞內存同步和一致性問題。

在此,我將分派具有8x8x1大小的工作組的計算着色器。 工作組的數量足以覆蓋屏幕,即720x480。

計算着色器代碼:

#version 450 core

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

layout (binding = 0, rgba8) uniform image2D u_fboImg;

layout (binding = 0, offset = 0) uniform atomic_uint u_counters[100];

void main() {
    ivec2 texCoord = ivec2(gl_GlobalInvocationID.xy);

    // Only use shader invocations within first 100x500 pixels
    if (texCoord.x >= 100 || texCoord.y >= 500) {
        return;
    }

    // Each counter should be incremented 400 times
    atomicCounterIncrement(u_counters[texCoord.x]);

    memoryBarrier();

    // Use only "bottom row" of invocations to draw results
    // Draw a white column as high as the counter at given x
    if (texCoord.y == 0) {
        int c = int(atomicCounter(u_counters[texCoord.x]));
        for (int y = 0; y < c; ++y) {
            imageStore(u_fboImg, ivec2(texCoord.x, y), vec4(1.0f));
        }
    }
}

這就是我得到的:(鋸齒條的高度每次都不同,但平均大約是那個高度)

在此處輸入圖片說明

這就是我所期望的,並且是將for循環硬編碼為400的結果。

在此處輸入圖片說明

奇怪的是,如果我減少了派遣中的工作組數量,比如說將x值減半(現在只覆蓋屏幕的一半),則條形會變大:

在此處輸入圖片說明

最后要證明沒有其他廢話,這里我只是根據本地調用ID進行着色:

在此處輸入圖片說明

*編輯:忘了提到調度,緊接着是glMemoryBarrier(GL_ALL_BARRIER_BITS);

除非另有說明,否則特定着色器階段(包括計算着色器階段)的所有着色器調用將以不確定的順序彼此獨立地執行。 調用memoryBarrier不會改變這一事實。 這意味着,當調用memoryBarrier之后的memoryBarrier ,無法保證原子計數器的值已經被最終將進行的所有着色器調用增加了。

因此,您所看到的正是人們所期望看到的:調用寫入一些隨機值,這取決於調用恰好在其中執行的依賴於實現的順序。

您要執行的是對所有調用執行所有原子增量,然后讀取這些值並根據讀取的內容繪制內容。 您編寫的代碼無法做到這一點。

盡管計算着色器確實具有操縱調用執行順序的能力 ,但這僅適用於同一工作組內的調用(實際上這就是存在工作組的原因)。 也就是說,您可以在工作組中將調用按順序排序,但不能在工作組之間進行。

簡單的解決方法是將其轉換為2個計算着色器調度操作。 首先進行所有增量。 第二個將讀取這些值並將結果寫入圖像。

更聰明的解決方案將涉及雇用工作組。 就是說,對您的工作進行分組,以便使增加了相同原子計數器的所有內容都可以在同一工作組中執行。 這樣,您甚至不需要原子計數器。 您只使用共享變量(可以執行原子操作 )。 在完成共享變量的所有增量之后,您將調用barrier() 這樣可以確保所有調用至少在執行任何操作之前就已經執行了。 因此,所有增量都已完成。

暫無
暫無

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

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