最大/最小深度GLSL着色器优化

4

我正在实现瓦片式延迟渲染,并且需要计算瓦片的最小/最大深度值。我每个瓦片只渲染一个像素,并在嵌套的for循环中收集深度值,代码如下:

float minDepth = 1.0;
float maxDepth = 0.0;

ivec2 clampMax = ivec2(screenSize) - 1;

// Iterate over each pixel in this tile
for (int x = 0; x < 32; x++) {
    for (int y = 0; y < 32; y++) {
        ivec2 newCoord = screenCoord + ivec2(x,y);
        newCoord = min(newCoord, clampMax);

        // Fetch the depth for that coordinate
        float currentDepth = texelFetch(depth, newCoord, 0).r;

        minDepth = min(minDepth, currentDepth);
        maxDepth = max(maxDepth, currentDepth);
    }
}

到目前为止,这个工作得很好,但是查看生成的汇编代码,纹理查找会变成这样:

// R2.xy contains 'newCoord'
MOV.S R2.z, {0, 0, 0, 0}.x;
TXF.F R1.x, R2.xyzz, handle(D0.x), 2D;

这基本上等于:

vec3 coordinate;
coordinate.xy = newCoord;
coordinate.z = 0;
result = texelFetch(depth, coordinate);

因此,在纹理查找中会产生一个多余的指令,这在循环中会累加很多。我的猜测是,NVIDIA在内部实现了texelFetch作为

texelFetch(sampler2D sampler, ivec3 coord) 

回到问题:如何优化这个循环?
我正在使用带有最新驱动程序的GTX 670在Windows上运行。
1个回答

2
不要担心这些额外的步骤。它很可能会在寄存器中完成,速度比单个全局内存访问(texelFetch)快200倍以上。
但是有一种优化问题的方法,而不是使用循环:
一般来说,最有效率的GPU程序是每个线程尽可能少地工作,所有线程的工作总量与顺序算法所需的相同。
现在Opengl的方法是在GPU上计算每个像素的线程。对于大多数情况来说,这是完全可以接受的,但在您的问题中,每个线程的工作量相当大(32 * 32 * texelFetch)。
那么如何优化这个问题?
-> 减少每个线程的工作量
如何做?
-> 并行减少(http://www.drdobbs.com/architecture-and-design/parallel-pattern-7-reduce/222000718
非正式描述:
您有一个32x32的区域。
而不是计算整个区域的最小/最大值,您可以分多个步骤进行。
- > 计算2x2块(每个区域16x16块)的最小/最大值
- > 现在您的图像变小了4倍
- > 这样做5次
- > 您现在拥有整个区域的最小/最大值。

谢谢你的回答,我会尝试你的方法!虽然我认为4x4和8x8的内核可能也可以。 - tobspr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接