2017-08-10 104 views
1

OpenGL紅皮書版本8(GL 4.3)示例11.19將imageLoad()放置在while循環中,保持輪詢,直到前一個基元的至少一個片段已更新此值。這本書說GLSL memoryBarrier()

例11.19顯示了一個非常簡單的內存障礙用例。它允許 片段之間的某種程度的排序得到保證。在 functionUsingBarriers()的頂部,使用一個簡單的循環等待內存位置的內容 到達我們當前的原始ID。 因爲我們知道 沒有來自同一個基元的兩個片段可以落在相同的 像素上,所以我們知道當我們在 函數的主體中執行代碼時,來自前一個基元的至少一個片段是 處理。然後我們使用非原子操作來修改我們的 片段位置處的內存內容。我們發信號給其他着色器 調用,我們通過寫入最初在函數頂部輪詢的共享內存位置 來完成調用。

爲了確保我們的修改的圖像內容寫回之前其他着色器調用內存 開始進入函數體中,我們使用 彩色圖像的更新和 原始計數器強制排序之間內存屏障通話。

然而,GL規範4.3表示由另一個調用書面

有一個調用民調內存假定其他調用已經啓動,可以完成其寫入

那麼我們怎麼能確保先前原語的片段調用已啓動並完成其寫入?

郵政SRC代碼

#version 420 core 

layout (rgba32f} uniform coherent image2D my_image; 

// Declaration of function 
void functionUsingBarriers(coherent uimageBuffer i) 

{ 

    uint val; 

    // This loop essentially waits until at least one fragment from 
    // an earlier primitive (that is, one with gl_PrimitiveID - 1) 
    // has reached the end of this function point. Note that this is 
    // not a robust loop as not every primitive will generate 
    // fragments. 
    do 
    { 
     val = imageLoad(i, 0).x; 
    } while (val != gl_PrimitiveID); 

    // At this point, we can load data from another global image 
    vec4 frag = imageLoad(my_image, gl_FragCoord.xy); 

    // Operate on it... 
    frag *= 0.1234; 
    frag = pow(frag, 2.2); 

    // Write it back to memory 
    imageStore(my_image, gl_FragCoord.xy, frag); 

    // Now, we’re about to signal that we’re done with processing 
    // the pixel. We need to ensure that all stores thus far have 
    // been posted to memory. So, we insert a memory barrier. 
    memoryBarrier(); 

    // Now we write back into the original "primitive count" memory 
    // to signal that we have reached this point. The stores 
    // resulting from processing "my_image" will have reached memory 
    // before this store is committed due to the barrier. 
    imageStore(i, 0, gl_PrimitiveID + 1); 

    // Now issue another barrier to ensure that the results of the 
    // image store are committed to memory before this shader 
    // invocation ends. 
    memoryBarrier(); 
} 
+0

並非我們所有人都有這本書。你能否真正向我們提供這個例子中正在發生的事情的具體細節?特別是,「以前的原始」是什麼意思? –

+0

嗨尼科爾,我已經更新了這個問題。請重新閱讀。 –

回答

0

此代碼(以及隨之而來的文字)是錯誤的廢話。此聲明:

因爲我們知道,從同一原始的沒有兩個片段可以在同一像素上的土地,我們知道,當我們正在執行的函數體的代碼,至少一個碎片從之前的基元已經被處理。

即使我們假設,在網格中的原語不重疊(幾乎在一般合理的假設),這意味着正是沒什麼對GPU的跨越原語分配工作。

OpenGL規範闡明瞭這一點:

同一着色器類型的調用的相對順序是不確定的。在基元B上工作時,由着色器發出的存儲可能會完成前 到基元A的存儲,即使基元A在原始基元 B之前指定。這甚至適用於片段着色器;而片段着色器輸出 總是以原始順序寫入幀緩衝區,片段着色器調用執行的存儲不是。

...

上着色器調用順序的上述限制還使一個單一的組原語不可實現的內某些形式的着色器調用之間 同步。例如,具有由另一個調用寫入的一個調用輪詢內存假定另一個調用已經啓動並且可以完成其寫操作。這種保證唯一的情況是 一個着色器調用的輸入是從上一階段 中的着色器調用的輸出中生成的。

是,OpenGL規範特意叫了這一點的東西,你不能做。我不知道如何進入官方的OpenGL書籍,但你的直覺是正確的:這是完全錯誤的。這實際上是爲什麼ARB_fragment_shader_interlock存在的原因:否則,你不能做這樣的事情。

+0

非常感謝。你的澄清維持我的懷疑。我懷疑我的直覺,因爲這個代碼示例來自權威的OpenGL紅皮書! –