0

我正在尝试使用 GPU 实现一种复杂的算法。唯一的问题是硬件限制,最大可用功能级别为 9_3。

算法基本上是两个图像的“立体匹配”算法。由于上述限制,所有计算只能在顶点/像素着色器中执行(没有可用的计算 API)。顶点着色器在这里相当无用,所以我认为它们是直通顶点着色器。

让我简要描述一下算法:

  1. 拍摄两张图像并计算成本体积图(基本上将 RGB 转换为灰度 -> 将右图像转换为D并从左图像中减去它)。对于生成 Texture3D的不同D ,此步骤重复大约 20 次。

    这里的问题:我不能简单地创建一个像素着色器来一次性计算这 20 次重复,因为像素着色器的大小限制(最多 512 个算术),所以我不得不在 C++ 中的循环中调用 Draw(),这不必要涉及CPU,而所有操作都在相同的两个图像上完成 - 在我看来,我在这里有一个瓶颈。我知道有多个渲染目标,但是:有最大值。8 个目标(我需要 20+),如果我想在一个像素着色器中生成 8 个结果,我会超出它的大小限制(我的硬件为 512 算术)。

  2. 然后我需要计算每个计算的纹理框过滤器,其中 r > 9 的窗口。

    这里的另一个问题是:因为窗口太大,我需要将框过滤拆分为两个像素着色器(分别垂直和水平方向),因为循环展开阶段会产生非常长的代码。这些循环的手动实现无济于事,因为它仍然会创建大像素着色器。所以这里的另一个瓶颈- CPU 需要参与将结果从临时纹理(V 通道的结果)传递到第二通道(H 通道)。

  3. 然后在下一步中,对来自第一步和第二步的每对结果应用一些算术运算。

    我的发展还没有到达这里,所以不知道什么样的瓶颈在等着我。

  4. 然后根据步骤 3 中的像素值为每个像素获取最小 D(第 1 步中的参数值)。

    ...与第 3 步相同。

这里基本上是非常简单的图表,显示了我当前的实现(不包括步骤 3 和 4)。

问题图

红点/圆圈/任何东西都是临时缓冲区(纹理),其中存储部分结果,并且每个红点 CPU 都参与其中。

问题1:是否有可能让GPU知道如何在不涉及CPU并导致瓶颈的情况下将每个分支形式执行到底?即一次性对图形管道序列进行编程,然后让 GPU 完成它的工作。

关于渲染到纹理的另一个问题:即使在 Draw() 方法调用和像素/顶点着色器切换之间,所有纹理是否一直驻留在 GPU 内存中?或者发生从 GPU 到 CPU 的任何传输......因为这可能是另一个导致瓶颈的问题。

任何帮助,将不胜感激!

先感谢您。

最好的问候,卢卡斯

4

1 回答 1

1

在像素着色器中编写计算算法可能非常困难。为目标编写这样的算法9_3是不可能的。限制太多。但是,好吧,我想我知道如何解决您的问题。

1.着色器重复

首先,不清楚,这里所说的“瓶颈”是什么。是的,理论上,for 循环中的绘制调用是性能损失。但它有瓶颈吗?您的应用程序真的会在这里失去性能吗?多少钱?只有分析器(CPU 和 GPU)才能回答。但要运行它,您必须首先完成您的算法(阶段 3 和 4)。所以,我最好坚持当前的解决方案,并开始实现整个算法,然后分析并修复性能问题。

但是,如果您准备好进行调整……常见的“重复”技术正在实例化。您可以再创建一个顶点缓冲区(称为实例缓冲区),其中包含的参数不是针对每个顶点,而是针对一个绘制实例。然后,您只需一个DrawInstanced()电话即可完成所有工作。

对于您的第一阶段,实例缓冲区可以包含您的目标层的D值和索引。Texture3D您可以从顶点着色器传递它们。

与往常一样,您需要权衡:代码的简单性与(可能)性能。

2.多遍渲染

CPU 需要参与将结果从临时纹理(V 通道的结果)传递到第二通道(H 通道)

通常,您会像这样进行链接,因此不涉及 CPU:

// Pass 1: from pTexture0 to pTexture1
// ...set up pipeline state for Pass1 here...
pContext->PSSetShaderResources(slot, 1, pTexture0); // source
pContext->OMSetRenderTargets(1, pTexture1, 0);      // target
pContext->Draw(...);

// Pass 2: from pTexture1 to pTexture2
// ...set up pipeline state for Pass1 here...
pContext->PSSetShaderResources(slot, 1, pTexture1); // previous target is now source
pContext->OMSetRenderTargets(1, pTexture2, 0);
pContext->Draw(...);
// Pass 3: ...

请注意,它pTexture1必须同时具有D3D11_BIND_SHADER_RESOURCED3D11_BIND_RENDER_TARGET标志。您可以有多个输入纹理和多个渲染目标。只要确保,每一次下一次传递都知道前一次传递的输出。如果之前的 pass 使用的资源比当前的多,不要忘记取消绑定 unneeded,以防止难以发现的错误:

pContext->PSSetShaderResources(2, 1, 0);
pContext->PSSetShaderResources(3, 1, 0);
pContext->PSSetShaderResources(4, 1, 0);
// Only 0 and 1 texture slots will be used

3.资源数据位置

即使在 Draw() 方法调用和像素/顶点着色器切换之间,所有纹理是否始终驻留在 GPU 内存中?

我们永远无法知道这一点。驱动程序为资源选择合适的位置。但是,如果您有DEFAULT使用使用率和0CPU 访问标志创建的资源,您几乎可以肯定它总是在显存中。

希望能帮助到你。快乐编码!

于 2013-09-23T15:36:43.010 回答