`
hereson
  • 浏览: 1451180 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

关于Cocos2dx-JS在iOS8以上系统调用OpenGL进入后台时崩溃的解决办法

 
阅读更多

这次发布新版本后没有预料到的crash是下面这些,并且在遇到之初十分没有头绪:
有这样的:

AGXGLDriver 
glrAGXRenderVertexArray(GLDContextRec*, unsigned int, unsigned int, int, int, unsigned int, void const*, int…

还有这样的:

IMGSGX543RC2GLDriver 
glrSGXRenderVertexArray	
IMGSGX543RC2GLDriver
glrSGXRenderVertexArray

还有最多的显示方式是这样的:

WebCore 
WebCore::GraphicsContext3D::endPaint()

但是他们最终crash的原因却是一样的

Crashed: WebThread 
EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00000001 

在web thread中遇到了一个空指针,并且可以肯定是内部的代码作祟,crash log基本也是相同的

Thread : Crashed: WebThread
0  libGPUSupportMercury.dylib     0x2980d776 gpus_ReturnNotPermittedKillClient + 9
1  libGPUSupportMercury.dylib     0x2980e251 gpusSubmitDataBuffers + 120
2  IMGSGX543RC2GLDriver           0x20ffcddd glrSGXRenderVertexArray + 4120
3  GLEngine                       0x25130b9b glDrawArrays_ACC_ES2Exec + 358
4  WebCore                        0x2ed1b9c5 WebCore::WebGLRenderingContext::drawArrays(unsigned int, int, int, int&) + 128
5  WebCore                        0x2ea15bff WebCore::jsWebGLRenderingContextPrototypeFunctionDrawArrays(JSC::ExecState*) + 466
6  JavaScriptCore                 0x23b15133 llint_entry + 21314
7  JavaScriptCore                 0x23b14cd9 llint_entry + 20200
8  JavaScriptCore                 0x23b14cd9 llint_entry + 20200
9  JavaScriptCore                 0x23b14cd9 llint_entry + 20200
10 JavaScriptCore                 0x23b14cd9 llint_entry + 20200
11 JavaScriptCore                 0x23b14cd9 llint_entry + 20200
12 JavaScriptCore                 0x23b0fbdf callToJavaScript + 334
13 JavaScriptCore                 0x23a9f3b5 JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 36
14 JavaScriptCore                 0x238ebda7 JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 350
15 JavaScriptCore                 0x239e10dd JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&, JSC::JSValue*) + 64
16 WebCore                        0x2e48c7f3 WebCore::JSCallbackData::invokeCallback(JSC::JSValue, JSC::MarkedArgumentBuffer&, bool*) + 426

原因在于嵌入的webview中使用到了Cocos2dx的JS框架,调用了WebGL做图形处理,而WebGL在系统里会调用OpenGL ES的API。根据苹果官方的说明:
https://developer.apple.com/library/ios/qa/qa1766/_index.html
http://developer.apple.com/library/ios/#documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/ImplementingaMultitasking-awareOpenGLESApplication/ImplementingaMultitasking-awareOpenGLESApplication.html#//apple_ref/doc/uid/TP40008793-CH5-SW1

Q: My OpenGL ES application crashes when moving to the background. How do I fix it?
调用了OpenGL ES的程序在退出到后台的时候crash怎么处理
A: If your OpenGL ES application crashes when moving to the background, and you get a crash report that contains a stack trace ending with libGPUSupportMercury.dylib: gpus_ReturnNotPermittedKillClient + 0 as shown in Listing 1, it indicates that the application has attempted to do rendering with OpenGL ES in the background.

Listing 1 Stack trace

Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libGPUSupportMercury.dylib    	0x30570094 gpus_ReturnNotPermittedKillClient + 0
1   libGPUSupportMercury.dylib    	0x305700ae gpus_KillClient ( )
2   libGPUSupportMercury.dylib    	0x305705ba gpusSubmitDMABuffers ( )
3   IMGSGX535GLDriver             	0x34bd29b8 SubmitPacketsIfAny ( )
4   IMGSGX535GLDriver             	0x34bd2ad0 glrFlushContextToken ( )
5   GLEngine                      	0x37719c4a gliPresentViewES ( )
6   OpenGLES                      	0x323df6b4 -[EAGLContext presentRenderbuffer:] ( )
...
...

An OpenGL ES application will be terminated if it attempts to execute OpenGL ES commands in the background. Your application must ensure that all previously submitted commands have been finished and then stop rendering prior to moving into the background. See details about how to achieve this in the Implementing a Multitasking-aware OpenGL ES Application chapter of the OpenGL ES Programming Guide for iOS.

如果你的程序调用了OpenGL ES并且在后台还尝试执行OpenGL的命令,他会被强制终结。你的程序需要在进入后台之前确认所有的OpenGL命令已经被执行完成并且停止继续执行。

在详细文档里,苹果写到:

An OpenGL ES app must perform additional work when it is moved into the background. If an app handles these tasks improperly, it may be terminated by iOS instead. Also, an app may want to free OpenGL ES resources so that those resources are made available to the foreground app.

如果你的程序调用了OpenGL ES,那么在进入后台前需要执行额外操作。如果你的程序没有合适的处理这个任务,系统会终结它。并且你将需要释放OpenGl的资源让前台的程序能够使用更多的资源。

Background Apps May Not Execute Commands on the Graphics Hardware
An OpenGL ES app is terminated if it attempts to execute OpenGL ES commands on the graphics hardware. iOS prevents background apps from accessing the graphics processor so that the frontmost app is always able to present a great experience to the user. Your app can be terminated not only if it makes OpenGL ES calls while in the background but also if previously submitted commands are flushed to the GPU while in the background. Your app must ensure that all previously submitted commands have finished executing before moving into the background.


苹果对于UI处理的资源是管理的十分严格的,对于图形计算的资源来说,如果是用户自己调用的OpenGL命令,系统会禁止处在后台的程序去调用这些命令,因为资源要全部的留给前台的程序去呈现更好的UI。系统的一些自己调用OpenGL的控件自身会处理这些。

If you use a GLKit view and view controller, and only submit OpenGL ES commands during your drawing method, your app automatically behaves correctly when it moves to the background. The GLKViewController class, by default, pauses its animation timer when your app becomes inactive, ensuring that your drawing method is not called.

If you do not use GLKit views or view controllers or if you submit OpenGL ES commands outside a GLKView drawing method, you must take the following steps to ensure that your app is not terminated in the background:

In your app delegate’s applicationWillResignActive: method, your app should stop its animation timer (if any), place itself into a known good state, and then call the glFinish function.

In your app delegate’s applicationDidEnterBackground: method, your app may want to delete some of its OpenGL ES objects to make memory and resources available to the foreground app. Call the glFinish function to ensure that the resources are removed immediately.

After your app exits its applicationDidEnterBackground: method, it must not make any new OpenGL ES calls. If it makes an OpenGL ES call, it is terminated by iOS.

In your app’s applicationWillEnterForeground: method, re-create any objects and restart your animation timer.

To summarize, your app needs to call the glFinish function to ensure that all previously submitted commands are drained from the command buffer and are executed by OpenGL ES. After it moves into the background, you must avoid all use of OpenGL ES until it moves back into the foreground.

当应用退出到后台时如果程序仍然在调用OpenGL的API,那么程序会被强制终结。文档没有说明系统版本问题,但是在iOS8以上的系统上测试确实是必现的一个crash,但是由于是在退出后crash(其实也就是下一次进入应用是重新启动了,有可能在刚打开的时候会闪现一下之前的画面),用户不易察觉。奇怪的是iOS7系统并不会出现这个问题,并且在后台所有的crash日志里也都100%是iOS8以上的用户报告了这一crash。
但是这些都是对于一个在自己的程序里开发了OpenGL ES接口的开发者来说的,我的程序里没有任何调用了OpenGL的地方,只有Cocos2dx-JS访问了OpenGL的接口,我在百度上搜到一篇新闻,说是Cocos2dx-JS从iOS8开始支持WebGL,大幅提升了图像的动画和显示质量,我开始怀疑系统版本的问题和底层的图像处理方式有关系。
报道出处:
http://www.cocoachina.com/cocos/20140928/9787.html

在Cocos2dx的游戏工程配置文件里:
• renderMode: Web引擎绘制模式,仅服务于Web引擎,可能的取值如下:
• 0 – 由引擎自动选择绘制模式
• 1 – 强制使用Canvas绘制模式
• 2 – 强制使用WebGL绘制模式,但是实际上WebGL仍然可能会在一些移动浏览器上被忽略而自动使用Canvas绘制模式

事实上,对于Web网页上的动画处理,在iOS7上的处理是用CANVAS的绘制形式,而iOS8开始采用了更好的WebGL的处理方式,但是这种处理方式给开发者带来的任务就是要在应用里合理的和Cocos2dx-JS的代码交互并且控制好对OpenGL接口的调用。
如果你是原生的调用OpenGL或者原生的Cocos2dx开发,那么需要遵循的原则可以参考苹果的文档和这篇StackOverFlow:
http://stackoverflow.com/questions/10620287/opengl-es-crash-on-move-background-ios-5-1

如果你是通过Cocos2dx-JS来调用OpenGL,那么你需要通过JavaScriptCore来执行页面的JS中可能有的各类Pause方法,在应用退出到后台之前阻止JS继续调用WebGL来绘制动画。
关于Objective-C如何与Javascript交互,可以参考这篇博客:
http://www.chentoo.com/?p=191

最后修改了Cocos2dx中的project.json配置文件,将rendermode强制改为1,在iOS8上运行虽然画质略微差,但是无需更底层的OpenGL访问控制,运行无误,Crash Solved

分享到:
评论

相关推荐

    Cocos2dx大型游戏源码02

    5. **Cocos2dx API**:Cocos2dx提供了丰富的API供开发者调用,包括场景(Scene)、层(Layer)、节点(Node)、动作(Action)等。源码会大量使用这些API来构建游戏世界。 6. **事件处理**:游戏中的用户输入、碰撞...

    Cocos2dx入门初级教程

    Cocos2dx是一款非常流行的游戏开发框架,它主要用于开发2D游戏,同时也适用于开发演示和其它图形交互应用程序。Cocos2dx基础教程是针对初学者设置的,旨在帮助零基础的程序员了解和掌握Cocos2dx的基本概念,包括调度...

    cocos2d(android,ios)

    《cocos2d在Android与iOS游戏开发中的应用详解》 Cocos2d,作为一个开源的游戏开发框架,已经在游戏行业中占据了重要的地位。尤其在移动设备的Android和iOS平台上,cocos2d以其强大的功能和易用性,为开发者提供了...

    cocos2d-x-3.17.2

    它支持包括iOS、Android、Windows、Mac、Linux等在内的多种操作系统,使得开发者只需编写一次代码,就能在多个平台上发布游戏,极大地降低了开发成本和时间投入。 二、渲染引擎 cocos2d-x 使用OpenGL作为其图形渲染...

    cocos2dx实现摇杆功能实例

    在游戏开发领域,cocos2dx是一个非常流行的开源游戏引擎,尤其适合开发2D游戏。它基于C++,提供了一套高效、强大的跨平台开发工具,支持iOS、Android、Windows等多个平台。在这个“cocos2dx实现摇杆功能实例”中,...

    c/c++完整视频教程(二)——–Cocos2dX跨平台游戏开发

    ### C/C++与Cocos2dX跨平台游戏开发知识点详解 #### 一、C/C++编程语言概述 - **C语言**:一种结构化编程语言,由Dennis Ritchie在1972年设计,主要用于系统编程。C语言的特点是简洁、高效,能够直接控制硬件资源...

    Cocos2d-x高级开发教程-网页版

    8. **性能优化**:Cocos2d-x提供了多种性能优化手段,如延迟初始化、内存管理、绘制调用优化等。深入学习并应用这些技巧,能显著提高游戏在各种设备上的运行效率。 9. **多平台支持**:Cocos2d-x支持iOS、Android、...

    cocos2d-iphone

    - **OpenGL ES**:Cocos2d-iPhone使用OpenGL ES进行渲染,这是一种在嵌入式设备上优化的图形库。 2. **核心组件**: - **Scene**:游戏或应用的顶级容器,可以包含多个Layer。 - **Layer**:逻辑分组,包含游戏...

    cocos2d-x 3.0-alpha0 SDK头文件和DLL文件

    8. cocos2dx:这个文件夹很可能包含了Cocos2d-x的核心库文件,包括各种模块如渲染、音频、事件处理等。 这些DLL文件与Cocos2d-x的头文件共同构成了游戏开发环境的基础。开发者在使用这些库时,需要根据平台和项目...

    2dx ccspritebatchnode

    "2dx ccspritebatchnode" 是一个关键的概念,它与2D游戏引擎Cocos2d-x中的渲染优化紧密相关。Cocos2d-x是一个开源的游戏开发框架,广泛应用于iOS、Android以及多种其他平台。`CCSpriteBatchNode`是Cocos2d-x中用于...

    cocosdx 动态波纹特效源码

    cocos2dx是一个跨平台的游戏开发框架,它基于C++,提供了丰富的功能和高效的性能,使得开发者能够轻松地创建2D游戏并将其部署在iOS、Android和Windows等不同平台上。 在描述中提到的“动态波纹特效”是一种常见的...

Global site tag (gtag.js) - Google Analytics