最近项目比较赶,没看Xcode 8的发布说明,不过,在做性能优化时,发现Instruments工具集比Xcode 7少了几项,被精简的工具中有一项对我们项目影响较大,就是GPU Driver。
更新:经各位老司机提醒,Xcode 7添加的UI Test功能上等同于Automation,所以Instruments 8在功能上并没比上一版本少内容。然而,这几天使用Instruments 8进行性能调优时,发现它一直提示glInvalidateFramebuffer调用位置有误,但是,同样的代码在Instruments 7并没此提示。可以确认的是,这段代码完全遵守WWDC和相关的Programming Guide建议。
Instruments的详细说明与官方文档的说法对我而言,是相反的,如下所示:
The application called glInvalidateFrameBuffer before presenting the renderbuffer. This is incorrect. If you call glInvalidateFramebuffer, do so after presenting.. renderbuffer ID = 1.
Other framebuffer attachments used in your rendering algorithm (for example, depth, stencil, and multisampling buffers) need not be preserved, because their contents will be recreated on the next frame drawn. OpenGL ES automatically stores these buffers to shared memory—incurring a performance cost—unless you explicitly invalidate them. To invalidate a buffer, use the glInvalidateFramebuffer command in OpenGL ES 3.0 or the glDiscardFramebufferEXT command in OpenGL ES 1.1 or 2.0. When you use the basic drawing cycle provided by GLKView class, it automatically invalidates any drawable depth, stencil, or multisampling buffers it creates.
摘自官方文档 Tuning Your OpenGL ES App - Avoid Logical Buffer Loads and Stores
如下是我们的代码,可见,它是按官方建议编写的。
glBlitFramebuffer(0, 0, width, height,
0, 0, width, height,
GL_COLOR_BUFFER_BIT,
GL_LINEAR);
GLenum discardAllAttachments[] = {GL_COLOR_ATTACHMENT0,
GL_DEPTH_ATTACHMENT,
GL_STENCIL_ATTACHMENT};
glInvalidateFramebuffer(GL_READ_FRAMEBUFFER,
sizeof(discardAllAttachments) / sizeof(discardAllAttachments[0]),
discardAllAttachments);
glBindRenderbuffer(GL_RENDERBUFFER, defaultRenderbuffer[0]);
[context presentRenderbuffer:GL_RENDERBUFFER];
现在,回到主题。
Xcode 8 Instruments保留了17个工具。
相比之下,Xcode 7 Instruments装载了19个工具。
被删除的工具分别是Automation和GPU Driver。Automation执行我们编写的脚本并启动在Automation分析应用列表中指定的App,这些脚本模拟了界面点击功能。GPU Driver则从GPU驱动统计接口调用并对相应时间段的CPU占用情况进行采样,用以分析OpenGL (ES)代码的性能。虽然它被删除了,但是,使用Instruments OpenGL ES Analysis时仍有GPU Driver的分析功能。
趋势分析
下面就Instruments的变更谈谈个人想法。
- Automation对应了自动化界面逻辑测试,此次Xcode更新移除它是否会在后期给出更方便的替代品,暂未得到消息,因此令人费解。
- GPU Driver的移动与Metal System Trace工具新增了tvOS和macOS对Metal的支持,暗示了苹果将不会推出官方支持的Vulkan,因为GPU Driver的存在主要是分析OpenGL (ES)程序的性能,Metal System Trace新增说明如下图所示。
那么,在未来的日子里,OpenGL ES 3.0将是iOS支持的最后一个OpenGL ES版本。对于国内多数GPU编程的小团队而言,可能需要同时使用Xcode 7及Xcode 8,工作流依然是在Xcode 8中实现着色器逻辑,用Xcode 7 Instruments进行GPU优化,调校完iOS的着色器性能,再移植至Android端,根据相应的芯片作进一步针对性的优化。当然,对于SenseTime这类有专业GPU开发团队的公司应该是没什么大影响的,因为它有资源实现Metal、Vulkan两套代码以便得到每个平台的最佳性能。当然,我是不会告诉你百度地图的引擎部分也是先在iOS上调试好再往Android上搬运的,这些故事是不能随便告诉别人的。
Xcode 8的GPU相关新增功能
问题来了,既然Xcode 8的Instruments被阉割了,为何我们还要使用Xcode 8呢?原因是,Xcode 8新增了几个实用的GPU调试功能,当然,新功能更多是方便Metal的。
1、查看已上传至GPU的纹理大小
此功能可用于OpenGL ES,可方便查看上传到GPU的纹理尺寸及格式和缓冲区大小,比如1920x1080、Luminance8。
2、屏蔽GPU部分功能
严格意义上说,这并非新功能,而是从Instruments OpenGL ES Analysis搬运到Xcode。
使用Xcode 8创建新项目,把老项目的代码逐一拷贝进来,发现部分功能可在OpenGL ES程序中使用,可禁用部分GPU功能查看性能表现,如下图所示。
比如,选择最小化渲染的像素数量查看Fragment Shader对性能的影响,如下图所示。
另外,iOS 10运行OpenGL ES项目,出错日志会提及Metal的信息,可能真如WWDC描述的那样,iOS 10的OpenGL ES调用为Metal实现。
Execution of the command buffer was aborted due to an error during execution. Caused GPU Hang Error (IOAF code 3)
GLDRendererMetal command buffer completion error: Error Domain=MTLCommandBufferErrorDomain
Code=2 "Caused GPU Hang Error (IOAF code 3)"
UserInfo={NSLocalizedDescription=Caused GPU Hang Error (IOAF code 3)}