【问题标题】:Flow Control in HLSLHLSL 中的流控制
【发布时间】:2020-03-12 01:32:45
【问题描述】:

我最近阅读了这篇关于 raymarching 云的论文(小心它是 PDF,如果你不想要的话:http://www.diva-portal.org/smash/get/diva2:1223894/FULLTEXT01.pdf),作者继续优​​化(第 22 页)。 通过重投影算法。 他表示,通过每帧仅对所有像素的 1/16 进行 raymarching(所选像素在 4x4 网格中四处跳动)并重新投影其余部分,他的性能提高了大约 10 倍。

我现在尝试在虚幻引擎 4(自定义 HLSL 着色器)中实现这一点,并且现在我得到了光线行进和重投影工作。 但是,我实际上只在必要的像素上运行 raymarching。据我所知,对于 HLSL 中的任何分支,都会计算分支的两侧,并且将丢弃一个。 因此,我 不能 在像素着色器中执行类似以下伪代码的操作: if(!PixelReprojection) { 返回 0;} 否则 { 返回 Raymarch(...); } 因为即使是重新投影的像素,它也会计算 Raymarch。

我没有看到任何其他方法来存档这个...... HLSL 中是否有任何类型的分支允许这样做?它不能是静态的,因为经过光线跟踪和重新投影的像素每帧都会发生变化。 我真的很好奇作者是如何在 GPU 上编写代码时实现性能提升十倍的,据我所知。

非常感谢您在这里提供任何形式的意见。

问候, 美食家

【问题讨论】:

    标签: hlsl unreal-engine4 fragment-shader flow-control


    【解决方案1】:

    TLDR:在 if 语句前使用属性 [branch]


    据我所知,对于 HLSL 中的任何分支,都会计算分支的两侧,并丢弃一个

    这实际上并不完全正确。是的,分支可以展平,这意味着两边都按照您的描述计算,但也可以展平(称为动态分支)。

    现在,不展平分支有一些缺点:如果同一波中的两个线程在分支中采用不同的路径,则必须产生第二波,因为波中的所有线程都必须运行相同的代码(所以有些线程将被移动到新产生的波)。因此,在这种情况下,许多线程被“禁用”(意味着它们运行与波中其他线程相同的代码,但实际上并未将任何内容写入内存)。尽管如此,这种动态分支可能仍然比运行分支的两侧更快,但这取决于实际代码。

    我们甚至可以通过智能着色器设计来消除这个缺点(即确保占据分支一侧的线程在同一个波中,因此波内不会发生分歧。但是,这需要一些知识底层硬件,如波形大小等)

    在任何情况下:如果没有另外说明,HLSL 编译器会自行决定分支是使用动态分支还是扁平化。但是,可以通过adding an attribute 对 if 语句强制执行两种方式之一,例如:

    //Enforce dynamic branching:
    [branch] 
    if (...) { ... }
    else { ... }
    
    //Enforce flattening of the branch:
    [flatten]
    if (...) { ... }
    else { ... }
    

    【讨论】:

    • 您好,非常感谢您的回答!这确实帮助并减少了渲染时间!实际上,在尝试解决问题之前,我偶然发现了 [branch] 标志,我只是认为这行不通,因为他们说很少有 GPU 支持动态分支。回顾那些页面,我发现它们有点旧 :D 再次非常感谢!
    • 编译器可能会考虑 ifmovc 相同类型的 SSA 依赖图分支,并将插入代码用于向量写入掩码 — 当波中的不同通道采用不同分支时,因为它只需要 - 并且当整个波采用与优化相同的路径时进行标量跳跃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-11-11
    • 1970-01-01
    相关资源
    最近更新 更多