opengl - 手动深度渲染: Random results despite using atomic operations

标签 opengl graphics atomic depth-buffer compute-shader

我正在使用计算着色器将单像素点渲染到 uint32 纹理中。纹理是 3D 纹理,x 和 y 是视口(viewport)坐标,z 在坐标 0 上具有深度信息,在 1 上具有附加属性。因此,如果您愿意,可以有两个手动构建的渲染目标。代码如下所示:

layout (r32ui, binding = 0) coherent volatile uniform uimage3D renderBuffer;
layout (rgba32f, binding = 1) restrict readonly uniform imageBuffer pointBuffer;

for(int j = 0; j < numPoints / gl_WorkGroupSize.x + 1; j++)
{
    vec4 point = imageLoad(pointBuffer, ...)
    // ... transform point ...
    uint originalDepth = imageAtomicMin(renderBuffer, ivec3(imageCoords, 0), point.depth);
    if (originalDepth >= point.depth)
    {
        // write happened, store the attributes
        imageStore(renderBuffer, ivec3(imageCoords, 1), point.attributes);
    }
}

虽然深度值是正确的,但我有一些像素属性在两个值之间闪烁。

pointBuffer 中的点的顺序是随机的(但我已经验证了所有点的集合始终相同),所以我的第一个想法是两个相等的深度值可能会改变输出,具体取决于哪个先出现。所以我做到了,if originalDepth == point.depth 它使用 imageAtomicMax 始终写入相同的两个替代属性,但这没有改变。

我把 barrier()memoryBarrier() 散落在各处,但这没有改变任何东西。我还为此删除了所有发散的控制流,没有任何改变。

将本地工作大小减少到 32 可消除 90% 的闪烁,但仍有一些闪烁。

任何想法将不胜感激。

编辑:在你问我为什么手动做这些事情而不是使用普通的光栅化和片段着色器之前,原因是性能。光栅化器没有帮助,因为我正在渲染单像素点,共享内存大大加快了速度,并且我多次渲染每个点,这需要我使用速度很慢的几何着色器。

最佳答案

问题是这样的:写入 renderBuffer 时存在竞争条件。如果两个不同的 CS 调用映射到同一像素,并且两者都决定写入该值,那么您的 imageStore 调用就会出现竞争。一个可能会覆盖另一个,可能是部分覆盖,或者完全是其他东西。但无论如何,并不能保证它一定能工作。

最好通过执行光栅化器所做的事情来解决这个问题:将过程分为两个单独的阶段。第一阶段执行...转换点...部分,将数据写入缓冲区。然后第二阶段遍历这些点并将它们写入最终图像。

在第 2 阶段,每个 CS 调用都会对特定输出像素执行所有处理。这样,就没有竞争条件。当然,这要求第一阶段以可以按像素排序的方式生成数据。

有几种方法可以解决后者。您可以使用链接列表,每个像素都有一个列表。或者您可以使用每个工作组的列表,其中工作组代表像素空间的某个 X/Y 区域。在这种情况下,您将使用本地共享内存作为本地深度缓冲区,所有 CS 调用都从该区域读取/写入。当它们全部处理完像素后,您将其写入实际内存。基本上,您将手动实现基于图 block 的渲染。

事实上,如果您有很多这些点,基于图 block 的解决方案将允许您合并管道,这样您就不必等到所有第 1 阶段都完成后再进行从第 2 阶段的某些部分开始。您可以将第 1 阶段分解为多个 block 。您启动几个第 1 阶段 block ,然后是从第一个第 1 阶段读取的第 2 阶段 block ,然后是另一个第 1 阶段,依此类推。

Vulkan 及其事件系统比 OpenGL 拥有更好的工具来构建如此高效的依赖链。

关于opengl - 手动深度渲染: Random results despite using atomic operations,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38723048/

相关文章:

concurrency - 如何使用 Swift 中的 OSAtomicCompareAndSwapPtrBarrier?

objective-c - 我应该如何设计显示动态 map ? (坐标+线)

c++ - 我的 OpenGL 应用程序适用于 ATI,但不适用于 nNVIDIA pc

java - 使用 OpenGL 四叉树渲染大型矩形平铺图像

java - 使用 LWJGL 绘制背景 Sprite 有困难

user-interface - 无障碍对比度与企业形象指南

java - Java图形中绘制平滑曲线

windows - 了解IDirect3DDevice9::Present在阻止vsync时的行为

C++11 memory_order_acquire 和 memory_order_release 语义?

java - 最小化 JDK8 ConcurrentHashMap 检查和设置操作的锁定范围