在OS X上,OpenGL核心档案的速度变慢了

6
我在我的引擎中添加了一个新的GL渲染器,它使用核心配置文件。虽然它在Windows和/或nvidia卡上运行良好,但在OS X上要慢10倍(只有3帧每秒而不是30)。奇怪的是,我的兼容性渲染器可以正常运行。
我使用Instruments和GL分析工具收集了一些跟踪数据:

https://www.dropbox.com/sh/311fg9wu0zrarzm/31CGvUcf2q

它显示应用程序在glDrawRangeElements中花费了时间。 我尝试了以下几件事情:
  • 使用glDrawElements代替(无效)
  • 翻转剔除(速度没有影响)
  • 禁用一些GL_DYNAMIC_DRAW缓冲区(无效)
  • 绑定索引缓冲区到VAO后进行绘制(无效)
  • 将索引转换为4字节(无效)
  • 使用GL_BGRA纹理(无效)
我没有尝试的是将我的顶点对齐到16字节边界和/或将索引转换为4字节,但是,如果那是问题,那么标准为什么允许呢? 我是这样创建上下文的:
NSOpenGLPixelFormatAttribute attributes[] =
{
    NSOpenGLPFAColorSize, 24,
    NSOpenGLPFAAlphaSize, 8,
    NSOpenGLPFADepthSize, 24,
    NSOpenGLPFAStencilSize, 8,
    NSOpenGLPFADoubleBuffer,
    NSOpenGLPFAAccelerated,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
    0
};

NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes];
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];

[self.view setOpenGLContext:context];
[context makeCurrentContext];

尝试以下规格:

  • radeon 6630M,OS X 10.7.5
  • radeon 6750M,OS X 10.7.5
  • geforce GT 330M,OS X 10.8.3

你有任何想法我可能做错了什么吗?再次强调,使用兼容性配置文件可以正常工作(不使用VAOs)。

更新:已向苹果报告。

更新:苹果对此问题不屑一顾...无论如何,我创建了一个小的测试程序,实际上很好。现在我用Instruments比较了调用堆栈,并发现使用引擎时,glDrawRangeElements会进行两个调用:

  • gleDrawArraysOrElements_ExecCore
  • gleDrawArraysOrElements_Entries_Body

而在测试程序中,它只调用第二个。现在第一个调用会执行类似于即时模式渲染的操作(gleFlushPrimitivesTCLFunc,gleRunVertexSubmitterImmediate),因此明显会导致减速。


4
“但说真的,如果那是个问题,那么为什么标准允许呢?”因为标准没有定义“性能”,只有功能。 - Nicol Bolas
它几乎听起来像是退回到软件处理。你应该对其进行分析,看看哪里出现了减速。此外,您可以使用OpenGL Profiler运行它并打开所有错误断点吗?这可能会指出您遗漏的内容(并告诉您是否退回到软件)。 - user1118321
我已经启用了错误检查和断点回退,但是没有任何反应。顺便说一下,我附加的日志显示引擎每帧也在检查GL错误。正如我所提到的,减速明显出现在glDrawRangeElements中。 - Asylum
你正在渲染的缓冲数据有多大? - Grimmy
由于GL_UNSIGNED_SHORT已经足够,所以它不能太大,而且在GL 2中也可以正常工作。我尝试了更小甚至更大的模型,无论着色器或几何复杂度如何,它们都运行缓慢。 - Asylum
我完全崩溃了...我写了一个测试程序,它可以正常运行。把测试程序的所有内容复制到引擎中,但速度仍然很慢。以为可能是我创建窗口等方面搞错了什么,所以这次用界面生成器和其他工具做得很好。仍然很慢...我真的没有任何想法...我的意思是现在差别是如此微小...(在代码中) - Asylum
2个回答

3

最后,我终于成功重现了减速情况。这太疯狂了...很明显是由于在“my_Position”属性上调用glBindAttribLocation引起的。现在我做了一些测试:

  • 1 是默认值(由glGetAttribLocation返回)
  • 如果我将它设置为 0,则没有问题
  • 如果我将它设置为 1,则渲染变慢
  • 如果我将它设置为任何较大的数字,那么它又会变慢

显然,我重新链接了程序(检查代码)。这不是实现中的问题,我也测试过“正常”的值。

测试程序:

https://www.dropbox.com/s/dgg48g1fwgyc5h0/SLOWDOWN_REPRO.zip

如何重现:

  • 使用 XCode 打开
  • 打开 common/glext.h 文件(不要被名称所困扰)
  • 将 GLDECLUSAGE_POSITION 常量从 0 修改为 1
  • 编译和运行 => 变慢
  • 将其改回为零 => 好

谢谢!我已经花了数天的时间来找出为什么在2013款MacBook Pro上使用50K Tris模型只有15FPS。FPS跳到了无限大(需要更高分辨率的计时器:P)。 - Alec Thilenius

2

我在以下情况下遇到了同样的问题,使用OS X Mavericks

  • 使用数组缓冲区进行实例化渲染,使每个实例都有自己的modelToWorldinverseNormal矩阵;通过布局指定属性位置而不是使用glGetAttribLocation

  • shader中未使用其中一个数组缓冲区,其中声明了位置但实际上在glsl代码中没有用于任何内容的属性

在这种情况下,调用glDrawElementsInstanced会占用大量CPU时间(通常情况下,即使绘制数千个实例,此调用的CPU使用率也几乎为零)。

如果几乎所有在glDrawElementsInstanced中使用的CPU时间都花费在gleDrawArraysOrElements_ExecCore中,则可以确定您正在遇到此特定问题。确保在您的shader代码中实际引用了所有数组缓冲区可将CPU时间修复为(几乎)零。

我怀疑这是一种情况,在glsl的main()函数中省略变量会使编译器混淆,从而删除对该变量的所有引用,留下对属性或统一变量的悬空引用。


我建议你也向苹果报告这个问题 :) 显然他们也没有解决我的问题。 - Asylum
我有一个非常简单的着色器类似的问题。 谢谢Deekey,虽然我没有使用实例渲染,但是未使用的向量缓冲区会使向量着色器在CPU上运行。 - Michel
进一步说明有多糟糕,如果一个VAO中有未使用但已绑定的变量,即使这些未使用的变量被禁用,顶点着色器也会在软件中运行。 - Michel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接