Image processing DirectX 11,结合像素着色器以防止瓶颈

Image processing DirectX 11,结合像素着色器以防止瓶颈,image-processing,directx,shader,pixel-shader,Image Processing,Directx,Shader,Pixel Shader,我试图用GPU实现一个复杂的算法。唯一的问题是硬件限制,最大可用功能级别为9_3 该算法基本上是两幅图像的“立体匹配”算法。由于上述限制,所有计算只能在顶点/像素着色器中执行(没有可用的计算API)。顶点着色器在这里非常无用,因此我将它们视为通过顶点着色器 让我简要描述一下算法: 拍摄两张图像并计算成本体积图(基本上是将RGB转换为灰度->将右侧图像转换为D并从左侧图像中减去)。对于生成纹理3d的不同D,此步骤重复大约20次 这里的问题:我不能简单地创建一个像素着色器来计算 由于像素的大小限制,

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

该算法基本上是两幅图像的“立体匹配”算法。由于上述限制,所有计算只能在顶点/像素着色器中执行(没有可用的计算API)。顶点着色器在这里非常无用,因此我将它们视为通过顶点着色器

让我简要描述一下算法:

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

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

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

    这里还有一个问题:因为窗口太大,我需要将框过滤拆分为两个像素着色器(垂直方向和水平方向分别),因为循环展开阶段的结果需要很长的代码。手动实现这些循环不会有任何帮助,因为它仍然会创建大像素着色器。因此,这里的另一个瓶颈-需要CPU将结果从temp纹理(V过程的结果)传递到第二个过程(H过程)

  • 然后在下一步中,对第一步和第二步的每对结果应用一些算术运算

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

  • 然后,基于步骤3中的像素值,为每个像素取最小D(第一步中的参数值)

    。。。与步骤3相同

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

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

    问题1:是否有可能让GPU知道如何在不涉及CPU和导致瓶颈的情况下执行每个分支表单到底部?也就是说,一次性编程图形管道的顺序,然后让GPU完成它的工作

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

    任何帮助都将不胜感激

    先谢谢你

    致以最良好的祝愿,
    卢卡斯在像素着色器中编写计算算法可能非常困难。为
    9_3
    目标编写这样的算法是不可能的。限制太多了。但是,我想我知道如何解决你的问题

    1。着色器重复

    首先,现在还不清楚,你在这里称之为“瓶颈”是什么。是的,理论上,循环中的draw调用是一种性能损失。但这是瓶颈吗?您的应用程序真的会降低性能吗?多少钱?只有探查器(CPU和GPU)可以回答。但要运行它,必须首先完成算法(第3和第4阶段)。所以,我最好坚持目前的解决方案,开始实现整个算法,然后分析并解决性能问题

    但是,如果你准备好调整。。。常见的“重复”技术是实例化。可以再创建一个顶点缓冲区(称为实例缓冲区),该缓冲区将包含一个绘制实例的参数,而不是每个顶点的参数。然后通过一个
    DrawInstanced()
    调用完成所有工作

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

    和往常一样,您在这里有一个折衷办法:代码的简单性(可能是)性能

    2。多次渲染

    CPU需要参与传递来自temp纹理的结果(测试结果 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_RESOURCE
    D3D11_BIND_RENDER_TARGET
    标志。可以有多个输入纹理和多个渲染目标。只需确保下一个过程都知道上一个过程的输出。 如果前一个过程使用的资源比当前多,请不要忘记解除不必要的绑定,以防止难以发现的错误:

    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。资源数据位置

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

    我们永远不会知道。驱动程序为资源选择合适的位置。但是,如果您有使用
    DEFAULT
    usage和
    0
    CPU访问标志创建的资源,您几乎可以肯定它将始终位于视频内存中


    希望能有帮助。快乐编码

    谢谢你的回答!你消除了我的疑虑。我开发的问题是,我为移动设备开发,但我找不到合适的GPU分析器。也许我会尝试在一些性能与se相当的旧PC上运行我的代码