【问题标题】:Optimizing Min/Max Depth GLSL Shader优化最小/最大深度 GLSL 着色器
【发布时间】:2014-07-15 16:48:47
【问题描述】:

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

【问题讨论】:

    标签: opengl glsl depth-buffer


    【解决方案1】:

    不用担心这些额外的步骤。它很可能在比单个全局内存访问 (texelFetch) 快 200 倍以上的寄存器中完成。

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

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

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

    那么如何优化这个问题呢?

    -> 减少每个线程的工作量

    怎么做?

    -> 并行缩减 (http://www.drdobbs.com/architecture-and-design/parallel-pattern-7-reduce/222000718)

    非正式描述:

    • 您拥有 32x32 的区域。

    • 您无需计算整个区域的最小值/最大值,而是分多个步骤进行。

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

    -> 所以现在你的图片小了 4 倍

    -> 重复 5 次

    -> 你现在有了整个区域的最小值/最大值

    【讨论】:

    • 谢谢你的回答,我会试试你的方法!虽然我认为一个 4x4 然后一个 8x8 内核可能没问题?
    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 2012-05-03
    • 2018-11-19
    • 2018-08-10
    • 2016-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多