You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reported in version: HG 2.0 Reported for operating system, platform: Android (All), Other
Comments on the original bug report:
On 2011-08-28 19:08:59 +0000, wrote:
The current SDLActivity.java samples that can be found in the repository assume that when the SDLSurface object is destroyed, it means the (native) app needs to quit.
This leads to problems, basically there are cases when the SDLSurface is destroyed while the game is still supposed to be "alive" in the background. Simple use cases include : getting a phone call, showing a webview (for people who want to include ads in their app), or pressing the home button.
I am not an Android expert but it seems the SDLActivity java file should have code to "deinit" EGL. In parallel, the native code needs to have "pause" and "resume" functions that can be called from Java. SDLActivity should basically handle onPause/onStop/onStart/onResume, and SDLSurface should not assume that surfaceDestroyed == quit the game.
I believe the ScummVM port on android had some code that does things more gracefully, it might be a good source of inspiration.
I marked this as a feature request, but it is such a "normal" use case on an android phone (multitasking/getting phone calls/showing ads) that I think it should be handled as a bug
On 2011-09-01 06:53:43 +0000, wrote:
I dug a bit more and I might have a suggested fix, however my current file is so far from the initial SDLActivity.java that I cannot submit a patch immediately, but here are the changes:
class SDLMain implements Runnable {
public void run() {
// Runs SDL_main()
try {
// wait for the surfaceChanged callback
synchronized(_sem_surface) {
while (_surface_holder == null)
_sem_surface.wait();
}
} catch (Exception e) {
throw new RuntimeException("Error preparing the ScummVM thread", e);
}
SDLActivity.nativeInit();
SDLActivity.nativeQuit();
// On exit, tear everything down for a fresh restart next time.
System.exit(0);
Log.v("SDL", "SDL thread terminated");
}
}
// Startup
public SDLSurface(Context context) {
super(context);
_sem_surface = new Object();
_surface_holder = null;
mSurfaceValid = false;
getHolder().addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
requestFocus();
setOnKeyListener(this);
setOnTouchListener(this);
mSensorManager = (SensorManager)context.getSystemService("sensor");
}
// Called when we have a valid drawing surface
public void surfaceCreated(SurfaceHolder holder) {
Log.v("SDL", "surfaceCreated()");
enableSensor(Sensor.TYPE_ACCELEROMETER, true);
}
public void onDestroy() {
// Send a quit message to the application
//should that be in SDLActivity "onDestroy" instead ?
SDLActivity.nativeQuit();
// Now wait for the SDL thread to quit
if (mSDLThread != null) {
try {
mSDLThread.join();
} catch(Exception e) {
Log.v("SDL", "Problem stopping thread: " + e);
}
mSDLThread = null;
//Log.v("SDL", "Finished waiting for SDL thread");
}
}
// Called when we lose the surface
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v("SDL", "surfaceDestroyed()");
synchronized(_sem_surface) {
_surface_holder = null;
mSurfaceValid = false;
_sem_surface.notifyAll();
}
enableSensor(Sensor.TYPE_ACCELEROMETER, false);
}
// Called when the surface is resized
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
Log.v("SDL", "surfaceChanged()");
int sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565 by default
switch (format) {
case PixelFormat.A_8:
Log.v("SDL", "pixel format A_8");
break;
case PixelFormat.LA_88:
Log.v("SDL", "pixel format LA_88");
break;
case PixelFormat.L_8:
Log.v("SDL", "pixel format L_8");
break;
case PixelFormat.RGBA_4444:
Log.v("SDL", "pixel format RGBA_4444");
sdlFormat = 0x85421002; // SDL_PIXELFORMAT_RGBA4444
break;
case PixelFormat.RGBA_5551:
Log.v("SDL", "pixel format RGBA_5551");
sdlFormat = 0x85441002; // SDL_PIXELFORMAT_RGBA5551
break;
case PixelFormat.RGBA_8888:
Log.v("SDL", "pixel format RGBA_8888");
sdlFormat = 0x86462004; // SDL_PIXELFORMAT_RGBA8888
break;
case PixelFormat.RGBX_8888:
Log.v("SDL", "pixel format RGBX_8888");
sdlFormat = 0x86262004; // SDL_PIXELFORMAT_RGBX8888
break;
case PixelFormat.RGB_332:
Log.v("SDL", "pixel format RGB_332");
sdlFormat = 0x84110801; // SDL_PIXELFORMAT_RGB332
break;
case PixelFormat.RGB_565:
Log.v("SDL", "pixel format RGB_565");
sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565
break;
case PixelFormat.RGB_888:
Log.v("SDL", "pixel format RGB_888");
// Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
sdlFormat = 0x86161804; // SDL_PIXELFORMAT_RGB888
break;
default:
Log.v("SDL", "pixel format unknown " + format);
break;
}
SDLActivity.onNativeResize(width, height, sdlFormat);
// Now start up the C app thread
synchronized(_sem_surface) {
_surface_holder = holder;
_sem_surface.notifyAll();
}
}
// unused
public void onDraw(Canvas canvas) {}
// EGL functions
public boolean initEGL(int majorVersion, int minorVersion) {
Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
try {
EGL10 egl = (EGL10)EGLContext.getEGL();
EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
int[] version = new int[2];
egl.eglInitialize(dpy, version);
int EGL_OPENGL_ES_BIT = 1;
int EGL_OPENGL_ES2_BIT = 4;
int renderableType = 0;
if (majorVersion == 2) {
renderableType = EGL_OPENGL_ES2_BIT;
} else if (majorVersion == 1) {
renderableType = EGL_OPENGL_ES_BIT;
}
int[] configSpec = {
//EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_RENDERABLE_TYPE, renderableType,
EGL10.EGL_NONE
};
EGLConfig[] configs = new EGLConfig[1];
int[] num_config = new int[1];
if (!egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config) || num_config[0] == 0) {
Log.e("SDL", "No EGL config available");
return false;
}
mEGLConfig = configs[0];
EGLContext ctx = egl.eglCreateContext(dpy, mEGLConfig, EGL10.EGL_NO_CONTEXT, null);
if (ctx == EGL10.EGL_NO_CONTEXT) {
Log.e("SDL", "Couldn't create context");
return false;
}
EGLSurface surface = egl.eglCreateWindowSurface(dpy, mEGLConfig, this, null);
if (surface == EGL10.EGL_NO_SURFACE) {
Log.e("SDL", "Couldn't create surface");
return false;
}
if (!egl.eglMakeCurrent(dpy, surface, surface, ctx)) {
Log.e("SDL", "Couldn't make context current");
return false;
}
mEGLContext = ctx;
mEGLDisplay = dpy;
mEGLSurface = surface;
mSurfaceValid = true;
} catch(Exception e) {
Log.v("SDL", e + "");
for (StackTraceElement s : e.getStackTrace()) {
Log.v("SDL", s.toString());
}
}
return true;
}
public Boolean createSurface(SurfaceHolder holder) {
/*
* The window size has changed, so we need to create a new
* surface.
*/
EGL10 egl = (EGL10)EGLContext.getEGL();
if (mEGLSurface != null) {
/*
* Unbind and destroy the old EGL surface, if
* there is one.
*/
egl.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE,
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
egl.eglDestroySurface(mEGLDisplay, mEGLSurface);
}
/*
* Create an EGL surface we can render into.
*/
mEGLSurface = egl.eglCreateWindowSurface(mEGLDisplay,
mEGLConfig, holder, null);
/*
* Before we can issue GL commands, we need to make sure
* the context is current and bound to a surface.
*/
egl.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface,
mEGLContext);
mSurfaceValid = true;
return true;
/*
GL gl = mEGLContext.getGL();
if (mGLWrapper != null) {
gl = mGLWrapper.wrap(gl);
}
return gl;*/
}
// EGL buffer flip
public void flipEGL() {
if (!mSurfaceValid)
{
createSurface(this.getHolder());
}
[...]
/**************************************/
Sorry, it's a bit "raw" (EGLInit should probably call surfaceCreated, also surfaceCreated should have more defensive checks, etc...) because I just got it to work and I don't know if I'll be good enough to submit a real patch once I clean up the code, but basically:
do not destroy the app when the surface is destroyed, instead do it when the Activity is destroyed
split initEGL into 2 functions: initEGL and createSurface. CreateSurface needs to be called whenever flipBuffers attempts to render on an invalidSurface. a Boolean can be used in surfaceDestroyed to keep track of when the surface becomes invalid.
For me, this solves some of the issues I had with rendering not working after opening an ad webview. I believe this also fixes pause/resume issues. Note that I added my own native pause/resume functions. Pause only sets a "mPause" bool in the C code, and the main SDL loop just checks for this.
On 2011-09-16 05:53:30 +0000, Tim Angus wrote:
In the fragment you've provided it looks like startSDLThread() is never called? It may be better to just attach your entire SDLActivity.java, unless there is something commercially sensitive in it...
That diff also contains things you don't need: adMob integration and things related to "JGE" which is our own engine.
The rest are changes to support pause/resume.
I hope this helps
On 2011-12-23 12:48:55 +0000, Gabriel Jacobo wrote:
Created attachment 739
Support for Pause/Resume in Android
On 2011-12-23 12:55:11 +0000, Gabriel Jacobo wrote:
Created attachment 740
SDLActivity.java with Pause/Resume support
The attached files provide some improvement over the current handling of pause/resume in Android.
I disabled the exit(status) instruction in SDL_main as that makes the entire app instead of the SDL thread exit (while not needed for pause/resume it is needed for Live Wallpapers, an SDLActivity for which I'll upload in a separate bug).
Added nativePause and nativeResume which basically just mark the window as visible/hidden, something that the end user needs to take into consideration (ideally pausing the event loop).
Also, this arrangement creates a new GL context when needed, which at least in my test system is every time you go away from the app and come back to it. So, this means that the textures need to be generated again after resuming (a problem the end user didn't have before because the app exited completely when it should've been pausing). I'd like to know if there's a standard way of letting the user know that the GL context has changed and that he needs to refresh his textures, or if this is out of the scope of the library and each user handles it in their own way (I don't know how/if this same thing is handled in the iPhone backend, but it would be wise to try to imitate that).
On 2011-12-23 12:57:10 +0000, Gabriel Jacobo wrote:
Also, in the SDLActivity the EGL handling code is moved up to the Activity from the Surface code, as I think it is possible (in theory) that the surface is destroyed temporarily while the context remains alive (though in practice in my test system this is not the case)
On 2011-12-28 10:23:49 +0000, Gabriel Jacobo wrote:
Created attachment 743
Support for Pause/Resume in Android via Window Events
Improved handling via window events.
On 2012-01-07 22:09:01 +0000, Sam Lantinga wrote:
Thanks Gabriel, your changes look fairly clean. There currently isn't any way to signal to the application that textures need to be reloaded, and this is something that probably needs to be added to the API. For now, we should note in the documentation that when you regain focus on Android you need to re-initialize your graphics.
On 2012-01-08 05:18:05 +0000, Vittorio Giovara wrote:
Just a thought, would it be possible to have a uniform event for ios/android?
Currently on iOS when an app is suspended/resumed it receives SDL_WINDOWEVENT_MINIMIZED/SDL_WINDOWEVENT_RESTORED, it would be nice to have the same events on android.
This bug report was migrated from our old Bugzilla tracker.
These attachments are available in the static archive:
Support for Pause/Resume in Android (Android_Pause_Resume.diff, text/plain, 2011-12-23 12:48:55 +0000, 1461 bytes)Reported in version: HG 2.0
Reported for operating system, platform: Android (All), Other
Comments on the original bug report:
On 2011-08-28 19:08:59 +0000, wrote:
On 2011-09-01 06:53:43 +0000, wrote:
On 2011-09-16 05:53:30 +0000, Tim Angus wrote:
On 2011-09-16 18:53:30 +0000, wrote:
On 2011-12-23 12:48:55 +0000, Gabriel Jacobo wrote:
On 2011-12-23 12:55:11 +0000, Gabriel Jacobo wrote:
On 2011-12-23 12:57:10 +0000, Gabriel Jacobo wrote:
On 2011-12-28 10:23:49 +0000, Gabriel Jacobo wrote:
On 2012-01-07 22:09:01 +0000, Sam Lantinga wrote:
On 2012-01-08 05:18:05 +0000, Vittorio Giovara wrote:
On 2012-01-08 10:42:46 +0000, Sam Lantinga wrote:
The text was updated successfully, but these errors were encountered: