Android opengl es context lost when device wake up
http://www.drovik.com/ 2013-6-14 13:00:01 来源:www.drovik.com 点击:
I've been working on a project for quite some time and it's progress is coming along well. However, I have one concern that is bugging me: every time the phone goes to sleep (either by inactivity, or the power button being pressed) or receives a phone call mid-game and resumes afterwards, OpenGL has to recreate the surface and as such, all textures must be reloaded...
I suppose this is "okay" but looking at Angry Birds and Replica Island (whose code for this feature seems to be a hack that is hard to reproduce) they do not need to spend the time reloading them after this happens.
Does anyone know how to either preserve the textures or GL context/surface?
I am currently using the standard GLSurfaceView as my drawing interface, reloading textures in onSurfaceCreated if the eglContext != previous eglContext [it has never been the same in testing thus far anyways]
I suppose this is "okay" but looking at Angry Birds and Replica Island (whose code for this feature seems to be a hack that is hard to reproduce) they do not need to spend the time reloading them after this happens.
Does anyone know how to either preserve the textures or GL context/surface?
I am currently using the standard GLSurfaceView as my drawing interface, reloading textures in onSurfaceCreated if the eglContext != previous eglContext [it has never been the same in testing thus far anyways]
Figured it out on my own - a modified GLSurfaceView is required for this, as the default one will create a new EGLContext after every thread pause. Not too hard to work around for anyone else who needs it!
I took my GLSurfaceView.java from google, the Android source is pretty wide spread and it hasn't changed much since it's first incarnation. Anyways, after you find the source:
In guardedRun () of the GLThread, the lines below need to be commented out or removed so that the EGLContext is not recreated every time the rendering thread is paused:
if (mPaused) {
mEglHelper.finish();
needStart = true;
}
mEglHelper.finish();
needStart = true;
}
After doing this, you need to check the result of "mEglHelper.swap();" when it is called later on in this function to see if it has failed, if it failed - the EGLContext has been lost and needs to be recreated - simply adding "needStart = true" if the swap call failed should recreate the EGLContext and surface the next iteration of the loop.
I also added a callback called onContextCreated to the Renderer class to inform my game when a new Context has been created, so it would only reload the textures after a flag is set in this callback. I call this callback from the GLThread every time mEglHelper.start(); is called (there are two occurances - needStart flag and the original context).
I also added a callback called onContextCreated to the Renderer class to inform my game when a new Context has been created, so it would only reload the textures after a flag is set in this callback. I call this callback from the GLThread every time mEglHelper.start(); is called (there are two occurances - needStart flag and the original context).
For simplicity's sake, here is the code to my modified guardedRun ():
private void guardedRun () throws InterruptedException
{
mEglHelper = new EglHelper ();
mEglHelper.start ();
GL10 gl = null;
boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true;
boolean tellRendererContextCreated = true;
/*
* This is our main activity thread's loop, we go until
* asked to quit.
*/
while (!mDone)
{
/*
* Update the asynchronous state (window size)
*/
int w, h;
boolean changed;
boolean needStart = false;
synchronized (this)
{
Runnable r;
while ((r = getEvent ()) != null)
{
r.run();
}
/*if (mPaused) -- removed for Context preservation
{
mEglHelper.finish();
needStart = true;
}*/
while (needToWait ())
{
wait();
}
if (mDone)
{
break;
}
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
}
if (needStart)
{
mEglHelper.start ();
tellRendererContextCreated = true;
tellRendererSurfaceCreated = true;
changed = true;
}
if (tellRendererContextCreated) // added to notify the renderer to reload GL data
{
mRenderer.onContextCreated ();
tellRendererContextCreated = false;
}
if (changed)
{
gl = (GL10)mEglHelper.createSurface (getHolder ());
tellRendererSurfaceChanged = true;
}
if (tellRendererSurfaceCreated)
{
mRenderer.onSurfaceCreated (gl, mEglHelper.mEglConfig);
tellRendererSurfaceCreated = false;
}
if (tellRendererSurfaceChanged)
{
mRenderer.onSurfaceChanged (gl, w, h);
tellRendererSurfaceChanged = false;
}
if (w > 0 && h > 0)
{
/* draw a frame here */
mRenderer.onDrawFrame (gl);
/*
* Once we're done with GL, we need to call swapBuffers()
* to instruct the system to display the rendered frame
*/
if (!mEglHelper.swap ())
needStart = true; // we've lost our Context, recreate it
}
}
/*
* clean-up everything...
*/
mEglHelper.finish ();
}
{
mEglHelper = new EglHelper ();
mEglHelper.start ();
GL10 gl = null;
boolean tellRendererSurfaceCreated = true;
boolean tellRendererSurfaceChanged = true;
boolean tellRendererContextCreated = true;
/*
* This is our main activity thread's loop, we go until
* asked to quit.
*/
while (!mDone)
{
/*
* Update the asynchronous state (window size)
*/
int w, h;
boolean changed;
boolean needStart = false;
synchronized (this)
{
Runnable r;
while ((r = getEvent ()) != null)
{
r.run();
}
/*if (mPaused) -- removed for Context preservation
{
mEglHelper.finish();
needStart = true;
}*/
while (needToWait ())
{
wait();
}
if (mDone)
{
break;
}
changed = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
}
if (needStart)
{
mEglHelper.start ();
tellRendererContextCreated = true;
tellRendererSurfaceCreated = true;
changed = true;
}
if (tellRendererContextCreated) // added to notify the renderer to reload GL data
{
mRenderer.onContextCreated ();
tellRendererContextCreated = false;
}
if (changed)
{
gl = (GL10)mEglHelper.createSurface (getHolder ());
tellRendererSurfaceChanged = true;
}
if (tellRendererSurfaceCreated)
{
mRenderer.onSurfaceCreated (gl, mEglHelper.mEglConfig);
tellRendererSurfaceCreated = false;
}
if (tellRendererSurfaceChanged)
{
mRenderer.onSurfaceChanged (gl, w, h);
tellRendererSurfaceChanged = false;
}
if (w > 0 && h > 0)
{
/* draw a frame here */
mRenderer.onDrawFrame (gl);
/*
* Once we're done with GL, we need to call swapBuffers()
* to instruct the system to display the rendered frame
*/
if (!mEglHelper.swap ())
needStart = true; // we've lost our Context, recreate it
}
}
/*
* clean-up everything...
*/
mEglHelper.finish ();
}
- 相关文章
- cocos2dx 2.0版本在android下的安装配置问题 (96人浏览)
- android获取Opengl es支持版本的方法 (727人浏览)
- Android AsyncTask threads never die (71人浏览)
- android app中使用JNI (229人浏览)
- Android模拟器下的NDK运行opengl的问题 (232人浏览)
- Drawing Textures Using OpenGL ES2.0 (or (1279人浏览)
- Fast Blit with OpenGL ES 2.0 and texture (216人浏览)
发表评论(4)
- 1楼 ルイヴィトンエピバッグ 发表于 2015-7-5 8:56:59
- That is a really good tip particularly to those fresh to the blogosphere. Simple but very accurate information… Many thanks for sharing this one. A must read post! [url=http://www.punjabmailonline.com/run.asp?pi54dp4ba.htm]ルイヴィトンエピバッグ[/url]
- 2楼 ルイヴィトンメンズ長財布 发表于 2015-7-7 5:18:44
- ルイヴィトンメンズ長財布, ルイヴィトンバッグエピ, ルイヴィトン長財布ラウンドファスナー, ルイヴィトンバッグ人気zozo, ルイヴィトン財布アンプラント, ルイヴィトン財布レディース人気,
- 3楼 ルイヴィトンセカンドバッグメンズ 发表于 2015-7-7 9:44:15
- ルイヴィトンセカンドバッグメンズ, ルイヴィトンデニム財布コピー, ルイヴィトン長財布デニム, ルイヴィトン新作メンズバッグ, ルイヴィトンバッグキーポル, ルイヴィトン財布アズール,
- 4楼 ルイヴィトンバッグジェロニモス 发表于 2015-7-7 9:44:17
- ルイヴィトンバッグジェロニモス, ルイヴィトンバッグコーディネート, ルイヴィトンモノグラムヴェルニジッピーウォレット長財布, ルイヴィトン財布べたつき, ルイヴィトンエピ長財布, ルイヴィトン新作メンズバッグ,
查看更多评论>>>