- Online Community Forums » Programming Questions » What is the proper procedure for restoring bitmaps on Android?

This thread is locked; no one can reply to it. rss feed Print
What is the proper procedure for restoring bitmaps on Android?
Max Savenkov
Member #4,613
May 2004

Android is driving me crazy. First, blend modes didn't work and I had to write a shader to subtract two textures, and now bitmaps are getting corrupted after I suspend and resume my game.

So, what's happening:

When I resume my game after going to background (via pressing Home button), I get not one, but two ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING events.

If I recreate all bitmaps on both of them, all bitmaps with NO_PRESERVE_TEXTURE get corrupted very badly. For example, when I later draw a one-pixel line on such bitmap, it gets displayed as a wide band.

If I only react to the first event, everything gets corrupted (as it should be, probably)

If I only react to the second event (beyond calling al_acknowledge_drawing_resume), the picture is more correct, but there are still some problems with alpha channel.

Here's the code I use:

1// Game.cpp, main loop: 2 3case DisplayEvent::DISPLAY_RESUME_DRAWING: 4 al_acknowledge_drawing_resume( al_get_current_display() ); 5 render.SetGlobalScaling( SCALING_KEEP_ASPECT, SCREEN_W, SCREEN_H ); 6 GetBitmapManager().ReloadAllResources(); 7 m_forcedPause = false; 8 break; 9 10// Bitmap manager, a simplified code for ReloadAllResources(): 11void BitmapManager::ReloadAllResources() 12{ 13 const int oldFlags = al_get_new_bitmap_flags(); 14 15 for ( ResVector::iterator iter = m_resources.begin(); 16 iter != m_resources.end(); 17 ++iter ) 18 { 19 ALLEGRO_BITMAP *pOld = ((AllegroImage5*)iter->m_res)->GetBitmap(); 20 ALLEGRO_BTIMAP *pNew = 0; 21 int newFlags = al_get_bitmap_flags( pOld ); 22 al_set_new_bitmap_flags( newFlags ); 23 if ( IsResourceFromFile( iter ) ) 24 pNew = al_load_bitmap( iter->filename.c_str() ); 25 else if ( !(newFlags & ALLEGRO_NO_PRESERVE_TEXTURE )) 26 pNew = al_clone_bitmap( pOld ); 27 else 28 { 29 const int w = al_get_bitmap_width( pOld ); 30 const int h = al_get_bitmap_height( pOld ); 31 pNew = al_create_bitmap( w, h ); 32 } 33 34 al_destroy_bitmap( pOld ); 35 delete iter->m_res; 36 iter->m_res = new AllegroImage5( pNew ); 37 } 38 39 al_set_new_bitmap_flags( oldFlags ); 40}

So, what am I doing wrong? I've tried everything I could think of already.

Member #7,536
July 2006

I'm not really overly familiar with Allegro 5, let alone the Android port, but what stands out to me are oldFlags and newFlags. You extract the flags from the original bitmap, but you don't seem to apply them to the new bitmap. And the al_set_new_bitmap_flags doesn't appear to do anything since you just reassign the exact same flags that were already set. It's difficult to know though what Allegro does in the background with all this global state... I would have expected you to use al_set_new_bitmap_flags to temporary change the flags before creating the new bitmap and then restore the original setting at the end...

Max Savenkov
Member #4,613
May 2004

Ah, sorry, I forgot to copy that line :( Amended.

Edgar Reynaldo
Major Reynaldo
May 2007

Do you ever clear the new bitmaps? You create new bitmaps in the case of un-preserved textures and bitmaps not reloaded from a file. If you aren't drawing over the whole bitmaps then you could have uninitialized memory in them.

That's all I can really see as you re-load bitmaps that were from files and you clone bitmaps that don't have the NO_PRESERVE_TEXTURE flag set.

Are all your resources in m_resources bitmaps? Ie, are they all AllegroImage5 objects?

Max Savenkov
Member #4,613
May 2004

Yes, they are all stored in m_resources. I do not clear NO_PRESERVE_TEXTURE bitmaps, as they are usually drawn over completely on the next frame. It's still would be more proper to clear them, of course, than to rely on that, so I'll do that.

What bothers me more, is those ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING events... Why am I getting two of them, and why recreating bitmaps twice screws things up royally (compared to a common screw up that happens if I only recreated them once, during handling of the second event)? I can't find any relevant references to surfaceChanged being called twice in Google...

EDIT: I've done some digging, and it seems that I found the reason for some of my troubles. Based on attached log, I deduced the following sequence of events:

1) The game is paused, halt_drawing is acknowledged, the game goes to background
2) The game is resumed, a new Surface is created in response to onCreate, nativeOnCreate is called, resume_drawing event is posted to queue.
3) My code begins to react to resume_drawing event by re-creating bitmaps
4) SUDDENLY! In the middle of it all, a second onCreate is called in another thread! The current Surface is destroyed - but my code is in the middle of recreation of bitmaps, and has no notion that something has gone wrong. After this part, all bitmaps I try to re-create are corrupted, because they have no Surface to be created against.
5) The second resume_drawing event reaches my code. I begin to recreate bitmaps once again, but most of their data is already corrupted (?).

This explains why things looks the best when I only react to the second resume_drawing event. I couldn't discern why onCreate is called twice, but there are mentions of such behaviour here and there. It seems like it's normal behaviour on Android sometimes. So the question is, how to make Allegro handle it correctly? The main problem I see is that Surface is destroyed when my own code is in the middle of work with bitmaps. Is there any way to postpone destruction of the old Surface? I don't quite see what to do here...

Go to: