【问题标题】:OpenGL barrier() Function and Divergent Flow ControlOpenGL barrier() 函数和发散流控制
【发布时间】:2018-02-07 06:22:56
【问题描述】:

问题

barrier() 的使用是否允许遵循但在发散流控制之外?

详情

在符合 OpenGL 4.00 的计算着色器中,我正在做一些涉及发散(即非动态统一)分支语句的工作。稍后在同一个着色器中,我需要同步该工作组内所有调用的执行,以实现内存访问。这也有利于提高效率,因为我希望它们彼此同步。但是,在咨询了 khronos.org wiki 和 refpages 之后,我不清楚我想做的事情是否符合标准(无论它在实践中是否有效)。

this page,我们看到:

barrier的调用不得放在任何控制流中。

this page,我们看到:

barrier()可以从流控中调用,但只能从统一流控中调用。导致对 barrier() 求值的所有表达式必须是动态统一的。

首先,关于流量控制的明显矛盾。我假设只有发散的(在工作组内)流控制是不允许的?

其次,在我看来,关于在发散流控制之后 调用barrier() 时出现了一些歧义。重要的是,再次注意“所有导致对barrier()求值的表达式必须是动态统一的”的断言。这是否意味着导致,或...?一些例子可以帮助说明我的困惑。

示例1,有效:

void main() {
    // ... do some work here ...
    barrier(); // valid use case
    // ... do some more work ...
}

示例2,有效:

void main() {
    if (IS_BEST_WORK_GROUP) { // dynamically uniform within work group
        // ... do some work here ...
        barrier(); // valid use case
        // ... do some more work ...
    }
}

示例3,无效:

void main() {
    if (IS_BEST_INVOCATION) { // divergent within work group
        // ... do some work here ...
        barrier(); // this is illegal
        // ... do some more work ...
    }
}

示例 4,模棱两可:

void main() {
    if (IS_BEST_INVOCATION) { // divergent within work group
        // ... do some work here ...
    }
    barrier(); // is this allowed?
                // it occurs after, but outside of, a divergent branch statement
    // ... do some more work ...
}
  • 如果示例 4 确实有效,我会在哪里以明确的形式找到此信息?
  • 或者,如果它无效,是否有其他机制可用于让我的所有调用在分歧分支条件后重新进入锁步?
  • 如果以上两项都不是,这是否可以在 Vulkan 中完成?

【问题讨论】:

    标签: opengl shader gpgpu


    【解决方案1】:

    唯一的声明来源是GLSL Specification

    第 8.16 节规定:

    对于镶嵌控制着色器,barrier() 函数只能放在镶嵌控制着色器的main() 函数内,不得在任何控制流中调用。 [...]

    对于计算着色器,barrier() 函数可以放在流控制中,但该流控制必须是统一流控制。

    您的示例 4 非常好,因为对 barrier 的调用不在任何控制流中。只要确保所有着色器调用都到达相同的屏障,在屏障之前做什么都没关系。

    【讨论】:

    • 太棒了!感谢您的pdf链接,原始措辞非常清楚。不知道我在看的时候怎么错过了。
    • 我想到了一个技术问题,只要在给定执行期间该控制最终评估为 true(例如循环内的条件)?例如,一些调用在第 4 次迭代中使用分支,另一些在第 5 次迭代中使用。我对 §8.16 的解读是它在技术上是非法的,但我对(当前)硬件的理解是它应该始终工作在实践中。
    • 从规范来看,这是不允许的。但我从未在实践中尝试过。
    【解决方案2】:

    来自 NV_compute_program5 扩展的一些额外的 Nvidia 特定信息:

    第 2.X.8.Z 节,BAR:执行障碍

    BAR 指令同步本地工作组内计算着色器调用的执行。当计算着色器调用执行 BAR 指令时,它会暂停,直到当前本地工作组中的所有调用都执行了相同的 BAR 指令。一旦所有调用都执行了 BAR 指令,处理将继续 BAR 指令之后的指令。

    程序中允许 BAR 的位置没有编译时限制。但是,BAR 指令在发散流控制中是不允许的;如果工作组中的任何计算着色器调用执行 BAR 指令,则所有计算着色器调用都必须执行该指令。执行 BAR 指令的结果是未定义的,如果发出指令,可能会导致应用程序挂起和/或程序终止:

    • 在任何 IF/ELSE/ENDIF 块中,由 IF 指令评估的条件结果在整个工作组中不相同;

    • 在 REP/ENDREP 块的任何迭代中,工作组中的至少一个调用已使用 CONT 指令跳到下一个迭代,使用 BRK 或 RET 指令退出循环,或由于以下原因退出循环已完成要求的循环迭代次数;或

    • 在工作组中的至少一个调用已使用 RET 指令退出子例程的任何子例程(包括主例程)内。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-25
      • 2015-09-29
      • 1970-01-01
      • 2018-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多