3

我正在尝试使用 Metal API 在 Apple A7 GPU 上尽可能快地渲染大量非常小的 2D 四边形。研究 GPU 的三角形吞吐量数字,例如这里,以及 Apple 在其主题演示期间在屏幕上引用 >1M 三角形,我希望能够以 60fps 的速度每帧渲染 500,000 个这样的四边形。考虑到它们都是可见的(在屏幕上,不被 z 缓冲区隐藏)和微小的(对于光栅化器来说很棘手),可能会少一些,所以这可能不是 GPU 超级优化的用例。也许那个 Apple 演示以 30fps 运行,所以假设大约 200,000 应该是可行的。当然是 100,000 ……对吧?

然而,在我的测试应用程序中,最大值仅为 20,000 左右——超过此值,并且 iPad Air 上的帧速率降至 60 以下。使用 100,000 个四边形,它以 14 fps 的速度运行,即吞吐量为 2.8M 三角形/秒(与 AnandTech 文章中引用的 68.1M屏幕三角形相比!)。

即使我将四边形缩小为单个像素,使用微不足道的片段着色器,性能也不会提高。所以我们可以假设这是顶点绑定,并且 Xcode 中的 GPU 报告同意(“Tiler”为 100%)。顶点着色器也很简单,除了一点缩放和平移数学什么都不做,所以我假设瓶颈是一些固定功能阶段......?

只是为了获得更多背景信息,我使用单个实例绘制调用渲染所有几何图形,每个实例一个四边形,即每个实例 4 个顶点。四边形的位置是从一个单独的缓冲区应用的,该缓冲区由顶点着色器中的实例 id 索引。我也尝试了其他一些方法(非实例化,所有顶点都预先转换,实例化+索引等),但这没有帮助。没有复杂的顶点属性、缓冲区/表面格式或我能想到的任何其他东西似乎可能会在驱动程序/GPU 中遇到缓慢的路径(尽管我当然不能确定)。混合已关闭。几乎所有其他东西都处于默认状态(视口、剪刀、ztest、剔除等)。

该应用程序是用 Swift 编写的,但希望这无关紧要;)

我想了解的是,在渲染这样的四边形(而不是“适当的”3d 场景)时,我所看到的性能是否是预期的,或者是否需要一些更先进的技术来接近广告三角形吞吐量。人们认为这里的限制瓶颈可能是什么?

另外,如果有人知道为什么这在 OpenGL 中可能比在 Metal 中更快(我没有尝试过,也想不出任何原因),那么我也很想听听。

谢谢

编辑:添加着色器代码。

vertex float4 vertex_shader(
        const constant float2* vertex_array [[ buffer(0) ]],
        const device QuadState* quads [[ buffer(1) ]],
        constant const Parms& parms [[ buffer(2) ]],
        unsigned int vid [[ vertex_id ]],
        unsigned int iid [[ instance_id ]] )
{
    float2 v = vertex_array[vid]*0.5f;

    v += quads[iid].position;

    // ortho cam and projection transform
    v += parms.cam.position;
    v *= parms.cam.zoom * parms.proj.scaling;

    return float4(v, 0, 1.0);
}


fragment half4 fragment_shader()
{
    return half4(0.773,0.439,0.278,0.4);
}
4

1 回答 1

1

如果没有看到您的 Swift/Objective-C 代码,我无法确定,但我的猜测是您在调用您的实例化代码上花费了太多时间。当您有一个包含数百个三角形的模型时,实例化很有用,而不是两个。

尝试创建一个包含 1000 个四边形的顶点缓冲区,看看性能是否会提高。

于 2015-05-07T02:58:03.520 回答