【问题标题】:Atomic counter anomalies in Geometry shader几何着色器中的原子计数器异常
【发布时间】:2014-07-10 01:53:52
【问题描述】:

我试图通过计算几何着色器中的顶点计数来控制片段着色器的行为,这样如果我有一个 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 上读出计数器的值时,它从不等于 externalSize。但它几乎比它小 2 倍。是否有顶点缓存在几何阶段也是如此?还是我做错了什么?

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

更新:

我怀疑问题出在原子写入同步上。如果我在不同的地方设置 memoryBarrier,计数器值会发生变化。但我仍然无法让它返回等于 externalSize 的确切值。

更新 2:

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

【问题讨论】:

    标签: opengl glsl


    【解决方案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

    【讨论】:

    • memoryBarrier 没有帮助。 memoryBarrierAtomicCounter 也无济于事。你注意到顶点与三角形的计数是对的。我都试过了。假设exteriorSize等于620,所以每次执行只增加一次计数器,直到它达到620,当我将它读回CPU时返回一个更大的数字(smth like 900+)所以我怀疑几何着色器中的计数器同步是“随意”发生的。
    • 基本上我需要告诉片段阴影:“在顶点编号 X 开始工作 Y 之后”而且我无法从原子计数器中得到那个确切的 X,即使我将它增加到它达到那个限制。
    • @MichaelIV memoryBarrier 是 GLSL 调用,glMemoryBarrier 是主机调用。听起来在顶点数、三角形数和顶点引用数上可能仍然存在混淆。我从未见过 GL 原子计数器得到错误的结果。原子并不便宜(分支也可能很糟糕)。简单地将其分成两个绘图调用怎么样?
    • 这就是问题所在,由于某些特殊需要,我试图将其从 2 到 1 绘制调用压缩。我知道 glMemoryBarrier 是主机调用,我不关心它,因为我需要读取输出主机上的值仅用于调试。但我的意思是“如果(计数器> = externalSize)”一次不会发生。因为如果它是我将在主机上获得等于externalSize的值
    • 也许间接绘制在这里可以提供帮助?但是在这种情况下,片段着色器如何知道为第二个实例的东西做一些特别的事情......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多