Inconsistent bitmap restoration

I'm assuming this is related to the information provided in the description of ALLEGRO_EVENT_DISPLAY_LOST. I'm using Direct3D on Windows 8.1, with Allegro 5.2.2.

After locking the computer or having the screensaver appear, sometimes bitmaps are replaced by black boxes. Sometimes they aren't. I assume they're getting lost and Allegro is unable to restore them. However, sometimes they'll reappear on their own after locking and unlocking the computer a number of times, or by having the screensaver appear/disappear again. Toggling fullscreen with al_toggle_display_flag almost always seems to restore them as well.

Why is this? Why does it have trouble restoring them sometimes, only to successfully restore them later? If toggling fullscreen somehow restores them, is there something I can do to make it so however it's restoring always occurs?

If this inconsistency is normal, what's the best approach here? The bitmaps are loaded from the file system with default flags. Do I need to free them, then load them from the file system again? If they still exist in memory somewhere (since they're restored sometimes, they must be), this seems like an inefficient approach.


The intention for it is to be consistent, but it appears that there might be some issue. It will be helpful if you turn on logging and see if the logs differ between when the bitmaps succeed in being restored, and when they fail. You can turn on logging by adding this line before al_init():

al_set_config_value(al_get_system_config(), "trace", "level", "debug");

That will produce an allegro.log file in the working directory of your program.

In terms of workarounds, we have this function al_set_d3d_device_restore_callback in which you can in principle reload all your bitmaps. It might be useful to pass it a callback and see if it's called reliably as well.

Lastly... while we have all sorts of checks against it, try ceasing your drawing code when you receive the ALLEGRO_EVENT_DISPLAY_LOST event (and resume drawing when you get the ALLEGRO_EVENT_DISPLAY_FOUND event) and see if that helps.


Thanks a lot for the reply! Here's what I've discovered:

After enabling logging, I generated two logs. For each log, I locked the computer once, then unlocked it. I've included what I believe to be the important portion of each one.

Here's what happens when it successfully restores the bitmap:

1dtor D dtor.c:196 _al_register_destructor [ 0.06058] added dtor for bitmap 00868AD8, func 514F4953 2d3d D d3d_bmp.cpp:539 _al_d3d_sync_bitmap [ 0.10467] _al_d3d_sync_bitmap (system) ref count == 1 3d3d D d3d_bmp.cpp:545 _al_d3d_sync_bitmap [ 0.10478] _al_d3d_sync_bitmap (video) ref count == 1 4d3d D d3d_disp.cpp:1489 d3d_display_thread_proc [ 1.21542] D3DERR_DEVICELOST: d3d_display=007AE8A0 5d3d E d3d_disp.cpp:2754 d3d_flush_vertex_cache [ 2.40279] d3d_flush_vertex_cache: DrawPrimitive failed. 6d3d I d3d_disp.cpp:901 d3d_destroy_display [ 4.79158] destroying display 007AE8A0 (current 00000000) 7bitmap D bitmap_type.c:308 _al_convert_to_memory_bitmap [ 4.79572] converting display bitmap 00868AD8 to memory bitmap 8dtor D dtor.c:196 _al_register_destructor [ 4.79577] added dtor for bitmap 03D5D5A0, func 514F4953 9d3d D d3d_bmp.cpp:539 _al_d3d_sync_bitmap [ 4.79580] _al_d3d_sync_bitmap (system) ref count == 1 10d3d D d3d_bmp.cpp:545 _al_d3d_sync_bitmap [ 4.79581] _al_d3d_sync_bitmap (video) ref count == 1 11dtor D dtor.c:227 _al_unregister_destructor [ 4.79673] removed dtor for bitmap 03D5D5A0 12d3d D d3d_disp.cpp:885 d3d_destroy_display_internals [ 4.79682] waiting for display 007AE8A0's thread to end 13d3d W d3d_disp.cpp:595 d3d_destroy_device [ 4.80140] d3d_destroy_device: ref count not 0 14d3d I d3d_disp.cpp:1549 d3d_display_thread_proc [ 4.80527] d3d display thread exits 15dtor D dtor.c:227 _al_unregister_destructor [ 4.80667] removed dtor for queue 00864DE0 16dtor D dtor.c:116 _al_run_destructors [ 4.80671] calling dtor for bitmap 00868AD8, func 514F4953 17dtor D dtor.c:227 _al_unregister_destructor [ 4.80672] removed dtor for bitmap 00868AD8 18dtor D dtor.c:116 _al_run_destructors [ 4.80676] calling dtor for timer 007BAB98, func 514F272A 19dtor D dtor.c:227 _al_unregister_destructor [ 4.80677] removed dtor for timer 007BAB98

Here's what happens when it doesn't:

1dtor D dtor.c:196 _al_register_destructor [ 0.06982] added dtor for bitmap 00BC8C38, func 514F4953 2d3d D d3d_bmp.cpp:539 _al_d3d_sync_bitmap [ 0.11221] _al_d3d_sync_bitmap (system) ref count == 1 3d3d D d3d_bmp.cpp:545 _al_d3d_sync_bitmap [ 0.11236] _al_d3d_sync_bitmap (video) ref count == 1 4d3d D d3d_disp.cpp:1489 d3d_display_thread_proc [ 1.09119] D3DERR_DEVICELOST: d3d_display=00B0E8A0

It seems the device is lost, and then... Nothing.

Here's one more log where it failed to restore the bitmap after the first lock/unlock, but successfully restored it after the third lock/unlock:

1dtor D dtor.c:196 _al_register_destructor [ 0.04357] added dtor for bitmap 00D38638, func 575A4953 2d3d D d3d_bmp.cpp:539 _al_d3d_sync_bitmap [ 0.08589] _al_d3d_sync_bitmap (system) ref count == 1 3d3d D d3d_bmp.cpp:545 _al_d3d_sync_bitmap [ 0.08600] _al_d3d_sync_bitmap (video) ref count == 1 4d3d D d3d_disp.cpp:1489 d3d_display_thread_proc [ 0.86039] D3DERR_DEVICELOST: d3d_display=00C7AD38 5d3d D d3d_disp.cpp:1489 d3d_display_thread_proc [ 2.77492] D3DERR_DEVICELOST: d3d_display=00C7AD38 6d3d D d3d_disp.cpp:1489 d3d_display_thread_proc [ 4.76360] D3DERR_DEVICELOST: d3d_display=00C7AD38 7d3d E d3d_disp.cpp:2754 d3d_flush_vertex_cache [ 5.78573] d3d_flush_vertex_cache: DrawPrimitive failed.

I added the callback as you suggested, and when the bitmap is restored successfully, it gets called twice. When it is not restored, it only gets called once.

Finally, I tried suspending the drawing until the display is found as you suggested (by setting a flag to false when ALLEGRO_EVENT_DISPLAY_LOST shows up, and to true when ALLEGRO_EVENT_DISPLAY_FOUND, and only drawing when it's true). The same issue came up.

If you want to see the code, let me know and I'll post it. In case it's relevant, I'm using Visual Studio 2015 with the Allegro nuget package.


That's very interesting, thanks. I'll take a look at this soon as I've been looking into this system recently.

EDIT: Still working on it, no luck so far.


Were you able to reproduce it, at least? If there's any other useful information I can provide, please let me know.


I may need to get your source after all. I fixed one device loss issue, but it doesn't look like yours. In particular, I'm trying to get these lines to happen for me:

d3d D d3d_bmp.cpp:539 _al_d3d_sync_bitmap [ 0.10467] _al_d3d_sync_bitmap (system) ref count == 1

. I saw those before, but I can't seem to get them again.


Sorry for delayed response! Here's the code:

1#include <allegro5/allegro.h> 2#include <allegro5/allegro_image.h> 3#include <allegro5/allegro_direct3d.h> 4#include <iostream> 5 6void callback(ALLEGRO_DISPLAY* display) { 7 8 std::cout << "Called!\n"; 9 10} 11 12int main(int argc, char* argv[]) { 13 14 // Enable logging. 15 al_set_config_value(al_get_system_config(), "trace", "level", "debug"); 16 17 // Initialize Allegro. 18 al_init(); 19 al_init_image_addon(); 20 21 // Set callback. 22 //al_set_d3d_device_restore_callback(callback); 23 24 // Create resources. 25 ALLEGRO_DISPLAY* display = al_create_display(640, 480); 26 ALLEGRO_EVENT_QUEUE* event_queue = al_create_event_queue(); 27 ALLEGRO_TIMER* timer = al_create_timer(1.0 / 60.0); 28 ALLEGRO_BITMAP* bitmap = al_load_bitmap("allegro_logo.png"); 29 30 // Register event sources. 31 al_register_event_source(event_queue, al_get_display_event_source(display)); 32 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 33 34 // Run main loop. 35 bool loop = true; 36 bool redraw = true; 37 bool allow_redraw = true; 38 al_start_timer(timer); 39 40 while (loop) { 41 42 ALLEGRO_EVENT ev; 43 al_wait_for_event(event_queue, &ev); 44 45 switch (ev.type) { 46 47 case ALLEGRO_EVENT_TIMER: 48 redraw = true; 49 break; 50 51 case ALLEGRO_EVENT_DISPLAY_CLOSE: 52 loop = false; 53 break; 54 55 case ALLEGRO_EVENT_DISPLAY_LOST: 56 allow_redraw = false; 57 break; 58 59 case ALLEGRO_EVENT_DISPLAY_FOUND: 60 allow_redraw = true; 61 break; 62 63 } 64 65 if (redraw && allow_redraw && al_is_event_queue_empty(event_queue)) { 66 67 // Redraw. 68 redraw = false; 69 al_clear_to_color(al_map_rgb(255, 255, 255)); 70 al_draw_bitmap(bitmap, 100, 100, NULL); 71 al_flip_display(); 72 73 } 74 75 } 76 77 // Free resources. 78 al_destroy_display(display); 79 al_destroy_event_queue(event_queue); 80 81 return 0; 82}

And some extra information, in case it might be helpful:

- I'm using C++ (obviously) rather than plain C, if that makes a difference.
- Compiled for x86 in Debug mode with Visual Studio 2015 on Windows 8.1 64-bit.
- I tested it out on another computer to see if the logs differed; they were the same.

"allegro_logo.png" is this image.


I tried your code, but I just can't get it to reproduce your issue. I think the best I can do at this point is describe how I'd approach fixing this if I could:

1. First, I'd turn on the debug runtime for DirectX using the DirectX Control Panel (not sure where I got it), it'll look like this:


2. Running your program in the debugger in MSVC will now print various logs, that may be useful.

3. Stepping through Allegro's code is essential. The Nuget package comes with debug symbols, you're just going to need to download Allegro's source and point the debugger to it (see What to look at here will depend on what errors #1 returns.


I opened up the DirectX Control Panel, and all of the debugging options are greyed-out. After doing some research, I found that apparently the debug version isn't available in Windows 8.1 (or Windows 7 post-KB2370838). Support for old versions of DirectX was dropped. It seems like it's possible to get around this by modifying a registry key in Windows 7, but I'm out of luck on 8.1.

I'll probably set up a VM to do this, but I'm definitely not looking forward to installing everything... :'(


Maybe I can try doing this with Win10 in a VM as well (I have Win7 as my real Windows).


All right, I got everything set up. The following is shown in the debug output log when it fails to restore the bitmap after a lock/unlock:

Direct3D9: (ERROR) :Lost due to display uniqueness change
Direct3D9: :DoneExclusiveMode
Direct3D9: (INFO) :Using FF to VS converter

Direct3D9: (INFO) :Using FF to PS converter

Before (and after that), it's continuously spamming Ignoring redundant SetSamplerState, but I doubt that that's important.

I wanted to see if it wrote anything different when it managed to restore the bitmap successfully, but I can't get it to do so in the VM. It never restores the bitmap, and presents the same output with each lock/unlock.

I'm sorry to say I wasn't able to figure out how to get step 3 working. The page you linked said I can specify the source files under "Common Properties / Debug Source Files", but "Common Properties" doesn't exist in VS2015 Found it, I'm an idiot. I just need to specify the source directory, right ("allegro5-master\src")? I did that, but it's not letting me "Step Into" Allegro functions...

Do I need to worry about specifying .pdb files? When it asks for "allegro.pdb" I tried selecting "packages\Allegro.\build\native\v141\win32\lib\allegro-debug.pdb", but that's not what it's looking for.

Pardon my ignorance-- I want to help, but this is not a familiar process.


You want to link to Allegro's debug versions, which will automatically pick-up the pdb files.

EDIT: Actually, it's pretty great that you got it failing on a different Windows version. I've been trying this on my virtual Windows 10 to no avail.

Yes, that redundant sampler state thing is harmless... but is that really all the errors it shows? What does the log look like when it succeeds to restore things?

Thread #616961. Printed from