几何着色器中的原子计数器异常

时间:2014-07-09 08:08:22

标签: opengl glsl

我试图通过计算几何着色器中的顶点数来控制片段着色器的行为,这样如果我有一个1000个三角形的顶点流,当计数达到500时,我为片段着色器设置了一些变化,这表明后者必须切换为了计算处理的总顶点(或三角形),我在几何着色器中使用了原子计数器。我计划先在顶点着色器中进行,但后来我在某处读到因为顶点缓存计数器在每个顶点上都没有增量但现在似乎在几何着色器中执行此操作并不能正确执行计数。

在我的几何着色器中,我这样做:

layout(triangles) in;

layout (triangle_strip ,max_vertices = 3) out; 

layout(binding=0, offset=0) uniform atomic_uint ac;

out flat float isExterior;

void main()
{
    memoryBarrier();
    uint counter = atomicCounter(ac);
    float switcher = 0.0;
    if (counter >= exteriorSize)
    {
        switcher = 2.0;
    }
    else
    {
        atomicCounterIncrement(ac);
        atomicCounterIncrement(ac);
        atomicCounterIncrement(ac);
    }
    isExterior = switcher;

    // here just emitting primitive....  

exteriorSize是一个统一,它包含一个等于数组中顶点数的数字。当我在CPU上读出计数器的值时,它永远不等于exteriorSize。但它几乎比它小2倍。是否存在顶点缓存在几何阶段也是如此?或者我做错了什么?

基本上我需要告诉片段着色器:"在顶点数X开始做工作Y之后。由于顶点数小于X,所以工作Z"而且我无法从原子计数器中获得精确的X,即使我将其递增直到达到该限制。

更新:

我怀疑问题在于原子写同步。如果我在不同的地方设置了memoryBarrier,则计数器值会改变。但是我仍然无法得到它返回等于exteriorSize的确切值。

更新2:

嗯,我没有弄清楚原子计数器同步的问题所以我做了using indirect draw .就像一个魅力。

1 个答案:

答案 0 :(得分:1)

几何着色器执行每个基元(在这种情况下为三角形),而顶点着色器几乎执行每个顶点。使用glDrawElements允许在三角形之间共享顶点结果(例如索引0,1,2然后0,2,3使用0和2两次:4个顶点,2个三角形和6个引用)。如你所说,有限的cache用于分享结果,因此如果长时间引用相同的顶点,则必须重新计算它。

看起来atomicCounteratomicCounterIncrement之间的计数器更新存在潜在问题。如果您想要像这样的整个代码段工作,则需要locked。根据您锁定的内容,这可能会非常缓慢。

相反,始终致电atomicCounterIncrement并允许ac增长超过exteriorSize会更容易。

AFAIK从原子计数器缓冲区读回值应该停止,直到内存操作完成,但我之前没有在两次传递之间调用glMemoryBarrier

如果在几何着色器中执行,则exteriorSize听起来应该等于三角形而不是顶点的数量。如果您确实需要逐顶点处理,那么可以更改为GL_POINTS或使用变换反馈扩展保存顶点着色器结果,然后从中绘制三角形(基本上自己进行缓存,但使用包含所有内容的缓冲区) 。如果您使用glDrawArrays或从不重复使用顶点,则标准顶点着色器应该没问题。

最后,拨打atomicCounterIncrement三次是浪费。拨打一次并使用counter * 3