Android black screen on resume

Despite using SDL 2.0.4 and, as far as I know, following all the guidelines (e.g. suspending rendering calls when my app is in the background) I’m suffering the old ‘black screen on resume’ problem. Here is a snippet from logcat, I’m guessing the EGL_BAD_ACCESS errors may be relevant:

Code:
V/SDL ( 972): nativeResume()
I/SDL/APP ( 972): SDL_APP_DIDENTERFOREGROUND
D/ ( 972): Updating FBO content dimensions 1920x1104
E/libEGL ( 972): eglMakeCurrent:777 error 3002 (EGL_BAD_ACCESS)
D/ ( 972): droid_create_context : config id = 10 conf->NativeVisualID=4
D/ ( 972): Pixel Format : GGL_PIXEL_FORMAT_RGB_565
I/ ( 972): Requested context : GLES 1.1.
E/libEGL ( 972): eglMakeCurrent:777 error 3002 (EGL_BAD_ACCESS)

I’m using OpenGLES (not ES2) and my rendering code is as follows (done this way so the target bitmap is preserved, since it is updated incrementally):

Code:
SDL_SetRenderTarget(renderer, NULL);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bitmap, NULL, &DestRect);
SDL_RenderPresent(renderer);
SDL_SetRenderTarget(renderer, bitmap);

The app is still running after the resume (for example if it is playing music that still works) but the display is entirely black.

Any ideas?

Richard.

I’ve had the same. You have to manually reupload all images to the GPU, e.g. convert all surfaces to textures when you receive the resume event.------------------------
ePic Character Generator - endless character stream in your games using SDL 2.0:


I’ve had the same. You have to manually reupload all images to the GPU, e.g. convert all surfaces to textures when you receive the resume event.------------------------
ePic Character Generator - endless character stream in your games using SDL 2.0:


LBandy wrote:

You have to manually reupload all images to the GPU, e.g. convert all surfaces to textures when you receive the resume event.

I don’t have any surfaces - only textures!

I’ve also discovered that if I go back to SDL 2.0.3 everything works fine: it resumes from the background correctly and the black screen problem does not occur.

Richard.

rtrussell wrote:

I’ve also discovered that if I go back to SDL 2.0.3 everything works

To double-check I downloaded and installed SDL-2.0.4 again from scratch, and the black screen problem came back. So, sadly, it does seem that a change from 2.0.3 to 2.0.4 is responsible. It’s a pity, because I particularly wanted to take advantage of the Android Message Box functionality added in 2.0.4.

Richard.

rtrussell wrote:

it does seem that a change from 2.0.3 to 2.0.4 is responsible.

I’ve been trying to pin down where the significant difference is, but so far without success. I was hoping to make incremental changes from 2.0.3 to 2.0.4 to find out which one introduces the fault, but there are so many dependencies it is proving difficult to make intermediate versions that successfully compile and run. I would welcome suggestions for how to proceed.

Richard.

I don’t have much in terms of guidance, but only some data points.
I do not have any problems with backgrounding with 2.0.4.
However, I’m using GLES2, not 1.1. But 100% of Android devices support
at least 2.0 by Google’s statistics. It looks like you are using the
SDL 2D renderer. I don’t see why you need to stay with 1.1.

Additionally, device manufacturer and operating system version may
matter here. Android fragmentation is real. Some devices are much
better than others. OS versions matter a lot too. I’ve tried 2.0.4
under 4.x and 5.0.2. How many different devices and OS versions have
you tried?

For example, the comment about unloading and reuploading textures is
less needed somewhere in the 3.0 or 4 time frame. I think officially
you still can get hosed, but I haven’t heard of any cases recently.)

Have you tried simple test apps to test the backgrounding?
More often than not, I see blank screen bugs the result of other bugs
in the codebase. For example, Android does something stupid and
doesn’t reinitialize static and global variables between
quits/relaunches, unless you do something like a force kill or crash
(or Android actually completely killed the process). I’ve had a lot of
annoying bugs due to the fact that these variables contained the state
from the previous run instead of being reset so the program wouldn’t
continue correctly.

-EricOn 2/14/16, rtrussell wrote:

rtrussell wrote:

it does seem that a change from 2.0.3 to 2.0.4 is responsible.

I’ve been trying to pin down where the significant difference is, but so far
without success. I was hoping to make incremental changes from 2.0.3 to
2.0.4 to find out which one introduces the fault, but there are so many
dependencies it is proving difficult to make intermediate versions that
successfully compile and run. I would welcome suggestions for how to
proceed.

Richard.

Eric Wing wrote:

I don’t see why you need to stay with 1.1.

I am using GLES 1.1 because I need the ‘glLogicOp’ functionality (where graphics are AND, OR or XOR plotted). Annoyingly, this functionality was deleted from GLES 2 but it’s essential for my application. There seem to be significant changes from 2.0.3 to 2.0.4 in the render/opengles directory so apparently GLES 1.1 is still supported by SDL.

How many different devices and OS versions have
you tried?

I’ve tried it on an Android 5.1 (Lollipop) tablet and an Android 4.2.1 (Jelly Bean) phone. The symptoms are identical: it works perfectly in SDL 2.0.3 but fails in 2.0.4.

Have you tried simple test apps to test the backgrounding?

No, but I do intend to try that, if only so I can upload a test case.

More often than not, I see blank screen bugs the result of other bugs
in the codebase.

I appreciate that, but it would have to be an obscure bug not to cause any problems with 2.0.3.

I will try to distil my app down to a minimal test case which demonstrates the issue.

Richard.

OK, here’s a test case to demonstrate the problem. With SDL 2.0.3 it resumes from the background correctly, but with SDL 2.0.4 resuming results in a black screen. The simplest way to test is to tap on the Android ‘square’ navigation button to put the app into the background, and then tap the app’s icon to resume. It would be really helpful if somebody can suggest a way forward to resolve this issue.

testcase.c:

Code:
/******************************************************************\

  • Testcase to demonstrate problem with SDL 2.0.4 on Android GLES 1 *
    ******************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include “SDL.h”

#define GL_COLOR_LOGIC_OP 0x0BF2
#define GL_XOR 0x1506
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 500
#define IDLE 2
#define PACER 20

void (*glEnable) (int) ;
void (*glLogicOp) (int) ;
void (*glDisable) (int) ;

static int bkgnd = 0 ;

int myEventFilter(void* userdata, SDL_Event* pev)
{
switch (pev->type)
{
case SDL_APP_WILLENTERBACKGROUND:
bkgnd = 1 ;
break ;

	case SDL_APP_WILLENTERFOREGROUND:
	bkgnd = 0 ;
	break ;
}
return 0 ;

}

int main(int argc, char* argv[])
{
int running = 1 ;
int sizex, sizey ;
SDL_Event ev ;
SDL_Window *myWindow ;
SDL_Renderer *myRenderer ;
SDL_Rect myRect ;

if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER |
SDL_INIT_EVENTS | SDL_INIT_JOYSTICK) != 0)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
“Testcase”, SDL_GetError(), NULL) ;
return 1;
}

#ifdef ANDROID
SDL_SetHint (SDL_HINT_RENDER_DRIVER, “opengles”) ;
SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, “linear”) ;
#else
SDL_SetHint (SDL_HINT_RENDER_DRIVER, “opengl”) ;
SDL_SetHint (SDL_HINT_RENDER_SCALE_QUALITY, “linear”) ;
#endif

myWindow = SDL_CreateWindow(“BBCSDL”, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE) ;
if (myWindow == NULL)
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
“Testcase”, SDL_GetError(), NULL) ;
SDL_Quit() ;
return 5;
}

SDL_GetWindowSize (myWindow, &sizex, &sizey) ; // Window may not be the requested size

myRenderer = SDL_CreateRenderer(myWindow, -1, SDL_RENDERER_ACCELERATED |SDL_RENDERER_PRESENTVSYNC) ;
if (myRenderer == NULL)
{
SDL_DestroyWindow(myWindow) ;
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
“Testcase”, SDL_GetError(), NULL) ;
SDL_Quit() ;
return 6;
}

if (!SDL_RenderTargetSupported(myRenderer))
{
SDL_DestroyWindow(myWindow) ;
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
“Testcase”, “Render targets not supported”, NULL) ;
SDL_Quit() ;
return 7;
}

SDL_SetRenderTarget(myRenderer, SDL_CreateTexture(myRenderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_TARGET, sizex, sizey)) ;

#ifdef ANDROID
glLogicOp = (void *) dlsym (-1, “glLogicOp”) ;
glEnable = (void *) dlsym (-1, “glEnable”) ;
glDisable = (void *) dlsym (-1, “glDisable”) ;
#else
glLogicOp = SDL_GL_GetProcAddress(“glLogicOp”) ;
glEnable = SDL_GL_GetProcAddress(“glEnable”) ;
glDisable = SDL_GL_GetProcAddress(“glDisable”) ;
#endif

glEnable(GL_COLOR_LOGIC_OP) ;
glLogicOp(GL_XOR) ;
SDL_SetRenderDrawColor(myRenderer, 0, 0, 255, 255) ;
SDL_RenderFillRect(myRenderer, NULL) ;
myRect.x = 0 ;
myRect.y = 0 ;
myRect.w = sizex / 2 ;
myRect.h = sizey ;
SDL_SetRenderDrawColor(myRenderer, 255, 0, 255, 255) ;
SDL_RenderFillRect(myRenderer, &myRect) ;
myRect.x = 0 ;
myRect.y = 0 ;
myRect.w = sizex ;
myRect.h = sizey / 2 ;
SDL_SetRenderDrawColor(myRenderer, 255, 255, 255, 255) ;
SDL_RenderFillRect(myRenderer, &myRect) ;
glDisable(GL_COLOR_LOGIC_OP) ;

SDL_AddEventWatch(myEventFilter, 0) ;

// Main loop:
while (running)
{
static unsigned int zoom = 32768 ;
static int offsetx, offsety ;
unsigned int lastpaint ;
unsigned int now = SDL_GetTicks () ;
float scale = (float)(zoom) / 32768.0 ; // must be float

if (((now >= (lastpaint + PACER)) || (now < lastpaint)) && !bkgnd)
{
	int winx, winy ;
	SDL_Rect DestRect ;
	SDL_Texture *bitmap = SDL_GetRenderTarget (myRenderer) ;
	SDL_GetWindowSize (myWindow, &winx, &winy) ;

	DestRect.x = -offsetx * scale ;
	DestRect.y = -offsety * scale ;
	DestRect.w = sizex * scale ;
	DestRect.h = sizey * scale ;
	DestRect.x += (winx - DestRect.w) >> 1 ;

	SDL_SetRenderTarget(myRenderer, NULL) ;
	SDL_SetRenderDrawColor (myRenderer, 0, 0, 0, 255) ;
	SDL_RenderClear (myRenderer) ;
	SDL_RenderCopy(myRenderer, bitmap, NULL, &DestRect) ;
	SDL_RenderPresent(myRenderer) ;
	SDL_SetRenderTarget(myRenderer, bitmap) ;

	lastpaint = SDL_GetTicks() ; // wraps around after 50 days
}

SDL_PumpEvents () ;
if (SDL_PeepEvents(&ev, 1, SDL_GETEVENT, 0, SDL_USEREVENT-1))
	switch (ev.type)
	{
		static float panx, pany ;

		case SDL_QUIT:
			running = 0 ;
			break ;

		case SDL_MULTIGESTURE :
    	                if (fabs(ev.mgesture.dDist) > 0.002)
				zoom = zoom * (1.0 + ev.mgesture.dDist) /
                     	                     (1.0 - ev.mgesture.dDist) ;

			if (fabs(ev.mgesture.x - panx) < 0.05)
				offsetx -= sizex * (ev.mgesture.x - panx) / scale ;

			if (fabs(ev.mgesture.y - pany) < 0.05)
				offsety -= sizey * (ev.mgesture.y - pany) / scale ;

			panx = ev.mgesture.x ;
			pany = ev.mgesture.y ;
			break ;
	}

else
	SDL_Delay (IDLE) ;

}

SDL_DestroyRenderer(myRenderer) ;
SDL_DestroyWindow(myWindow) ;
SDL_Quit() ;

exit(0) ;
}

AndroidManifest.xml:

Code:

<?xml version="1.0" encoding="utf-8"?>

<!-- Create a Java class extending SDLActivity and place it in a
     directory under src matching the package, e.g.
     	src/com/gamemaker/game/MyGame.java

     then replace "SDLActivity" with the name of your class (e.g. "MyGame")
     in the XML below.

     An example Java class can be found in README-android.txt
-->
<application android:label="@string/app_name"
             android:icon="@drawable/ic_launcher"
             android:allowBackup="true"
             android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
             android:hardwareAccelerated="true" >
    <activity android:name="TestCase"
              android:label="@string/app_name"
              android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
              >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

<!-- Android 2.3.3 -->
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" />

<!-- OpenGL ES 2.0 -->
<!-- uses-feature android:glEsVersion="0x00020000" --> 

<!-- Allow writing to external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

Richard.

Out of curiosity, did you test OpenGLES 2 in this case to show there
is a difference between it and 1.1?

Also, I see static/global variables in your example. That has a code
smell for Android because Android doesn’t always reinitialize your
static/global variables on quit/relaunch (because Android is stupid).
This means when you are repeating you testing, your global/statics
might not be set to what you think they are and are carrying garbage
values from the prior run.

Finally, I posted these in another thread for Android troubleshooting,
but they might reveal something. Here are some apks I made. They use
SDL’s 2D renderer (defaults) and 2.0.4. As far as I know, they
background and resume correctly. Try running these and see if you see
a blank screen problem.

http://blurrrsdk.com/tempdownload/BlurrrBinaries/FlappyBlurrr/FlappyBlurrrC.apk
http://blurrrsdk.com/tempdownload/BlurrrBinaries/FlappyBlurrr/FlappyBlurrrJavaScript.apk
http://blurrrsdk.com/tempdownload/BlurrrBinaries/FlappyBlurrr/FlappyBlurrrLua.apk
http://blurrrsdk.com/tempdownload/BlurrrBinaries/FlappyBlurrr/FlappyBlurrrSwift.apk

-EricOn 3/25/16, rtrussell wrote:

OK, here’s a test case to demonstrate the problem. With SDL 2.0.3 it
resumes from the background correctly, but with SDL 2.0.4 resuming results
in a black screen. The simplest way to test is to tap on the Android
’square’ navigation button to put the app into the background, and then tap
the app’s icon to resume. It would be really helpful if somebody can
suggest a way forward to resolve this issue.

Eric Wing wrote:

Out of curiosity, did you test OpenGLES 2 in this case to show there
is a difference between it and 1.1?

Yes, GLES2 resumes correctly (but I can’t use it). The problem only affects GLES 1.1.

This means when you are repeating you testing, your global/statics
might not be set to what you think they are and are carrying garbage
values from the prior run.

The only globals/statics are ordinary C variables that are stored on the heap. They are preserved through a suspend/resume.

I posted these in another thread for Android troubleshooting,
but they might reveal something… They use SDL’s 2D renderer (defaults)

The default renderer will be GLES 2 on my devices, so running your apps here won’t reveal anything I’m afraid. What might be informative is if you can add the opengles hint to your code and then see whether they still resume correctly for you using GLES 1.1.

Richard.

rtrussell wrote:

What might be informative is if you can add the opengles hint to your code and then see whether they still resume correctly for you using GLES 1.1.

Eric, are you able to do that test? If you find SDL 2.0.4 with GLES 1.1 does resume correctly for you it would give me an avenue to explore, otherwise I’m all out of ideas for how to progress this. Although I can cope with using 2.0.3 at the moment it’s not very satisfactory, and if a fix isn’t forthcoming I’m not going to be able to take advantage of future SDL upgrades.

Richard.

I tried to reproduce, but I’m not seeing the problem.

I added SDL_SetHint (SDL_HINT_RENDER_DRIVER, “opengles”); right before
my SDL_CreateWindow call in my FlappyBlurrr example. I’m on SDL 2.0.4
(plus a couple of weeks).

Running Nexus 7 2013, Android 5.0.2.

Tried suspending by hitting the circle button and also the square
button. Both resumed with no problems. Also swapped to another SDL
program and back; no problem there either.

-EricOn 3/30/16, rtrussell wrote:

rtrussell wrote:

What might be informative is if you can add the opengles hint to your code
and then see whether they still resume correctly for you using GLES 1.1.

Eric, are you able to do that test? If you find SDL 2.0.4 with GLES 1.1
does resume correctly for you it would give me an avenue to explore,
otherwise I’m all out of ideas for how to progress this. Although I can
cope with using 2.0.3 at the moment it’s not very satisfactory, and if a fix
isn’t forthcoming I’m not going to be able to take advantage of future SDL
upgrades.

Eric Wing wrote:

I tried to reproduce, but I’m not seeing the problem.

Interesting. Is the source available for me to compare with mine?

Any chance of you making a GLES 1.1 APK available for download so I can confirm I don’t see the problem on my devices?

I’m on SDL 2.0.4 (plus a couple of weeks).

Do you think the “plus a couple of weeks” could be significant?

Richard.

Eric Wing wrote:

I tried to reproduce, but I’m not seeing the problem.

Interesting. Is the source available for me to compare with mine?

I haven’t formally announced this repo, as it is part of my SDK
examples. But whatever.

Though I highly recommend using the full SDK. It makes actually trying
things so much easier. I have an early access program going on right
now.
https://blurrrsdk.com

Any chance of you making a GLES 1.1 APK available for download so I can
confirm I don’t see the problem on my devices?
Here you go.
http://playcontrol.net/tempdownload/BlurrrBinaries/FlappyBlurrrC_es11.apk

I’m on SDL 2.0.4 (plus a couple of weeks).
Do you think the “plus a couple of weeks” could be significant?

I wouldn’t think so, but here’s my branch. It merges a few patches I
have. I don’t think they are relevant to your situation, but you can
sift through it.

-EricOn 3/31/16, rtrussell wrote:

I wouldn’t think so, but here’s my branch.
https://bitbucket.org/ewing/blurrrsdl

Sorry, wrong link. This is the correct link:

Eric Wing wrote:

Here you go.
http://playcontrol.net/tempdownload/BlurrrBinaries/FlappyBlurrrC_es11.apk

Progress, of sorts. I’ve confirmed that your APK runs correctly here, so it’s not something specific to my devices. Comparing your code with mine, the most significant difference is that I am using a separate texture as my render target:

Code:
SDL_SetRenderTarget(myRenderer, myTexture) ;

If, as an experiment, I convert my testcase to use the default render target (which means rendering my graphic every frame, rather than just once) then it does resume correctly. So it would seem that the difference between 2.0.3 and 2.0.4 is specifically affecting the case when a separate texture is used as the render target.

Is it possible that my target texture is being destroyed by the suspend/resume in 2.0.4 but not in 2.0.3?

Richard.

Guys,

In reproducing the black screen bug, you are not discerning between onPause() and onDestroy() in the Android lifecycle.

By default, SDL2 (both 2.0.3 and 2.0.4) freezes the application when it goes into the background with onPause(). When it resumes, very few resources need to be recreated since you are un-suspending a process.

When onDestroy() is called, application resources are destroyed and need to be recreated.

Unless overridden by developer settings, it is non-deterministic when onDestroy() is being called, so trying to reproduce black screen bugs without knowing whether it has or not is a waste of time.

In developer options, you can select ?Do not keep activities? which will force onDestroy() on backgrounding. However, it is called as soon as onPause() is called, overriding any asynchronous events such as writing saves to a cloud or whatever, so it is not the same as testing the true lifecycle of an Android app.

But at any rate, this ?it works for me?, ?it does not work for me?, needs to take into account the fact that onDestroy() may or may not be getting called, invalidating all your tests.

The resume code path for SDL2 is very different if onDestroy() was called while or during the application backgrounding.

Michael Labb?> On Mar 31, 2016, at 10:13 AM, rtrussell wrote:

Eric Wing wrote:
Here you go.
http://playcontrol.net/tempdownload/BlurrrBinaries/FlappyBlurrrC_es11.apk http://playcontrol.net/tempdownload/BlurrrBinaries/FlappyBlurrrC_es11.apk
Progress, of sorts. I’ve confirmed that your APK runs correctly here, so it’s not something specific to my devices. Comparing your code with mine, the most significant difference is that I am using a separate texture as my render target:

Code:
SDL_SetRenderTarget(myRenderer, myTexture) ;

If, as an experiment, I convert my testcase to use the default render target (which means rendering my graphic every frame, rather than just once) then it doesresume correctly. So it would seem that the difference between 2.0.3 and 2.0.4 is specifically affecting the case when a separate texture is used as the render target.

Is it possible that my target texture is being destroyed by the suspend/resume in 2.0.4 but not in 2.0.3?

Richard.


SDL mailing list
SDL at lists.libsdl.org <mailto:SDL at lists.libsdl.org>
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

FYI, FlappyBlurrr does use render to texture (change the target) to
render things like some of the text (particularly for the Game Over
panel).On 3/31/16, rtrussell wrote:

Eric Wing wrote:

Here you go.
http://playcontrol.net/tempdownload/BlurrrBinaries/FlappyBlurrrC_es11.apk

Progress, of sorts. I’ve confirmed that your APK runs correctly here, so
it’s not something specific to my devices. Comparing your code with mine,
the most significant difference is that I am using a separate texture as my
render target:

Code:
SDL_SetRenderTarget(myRenderer, myTexture) ;

If, as an experiment, I convert my testcase to use the default render target
(which means rendering my graphic every frame, rather than just once) then
it does resume correctly. So it would seem that the difference between
2.0.3 and 2.0.4 is specifically affecting the case when a separate texture
is used as the render target.

Is it possible that my target texture is being destroyed by the
suspend/resume in 2.0.4 but not in 2.0.3?

Richard.

Michael Labb?? wrote:

But at any rate, this ???it works for me???, ???it does not work for me???, needs to take into account the fact that onDestroy() may or may not be getting called, invalidating all your tests.

I do not understand how, in a practical sense, you want me to “take it into account”. SDL is designed to isolate the application programmer from this kind of OS-specific detail. All I observe is a program that always works correctly in 2.0.3 but always fails in 2.0.4. I don’t see any other variability that might suggest onDestroy() is sometimes being called and sometimes not.

Richard.