Android black screen on resume

So my Flappy Blurrr example does properly distinguish and handle
onPause vs. onDestroy(). And this was what I was alluding to earlier
when I warned about his use of global/static variables in his sample
code because these are the things that will screw you up if you don’t
use them properly and fail to distinguish between these two events.

However in practice, just for quick suspend/resume testing (hitting
Square) in a small test app, Android isn’t that wildly random for
testing just the suspend/resume part. I don’t think I’ve ever seen it
call onDestroy just toggling with that button, nor should it since
Android users would be really annoyed their apps completely restart
the very first time they hit Square/Circle. (Though I still find it
incredible that Android still makes the default behavior to restart
your app on an orientation change. I used to get tons of misdirected
confusion/blame/hate from developers about that at a previous job.)

-EricOn 3/31/16, Michael Labb? wrote:

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?

Eric Wing wrote:

FYI, FlappyBlurrr does use render to texture (change the target) to
render things like some of the text (particularly for the Game Over
panel).

However (and correct me if I’m wrong) I don’t think you rely on the target texture retaining its contents through a suspend/resume in quite the same way as I do. If I’ve understood your code correctly, everything is rendered from scratch on every frame. In my testcase however I render the background just once during the startup phase of the program; it doesn’t get rendered every frame, just copied from a texture. This technique works fine on all platforms, using SDL 2.0.3.

This is the essence of what my code does every frame, note that nothing is ‘rendered’ as such:

Code:
myTexture = SDL_GetRenderTarget(myRenderer) ;
SDL_SetRenderTarget(myRenderer, NULL) ;
SDL_RenderClear(myRenderer) ;
SDL_RenderCopy(myRenderer, myTexture, NULL, NULL) ;
SDL_RenderPresent(myRenderer) ;
SDL_SetRenderTarget(myRenderer, myTexture) ;

Richard.

Does your code respond to SDL_RENDER_TARGETS_RESET and SDL_RENDER_DEVICE_RESET events?> On Mar 31, 2016, at 6:47 PM, rtrussell wrote:

Eric Wing wrote:
FYI, FlappyBlurrr does use render to texture (change the target) to
render things like some of the text (particularly for the Game Over
panel).

However (and correct me if I’m wrong) I don’t think you rely on the target texture retaining its contents through a suspend/resume in quite the same way as I do. If I’ve understood your code correctly, everything is rendered from scratch on every frame. In my testcase however I render the background just once during the startup phase of the program; it doesn’t get rendered every frame, just copied from a texture. This technique works fine on all platforms, using SDL 2.0.3.

Alex Szpakowski wrote:

Does your code respond to SDL_RENDER_TARGETS_RESET and SDL_RENDER_DEVICE_RESET events?

No, and it doesn’t seem to be necessary with SDL 2.0.3. If you are suggesting that in SDL 2.0.4 the render target may be reset when in 2.0.3 it wasn’t, I’m probably screwed (I can’t recreate the contents of the target texture on demand, it’s not stored anywhere else)!

Richard.

It was always necessary on Android as far as I know. The OS tends to destroy the OpenGL context behind the app?s back.> On Mar 31, 2016, at 7:03 PM, rtrussell wrote:

Alex Szpakowski wrote:
Does your code respond to SDL_RENDER_TARGETS_RESET and SDL_RENDER_DEVICE_RESET events?

No, and it doesn’t seem to be necessary with SDL 2.0.3. If you are suggesting that in SDL 2.0.4 the render target may be reset when in 2.0.3 it wasn’t, I’m probably screwed (I can’t recreate the contents of the target texture on demand, it’s not stored anywhere else)!

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

Alex Szpakowski wrote:

It was always necessary on Android as far as I know.

I’ve read that too, but I’ve seen no evidence of the OpenGL context being destroyed on a suspend/resume when using SDL 2.0.3 on Android. My assumption is that if this is going to happen it will be as the result of an onDestroy(), which as Eric commented would not be expected on a simple suspend/resume (for example using the square button). In my application (a programming language) I would expect a black screen after an onDestroy(); it would then be the responsibility of the user’s program to decide what to do.

Richard.

rtrussell wrote:

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.

This is definitely key to the issue. If I deselect my target texture as soon as I’ve rendered the background (rather than leaving it selected as the render target most of the time) then the suspend/resume works correctly in 2.0.4. So it’s looking as though what matters is whether the texture is selected as the render target when the resume happens: if it is I get a black screen, if it isn’t I don’t. Why should that have changed since 2.0.3?

I tried deselecting the texture in my SDL_APP_WILLENTERBACKGROUND handler and reselecting it in my SDL_APP_DIDENTERFOREGROUND handler, reasoning that this ought to have the same effect. But it doesn’t: I still get a black screen. It’s almost as though the resume hasn’t fully completed when the DIDENTERFOREGROUND event is triggered; is that possible?

At least I can feel I’m homing in on the problem.

Richard.

Actually, there are some things that rely on the textures persisting
in the code. This is kind of a bug, however I’ve done a lot of testing
and it only is a problem for Direct3D when I toggle fullscreen modes.
OpenGL on all the platforms I’ve tested on seem to handle this okay.

I didn’t know about the SDL_RENDER_TARGETS_RESET and
SDL_RENDER_DEVICE_RESET events, but these sound perfect for handling
the Direct3D fullscreen toggle case.

But for your problem, this might rule out this line of reasoning.

Also, while the Android documentation warns the OpenGL context can be
destroyed out from under you, I don’t think this actually happens in
the real world any more because it was such a pain for developers and
actually having reliable apps in the market place (I forgot what
Android version, but pretty confident it was done by 4.0). I think
that clause was left in to cover their butts because they never like
to guarantee anything actually works in Android. (Though if anybody
knows of real device models and Android versions that still have this
problem, I’d like to know. I already scattered notes about There
might be a manifest setting or API thing to request this mode.
(Already forgot all the details, ) But again, for your case of
toggling the Square/Circle, I don’t think losing the OpenGL context is
the actual problem. (And Flappy Blurrr doesn’t jump through any
special hoops to handle this and this is working for you.)

But there could be a multitude of other differences. NDK version, NDK
target API, SDK version, SDK api version, toolchain version, how you
and I built SDL (I used my CMake patch/fork) and against which
settings of theses, which compiler version/chain you used,
optimization levels, AndroidManifest settings and so forth. I’ve seen
little things like this make all the difference sometimes with bugs.
There was another thread here that had a thread deadlock problem or
something, and simply updating to the lastest NDK made the problem
disappear.

-EricOn 3/31/16, rtrussell wrote:

Eric Wing wrote:

FYI, FlappyBlurrr does use render to texture (change the target) to
render things like some of the text (particularly for the Game Over
panel).

However (and correct me if I’m wrong) I don’t think you rely on the target
texture retaining its contents through a suspend/resume in quite the same
way as I do. If I’ve understood your code correctly, everything is rendered
from scratch on every frame. In my testcase however I render the background
just once during the startup phase of the program; it doesn’t get rendered
every frame, just copied from a texture. This technique works fine on all
platforms, using SDL 2.0.3.

One more thing, I feel remiss in not pointing out that all we actually
established with my build is I added
SDL_SetHint(SDL_HINT_RENDER_DRIVER, “opengles”); We don’t have any
proof it actually triggered 1.1 mode. I honestly would not have
guessed that SDL would force 1.1 mode with that hint. Why not OpenGL
ES 2.0 or 3.0?

-Eric

Eric Wing wrote:

We don’t have any proof it actually triggered 1.1 mode.

Not in your case, I admit, but in my testcase (and in my app) I perform ‘exclusive-or’ plotting which won’t work otherwise. If it’s easy for you to build my testcase from the source I listed (and with your toolchain I guess it should be) you can confirm that GLES 1.1 is being used by checking that the display looks like this (possibly upside-down, which is another known bug in SDL/GLES 1.1!):

[Image: http://www.rtr.myzen.co.uk/testcase.gif ]

I realise that it’s in the nature of a ‘hint’ that nothing is guaranteed, but since my app relies on the ‘logical’ plotting modes it’s that or nothing as far as I am concerned!

If I’m right in concluding from my experiments that SDL 2.0.4/GLES 1.1 is causing the target texture to be destroyed on a suspend/resume, there isn’t a fully satisfactory workaround. I can attempt to keep the texture deselected most of the time, and I’m sure that will help, but inevitably it must be selected as the render target some of the time. Given the asynchronous nature of a suspend/resume it’s bound to happen occasionally when the texture is selected, and then I’m stuck.

It seems to me (in the absence of an unequivocal statement of what should happen) that since 2.0.3 always seems to preserve the texture through a suspend/resume, and since 2.0.4 with GLES 2 also seems to preserve the texture, that the issue with 2.0.4 and GLES 1.1 is indeed most probably a bug in SDL. Unfortunately, given the relatively uncommon circumstances, I can have little confidence that it’s going to be fixed, and that’s a worry for me.

Richard.

Eric Wing wrote:

But there could be a multitude of other differences. NDK version, NDK
target API, SDK version, SDK api version, toolchain version, how you
and I built SDL (I used my CMake patch/fork) and against which
settings of theses, which compiler version/chain you used,
optimization levels, AndroidManifest settings and so forth.

Right. Now, if I could only persuade you to build my testcase using your toolchain we could eliminate (or confirm) that possibility at a stroke! Is there some inducement I could provide that might have the desired effect? I would be happy to make a small monetary contribution, if you don’t consider that too sordid!

Richard.

Hello Richard,

I tried your test-case, thanks for providing it !

  1. first I got some noise, so I believe the “GL_COLOR_LOGIC_OP” should be
    done after the “SDL_RenderFillRect”…

  2. I can reproduce it on my android device :
    As you said, it appears that when using opengles2 it resumes correctly,
    but when using opengles it resumes as black.

  3. … Found out there was no need of the gl calls to produce the black
    screen on resume.

  4. This seems to happen when changing the renderer target, with a call to
    "SDL_SetRenderTarget".
    In the opengles leaf function (in
    "src/render/opengles/SDL_render_gles.c"), it appears there is a call to
    "GLES_ActivateRenderer" in “GLES_SetRenderTarget”, which is not present in
    opengles2.
    when commenting out this “GLES_ActivateRenderer”, it seems to resume fine.

Hope it helps …

Cheers,

SylvainOn 1 April 2016 at 14:03, rtrussell wrote:

Eric Wing wrote:

But there could be a multitude of other differences. NDK version, NDK
target API, SDK version, SDK api version, toolchain version, how you
and I built SDL (I used my CMake patch/fork) and against which
settings of theses, which compiler version/chain you used,
optimization levels, AndroidManifest settings and so forth.

Right. Now, if I could only persuade you to build my testcase using your
toolchain we could eliminate (or confirm) that possibility at a stroke! Is
there some inducement I could provide that might have the desired effect? I
would be happy to make a small monetary contribution, if you don’t consider
that too sordid!

Richard.


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


Sylvain Becker

slvn wrote:

Hope it helps …

This is marvellous, thank you so much. I will investigate all your suggestions.

Richard.

slvn wrote:

when commenting out this “GLES_ActivateRenderer”, it seems to resume fine.

Well, I’m flabbergasted! Making that change seems not only to have completely fixed the issue in my testcase, but in my main app as well! It’s such a non-obvious (to me) change too: I would never have expected the problem to be in SetRenderTarget (which has always appeared to work correctly), and the call to ActivateRenderer looks so ‘deliberate’ I’m surprised that it apparently works so well without it. Goodness knows how you managed to figure it out.

I can’t thank you enough.

Richard.

Sorry, I didn’t back to your thread sooner. But it sounds like it’s solved!On 4/1/16, rtrussell wrote:

slvn wrote:

when commenting out this “GLES_ActivateRenderer”, it seems to resume
fine.

Well, I’m flabbergasted! Making that change seems not only to have
completely fixed the issue in my testcase, but in my main app as well! It’s
such a non-obvious (to me) change too: I would never have expected the
problem to be in SetRenderTarget (which has always appeared to work
correctly), and the call to ActivateRenderer looks so ‘deliberate’ I’m
surprised that it apparently works so well without it. Goodness knows how
you managed to figure it out.

I can’t thank you enough.

Richard.

Eric Wing wrote:

it sounds like it’s solved!

The issue with my app seems to be fixed, but presumably before Sylvain’s modification can find its way into SDL 2.0.5 somebody needs to do a more detailed investigation to confirm that it has no unwanted side-effects. Do I need to report it formally as a bug, or submit a patch, to initiate that?

Richard.

Yes, you should file a formal bug and include a patch.On 4/1/16, rtrussell wrote:

Eric Wing wrote:

it sounds like it’s solved!

The issue with my app seems to be fixed, but presumably before Sylvain’s
modification can find its way into SDL 2.0.5 somebody needs to do a more
detailed investigation to confirm that it has no unwanted side-effects. Do
I need to report it formally as a bug, or submit a patch, to initiate that?

Richard.