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

时间:2014-07-15 16:48:47

标签: opengl glsl depth-buffer

我正在实现平铺延迟着色,为此我需要计算平铺的最小/最大深度值。我在每个图块上渲染1个像素,并在嵌套的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) 

回到问题:如何优化此循环?

我在Windows上使用带有最新驱动程序的GTX 670。

1 个答案:

答案 0 :(得分:2)

不要担心这些额外的步骤。它最有可能在寄存器中完成,这些寄存器比单个全局存储器访问(texelFetch)快200倍。

但这是一种优化问题而不是循环的方法:

一般来说,最有效的GPU程序是那些每个线程尽可能少地工作的程序,并且所有线程工作的组合与您使用顺序算法所需的数量相同。

Opengls方法现在计算GPU上自己线程中的每个像素。对于大多数情况来说这是完全正常的,但在你的问题中,每个线程的工作量非常大(32 * 32 * texelFetch)。

那么如何优化这个问题?

- &GT;减少每个线程的工作量

如何?

- &GT;平行减少(http://www.drdobbs.com/architecture-and-design/parallel-pattern-7-reduce/222000718

非正式说明:

  • 你有32x32的区域。

  • 不是计算整个区域的最小值/最大值,而是分多步完成。

- &GT;计算2x2块的最小值/最大值(每个区域16x16块)

- &GT;所以现在你的图像要小4倍

- &GT;这样做5次

- &GT;您现在拥有整个区域的最小值/最大值