【问题标题】:Possible Rendering Performance Optimizations可能的渲染性能优化
【发布时间】:2015-04-09 18:51:59
【问题描述】:

我今天使用 C# 和 OpenTK 进行了一些基准测试,只是想看看在帧率下降之前我可以实际渲染多少。我得到的数字非常惊人,我对我的测试结果非常满意。

在我的项目中,我正在加载由 968 个三角形组成的搅拌机猴子。然后我实例化它并渲染它 100 次。这意味着我每帧渲染 96,800 个三角形。这个数字远远超过了我在游戏中任何给定场景中需要渲染的任何东西。在此之后,我将其推得更远,并在不同的位置渲染了 2000 只猴子。我现在渲染了惊人的 1,936,000(每帧几乎 200 万个三角形),并且帧速率仍然锁定在每秒 60 帧!这个数字让我大吃一惊。我把它推得更远,最后帧率开始下降,但这只是意味着每帧实例化的限制大约是 400 万个三角形。

不过我只是想知道,因为我使用的是一些旧版 OpenGL,如果这仍然可以进一步推动 - 还是我应该打扰?

对于我的测试,我加载了搅拌机猴子模型,使用不推荐使用的调用将其存储到显示列表中,例如:

modelMeshID = MeshGenerator.Generate( delegate {
            GL.Begin( PrimitiveType.Triangles );
            foreach( Face f in model.Faces ) {
                foreach( ModelVertex p in f.Points ) {
                    Vector3 v = model.Vertices[ p.Vertex ];
                    Vector3 n = model.Normals[ p.Normal ];
                    Vector2 tc = model.TexCoords[ p.TexCoord ];
                    GL.Normal3( n.X , n.Y , n.Z );
                    GL.TexCoord2( tc.Y , tc.X );
                    GL.Vertex3( v.X , v.Y , v.Z );
                }
            }
            GL.End();
        } );

然后调用该列表 x 次。 我的问题是,如果我将 VAO(顶点数组对象)放入显示列表而不是旧的 GL.Vertex3 api,是否可以加快速度?这会影响性能吗?还是会与显示列表产生相同的结果?

这是几千张的截图:

我的系统规格:

CPU: AMD Athlon IIx4(quad core) 620 2.60 GHz
Graphics Card: AMD Radeon HD 6800

【问题讨论】:

  • 您测量的是什么硬件?
  • 永远不要用顶点绘制GLif you can buffer 它们...
  • @RetoKoradi 查看我的更新。
  • @n0rd 的意思是简单的几何、实例化、缺乏转换等……允许大量优化,大多数实际应用程序不可用,从而加快速度“人为地”,因此它不能代表任何其他应用程序的性能
  • 是的,没有纹理,没有批处理,没有着色器。这些中的每一个都会付出代价。此外,从一帧中只有大约 100 个猴子头来判断(在您声称要绘制的数千个中),您绘制的 95% 的内容在早期管道阶段被剪切。所以你得到的数字不代表任何东西。

标签: c# opengl performance-testing opentk


【解决方案1】:

我的问题是,如果我将 VAO(顶点数组对象)放入显示列表而不是旧的 GL.Vertex3 api,是否可以加快速度?这会影响性能吗?还是会与显示列表产生相同的结果?

没有。

您将遇到的主要问题是,显示列表和顶点数组不能很好地相互配合。使用缓冲区对象他们有点工作,但显示列表本身就像即时模式绘图 API 一样是遗留的。

但是,即使您设法从显示列表中正确获取 VBO 绘图,也会有一些改进:当编译显示列表时,OpenGL 驱动程序知道,到达的所有内容最终都会“冻结” .这允许进行一些非常激进的内部优化;所有几何数据都将打包到 GPU 上的缓冲区对象中,合并状态更改。 AMD 在这款游戏上不如 NVidia 好,但也不差。显示列表在 CAD 应用程序中大量使用,并且在 ATI 解决娱乐市场之前,他们专注于 CAD,因此它们的显示列表实现一点也不差。如果您将特定绘图调用所需的所有相关状态更改打包到显示列表中,那么在调用显示列表时您可能会进入快速路径。

我更进一步,最后帧率开始下降,但这只是意味着限制是每帧实例化大约 400 万个三角形。

实际上限制您的是调用显示列表的开销。我建议您在 DL 中添加更多几何图形,然后重试。

显示列表的效率惊人。它们从现代 OpenGL 中被删除主要是因为它们只能与立即模式绘图命令一起有效地使用。此外,最近的诸如转换反馈和条件渲染之类的东西也很难集成到显示列表中。所以他们被移除了;确实如此,因为使用显示列表有点尴尬。

现在,如果您查看 Vulkan,其基本思想是在命令缓冲区中预先设置尽可能多的绘图命令(状态更改、资源绑定等),并将这些命令重用于不同的数据。这就像您可以创建多个显示列表并让它们生孩子一样。

【讨论】:

    【解决方案2】:

    使用顶点列表,beginend 会导致猴子几何体在每次迭代时通过 PCI-E 发送到 GPU,这是渲染期间最慢的内存接口。此外,根据您的 GL 实现,对 GL 的每次调用都可能会产生或多或少的开销。如果您使用缓冲区对象,所有这些开销都将消失,因为您只需将猴子发送一次,然后您所需要的只是每次迭代的一次绘制调用。

    但是,猴子几何体很小(只有几 kb),因此通过 PCI-E 总线(大约 16 GB/s?)发送它,加上“几何循环”的几百次迭代,不会甚至需要一毫秒。即使这样也不会影响您的帧速率,因为除非您明确指定synchronizing,否则它将完全被流水线吸收:复制和绘图调用将在 GPU 仍在忙于渲染前一帧时运行。此时,GPU 开始渲染下一帧,数据已经存在。

    这就是我猜测的原因,因为您有一个相当优化的 GL 实现(良好的驱动程序),使用缓冲区对象不会产生任何加速。请注意,面对更大、更复杂的几何图形和渲染操作,缓冲区对象当然对性能至关重要。小缓冲区甚至可能在绘图调用之间保持缓存在芯片上。

    尽管如此,作为一个严重的速度狂,你肯定想仔细检查和验证这些猜测:)

    【讨论】:

    • 您认为您可以提供代码中的示例吗?即使是伪代码也足够了。
    • 几年前我写了a bunch of primitives 使事情变得更容易(在C++ 中),然后this sample code 使用它来说明支持BO 的GL 应用程序的基本程序布局。不确定这是否对您有帮助?它包括 SDL(用于简单的 GUI 和键盘、鼠标输入等)并与 GLSL 相关联,尽管它不是最小的......
    • 吹毛求疵;绘制调用不需要往返 GPU。
    • @ColonelThirtyTwo 已修复。谢谢你提醒我!
    • @Domi:OP 正在使用 DisplayList。编译显示列表时,驱动程序会将其全部打包并放到 GPU 上。所以这几乎和拥有 VBO 一样好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2018-01-09
    • 2011-08-26
    相关资源
    最近更新 更多