【问题标题】:iPhone openGLES performance tuningiPhone openGLES 性能调优
【发布时间】:2011-01-05 18:01:59
【问题描述】:
我现在尝试了很长一段时间来优化我的游戏的帧率,但没有真正取得进展。我在最新的 iPhone SDK 上运行并拥有 iPhone 3G 3.1.2 设备。
我调用了大约 150 个绘制调用,总共渲染了大约 1900 个三角形(所有对象都使用两个纹理层和多重纹理进行纹理化。大多数纹理来自存储在 pvrtc 2bpp 压缩纹理中的同一个 textureAtlasTexture)。
这在我的手机上以大约 30 fps 的速度呈现,在我看来这对于仅 1900 个三角形来说太低了。
我尝试了很多方法来优化性能,包括将对象批处理在一起,在 CPU 上转换顶点并在单个绘图调用中渲染它们。这会产生 8 个 drawcall(相对于 150 个 drawcall),但性能大致相同(fps 下降到 26fps 左右)
我正在使用存储在交错数组中的 32 字节顶点(12 字节位置,12 字节法线,8 字节 uv)。我正在渲染三角形列表,顶点按 TriStrip 顺序排列。
我做了一些分析,但我真的不知道如何解释它。
仪器采样
使用 Instruments and Sampling 得出以下结果:
http://neo.cycovery.com/instruments_sampling.gif
告诉我很多时间都花在“mach_msg_trap”上。我用谷歌搜索它,似乎调用这个函数是为了等待其他一些事情。但是等什么??
仪器-openGL
带有 openGL 模块的仪器产生了这样的结果:
http://neo.cycovery.com/intstruments_openglES_debug.gif
但在这里我真的不知道这些数字告诉我什么
鲨鱼分析:
用鲨鱼分析也没有告诉我太多:
http://neo.cycovery.com/shark_profile_release.gif
最大的数字是 10%,由 DrawTriangles 花费 - 其余全部花费在非常小的百分比函数中
谁能告诉我我还能做些什么来找出瓶颈并帮助我解释这些分析信息?
非常感谢!
【问题讨论】:
标签:
iphone
opengl-es
performance
【解决方案1】:
您可能受 CPU 限制。 OpenGL ES 工具中的平铺器/渲染器利用率统计显示,GPU 的占空比在 20-30% 之间,以 20-30 fps 进行渲染,这表明如果速度足够快,GPU 可以以 60 fps 运行。看起来您可以做一些事情来从 Instruments 和 Shark 中获取更多关于追求目标的信息:
默认情况下,Sampler 会显示来自每个线程的每个样本,这意味着由系统框架创建的大部分空闲的辅助线程将主导您的视图。为了更好地了解 CPU 实际在做什么,请确保显示详细信息视图(左下角左起第三个按钮)并将 Sample Perspective 更改为 Running Sample Times 以排除线程空闲/阻塞的样本.
我在您的应用程序本身的 Shark 跟踪中没有看到任何示例。这很可能是因为您的代码足够快,以至于它不会出现在热函数列表中的任何位置,但也可能是因为 Shark 无法为您的应用程序找到符号。您可能需要在其首选项中配置搜索路径或手动将 Shark 指向您的应用程序二进制文件。此外,Shark 默认显示函数列表,这些函数按 CPU 时间花费在它们中的多少排序。将视图更改为更像常规调用树的视图可能很有用,因此您可以可视化整个渲染循环如何花费时间。为此,请将右下角的“查看”选项更改为“树(自上而下)”。 (如果您在这里也没有看到您的应用名称或功能,那么 Shark 肯定缺少您的符号。)
【解决方案2】:
不幸的是,我并不精通 OpenGL,但从这三个结果中,有一些让我脱颖而出的地方:
1) 从采样工具中,您可能有某种后台网络连接正在运行?
2) 渲染的利用率百分比对我来说似乎很低(虽然我不知道如何提高它们)。
3) 尽管 10% 看起来很低,但这似乎是一个很好的攻击点 - 但是几乎同样怀疑在 memcpy 中花费了太多时间。 ValidateState 的数量也很大,可能会让您望而却步。
工具方面,我认为您正在使用正确的工具来检查性能,您只需要更多地考虑这些工具对您的应用程序意味着什么。
【解决方案3】:
如果没有完整的来源,很难确切地知道发生了什么。 Instruments 跟踪显示 20% 的渲染利用率,这有点低。这可能意味着您受 CPU 限制。但是,如果是这种情况,我希望在您的第一个跟踪中看到更多特定于应用程序的样本点。
我的建议是推出自己的计时课程。像这样的东西(c++):
#include <sys/time.h>
class Timer
{
public:
Timer()
{
gettimeofday(&m_time, NULL);
}
void Reset()
{
gettimeofday(&m_time, NULL);
}
// returns time since construction or Reset in microseconds.
unsigned long GetTime() const
{
timeval now;
gettimeofday(&now, NULL);
unsigned long micros = (now.tv_sec-m_time.tv_sec)*1000000+
(now.tv_usec-m_time.tv_usec);
return micros;
}
protected:
timeval m_time;
};
为你的代码段计时,以准确了解你的时间花在了哪里。
另一个快速解决方法是禁用 Thumb 指令集。这可以以牺牲可执行文件大小为代价,帮助您的浮点性能提高 20% 或更多。
【解决方案4】:
如果您使用的是 glFlush 或 glFinish,请删除所有这些。