2016-10-25 58 views
2

我對每個輸出像素都要執行一次計算,它使用從着色器管道中的早期步驟傳遞的一些數據 - 因此在片段着色器中執行此計算最有意義。爲了查看它是否可能,我從最簡單的例子開始 - 只爲每個基元計算像素。這僅需要兩個着色器 - 頂點着色器:僅對可見像素執行片段着色器

#version 430 
in vec3 position; 

void main() {{ 
    gl_Position = vec4(position, 1); 
}} 

和片段着色器:

#version 430 
layout(early_fragment_tests) in; 

out vec4 out_color; 

layout(std430, binding = 3) buffer out_data { 
    int data[]; 
}; 

void main() {{ 
    atomicAdd(data[gl_PrimitiveID], 1); 
    out_color = vec4(1, gl_PrimitiveID, 0, 1); 
}} 

正如你可以看到它只是增加着色器的存儲緩衝對象的元素。

然後我餵它兩個三角形(6分):[-1, -1, 0], [-1, 1, 0], [1, 1, 0], [-1, -1, 0], [1, -1, 0], [-1, 1, -1]。它正確顯示了一個紅色的三角形和一個綠色的三角形,每個三角形都佔據了窗口的一半,但是綠色的三角形位於頂部 - 所以只有一半的紅色三角形可見(窗口的1/4)。

當然,我預計計數將是紅色三角窗口大小的1/4,綠色窗口大約是1/2,但它們都等於1/2!順便說一句,如果我將所有輸入Z座標設置爲零,那麼紅色三角形在頂部,而綠色是半隱藏的 - 在這種情況下,計數是正確的。當我閱讀OpenGL文檔(我發現選項early_fragment_tests)時,我明白由於任何原因(例如在我的情況下深度測試)丟棄的片段不會影響原子計數器和SSBO - 請參閱here。但正如我的例子所顯示的,他們顯然影響他們!還有什麼可以解決這個問題嗎?

如果這很重要,我使用intel skylake iGPU,OpenGL 4.3在linux下運行它。

+0

您確定深度測試正常嗎? (已啓用深度測試,沒有寫入蒙版,深度func可以...)您可以通過更改三角形的Z值並查看頂部三角形是否更改來檢查此問題。你使用哪個Z值?對兩個三角形使用完全相同的值可能會導致您的問題。你是否嘗試手動丟棄一些碎片以查看這是否改變了原子計數器? – dv1729

+1

你以哪種順序繪製三角形?當您繪製紅色然後綠色時,結果並不令人驚訝,因爲紅色三角形在渲染時完全可見。 – BDL

+0

我提到我用兩個三角形(6點)提供着色器 - 我只需一次調用DrawArrays即可完成此操作。 – aplavin

回答

3

處理來自不同三角形的碎片的順序在很大程度上是未定義的。早期的片段測試不會強制每個三角形的片段按照光柵化程序進行處理。雖然OpenGL主要是在「as-if」規則下工作的(即:一切正常,「按原樣」按順序處理),但圖像加載/存儲和SSBO存儲器訪問的不連貫特性意味着您不能依賴in-訂單處理。

如果你想發出一批作品,並且FS只對每個片段執行一次,那麼你將不得不進行深度預傳。首先,你渲染場景,但沒有FS;這意味着唯一被寫入的東西是深度值。接下來,您正常渲染場景。

這兩者之間應該是某種形式的同步,確保第一遍中的所有三角形在第二遍開始之前完成。不幸的是,OpenGL沒有一個體面的方式來要求這一點。你可以use a fence sync object with glWaitSync,但這需要一個明確的glFlush調用,這不是很便宜。

相關問題