Funky Lost/Found - Inc Code Sample
fallenlight12

Ok so to make a long story short I narrowed down the problem I've been having with the lost and found event to something that's easily built and executed by anybody.

To test it:
Tab-out and back repeatedly until it fails to re-enter correctly. On my computer, it eventually (and simply) does not re-enter after tabbing out. To kill the application I press escape.

You may have to tab out and in a couple dozen times. Or not. It's random.

Now I did figure out which line is causing the trouble. It appears to be:

#SelectExpand
1 if (redraw && !skip_redraw) { 2 --> al_set_target_bitmap(pbitmap);

So it seems if I target the pbitmap in the render function the reset fails sometimes.

Try it yourself. This is just what happens on my system.

Again, the problem is the reset fails.

I'm using Allegro 5.1.4 on Windows Xp Sp3.

Here's the code:

#SelectExpand
1#include <stdio.h> 2#include <allegro5/allegro.h> 3 4ALLEGRO_DISPLAY *display; 5 6namespace g 7{ 8 float f_fps = 1590; 9} 10 11int main(int argc, char **argv) 12{ 13 ALLEGRO_EVENT_QUEUE *queue = NULL; 14 ALLEGRO_TIMER *timer = NULL; 15 16 if (!al_init()) 17 { 18 fprintf(stdout,"Could not init Allegro.\n"); 19 return -1; 20 } 21 22 al_install_keyboard(); 23 24 al_set_new_display_flags(ALLEGRO_FULLSCREEN); 25 display = al_create_display(800, 600); 26 if (!display) 27 { 28 fprintf(stdout,"Could not create display.\n"); 29 al_rest(4.0); 30 return -1; 31 } 32 33 //al_add_new_bitmap_flag(ALLEGRO_NO_PRESERVE_TEXTURE); 34 35 queue = al_create_event_queue(); 36 if(!queue) 37 { 38 fprintf(stdout,"Could not create queue.\n"); 39 al_destroy_display(display); 40 al_rest(4.0); 41 return -1; 42 } 43 44 timer = al_create_timer(1.0 / g::f_fps); 45 al_register_event_source(queue, al_get_keyboard_event_source()); 46 al_register_event_source(queue, al_get_display_event_source(display)); 47 al_register_event_source(queue, al_get_timer_event_source(timer)); 48 49 ALLEGRO_BITMAP * pbmfront = al_get_backbuffer(display); 50 ALLEGRO_BITMAP *pbitmap = ::al_create_bitmap(200,200); 51 if(!pbitmap) { 52 al_destroy_display(display); 53 al_destroy_timer(timer); 54 al_destroy_event_queue(queue); 55 fprintf(stdout,"Failed to load image.\n"); 56 al_rest(4.0); 57 return -1; 58 } 59 60 al_set_target_bitmap(pbitmap); 61 ::al_clear_to_color(al_map_rgb(0,100,0)); 62 al_set_target_bitmap(pbmfront); 63 64 bool redraw = true; 65 bool quit = false; 66 bool skip_redraw = false; 67 68 al_start_timer(timer); 69 70 do { 71 72 if (redraw && !skip_redraw) { 73 al_set_target_bitmap(pbitmap); 74 al_set_target_bitmap(pbmfront); 75 al_clear_to_color(::al_map_rgb(100,0,0)); 76 ::al_draw_bitmap(pbitmap, 0, 0, 0); 77 al_flip_display(); 78 } 79 80 do { 81 ALLEGRO_EVENT ev; 82 al_wait_for_event(queue , &ev); 83 84 if (ev.type == ALLEGRO_EVENT_DISPLAY_LOST) { 85 printf("Display Lost\n"); 86 skip_redraw = true; 87 } 88 else if (ev.type == ALLEGRO_EVENT_DISPLAY_FOUND) { 89 printf("Display Found\n"); 90 skip_redraw = false; 91 } 92 else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN) { 93 printf("Display Switch In\n"); 94 } 95 else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) { 96 printf("Display Switch Out\n"); 97 skip_redraw = true; 98 } 99 else if (ev.type == ALLEGRO_EVENT_TIMER) { 100 redraw = true; 101 } 102 else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 103 printf("User clicked on close.\n"); 104 quit = true; 105 break; 106 } 107 else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { 108 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { 109 quit = true; 110 break; 111 } 112 } 113 } while (!al_is_event_queue_empty(queue)); 114 } while (!quit); 115 116 al_destroy_bitmap(pbitmap); 117 al_destroy_display(display); 118 al_destroy_timer(timer); 119 al_destroy_event_queue(queue); 120 121 al_rest(1.0); 122 123 return 0; 124}

Trent Gamblin

Try this:

#SelectExpand
1#include <stdio.h> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_direct3d.h> 4 5bool halt_main_thread = false; 6bool resume_main_thread = false; 7 8void release_callback() 9{ 10 halt_main_thread = true; 11 while (halt_main_thread) { 12 al_rest(0.001); 13 } 14} 15 16void restore_callback() 17{ 18 resume_main_thread = true; 19 while (resume_main_thread) { 20 al_rest(0.001); 21 } 22} 23 24ALLEGRO_DISPLAY *display; 25 26namespace g 27{ 28 float f_fps = 1590; 29} 30 31int main(int argc, char **argv) 32{ 33 ALLEGRO_EVENT_QUEUE *queue = NULL; 34 ALLEGRO_TIMER *timer = NULL; 35 36 if (!al_init()) 37 { 38 fprintf(stdout,"Could not init Allegro.\n"); 39 return -1; 40 } 41 42 al_install_keyboard(); 43 44 al_set_new_display_flags(ALLEGRO_FULLSCREEN); 45 display = al_create_display(800, 600); 46 if (!display) 47 { 48 fprintf(stdout,"Could not create display.\n"); 49 al_rest(4.0); 50 return -1; 51 } 52 53 al_d3d_set_release_callback(release_callback); 54 al_d3d_set_restore_callback(restore_callback); 55 56 //al_add_new_bitmap_flag(ALLEGRO_NO_PRESERVE_TEXTURE); 57 58 queue = al_create_event_queue(); 59 if(!queue) 60 { 61 fprintf(stdout,"Could not create queue.\n"); 62 al_destroy_display(display); 63 al_rest(4.0); 64 return -1; 65 } 66 67 timer = al_create_timer(1.0 / g::f_fps); 68 al_register_event_source(queue, al_get_keyboard_event_source()); 69 al_register_event_source(queue, al_get_display_event_source(display)); 70 al_register_event_source(queue, al_get_timer_event_source(timer)); 71 72 ALLEGRO_BITMAP * pbmfront = al_get_backbuffer(display); 73 ALLEGRO_BITMAP *pbitmap = ::al_create_bitmap(200,200); 74 if(!pbitmap) { 75 al_destroy_display(display); 76 al_destroy_timer(timer); 77 al_destroy_event_queue(queue); 78 fprintf(stdout,"Failed to load image.\n"); 79 al_rest(4.0); 80 return -1; 81 } 82 83 al_set_target_bitmap(pbitmap); 84 ::al_clear_to_color(al_map_rgb(0,100,0)); 85 al_set_target_bitmap(pbmfront); 86 87 bool redraw = true; 88 bool quit = false; 89 bool skip_redraw = false; 90 91 al_start_timer(timer); 92 93 do { 94 95 if (redraw && !skip_redraw) { 96 al_set_target_bitmap(pbitmap); 97 al_set_target_bitmap(pbmfront); 98 al_clear_to_color(::al_map_rgb(100,0,0)); 99 ::al_draw_bitmap(pbitmap, 0, 0, 0); 100 al_flip_display(); 101 } 102 103 do { 104 ALLEGRO_EVENT ev; 105 al_wait_for_event(queue , &ev); 106 107 if (ev.type == ALLEGRO_EVENT_DISPLAY_LOST) { 108 printf("Display Lost\n"); 109 skip_redraw = true; 110 } 111 else if (ev.type == ALLEGRO_EVENT_DISPLAY_FOUND) { 112 printf("Display Found\n"); 113 skip_redraw = false; 114 } 115 else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_IN) { 116 printf("Display Switch In\n"); 117 } 118 else if (ev.type == ALLEGRO_EVENT_DISPLAY_SWITCH_OUT) { 119 printf("Display Switch Out\n"); 120 skip_redraw = true; 121 } 122 else if (ev.type == ALLEGRO_EVENT_TIMER) { 123 redraw = true; 124 } 125 else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { 126 printf("User clicked on close.\n"); 127 quit = true; 128 break; 129 } 130 else if (ev.type == ALLEGRO_EVENT_KEY_DOWN) { 131 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { 132 quit = true; 133 break; 134 } 135 } 136 } while (!al_is_event_queue_empty(queue)); 137 138 if (halt_main_thread) { 139 halt_main_thread = false; 140 while (!resume_main_thread) { 141 al_rest(0.001); 142 } 143 resume_main_thread = false; 144 } 145 146 } while (!quit); 147 148 al_destroy_bitmap(pbitmap); 149 al_destroy_display(display); 150 al_destroy_timer(timer); 151 al_destroy_event_queue(queue); 152 153 al_rest(1.0); 154 155 return 0; 156}

fallenlight12

Well when I tried your code as-is it didn't get rid of the problem.

However, enabling NO_PRESERVE and just destroying and recreating did.

Now...

In my main application I have made some progress.

I found out that the problem is occurring in the destroying process that happens immediately after the lost event. Somehow an al_destroy_bitmap() call is failing. This is of course later causing reset to fail.

Right now, I'm using ::al_is_d3d_device_lost() to test if the device is lost in different places. I've figured out that those cases where the device is unable to reset correctly happen when the device is lost INSIDE the display routine (bundles all of the rendering for the application). So even if I skip the display routine if the device is lost (which I am currently doing), it can still happen inside. And somehow that's causing this problem.

Basically, it looks like even if I use the code that you supplied - that uses callback routines - I'll still have this problem. I have to dig deeper to find out exactly where it's happening and if I can do a test when I'm destroying.

I may have said something wrong, but this is the gist of it. The display is lost inside where I use allegro display routines and somehow it's choking something that prevents me from destroying a bitmap.

Trent Gamblin

I've said it about 8 times now and this is the last. You can't do anything with d3d after returning from the release callback until returning from the restore callback. NOTHING. al_is_d3d_device_lost takes a snapshot of the flag at a given point but it can change in the middle of your function. The ONLY way to do it right is as I said above, and on top of that set a flag that says DON'T TOUCH D3D in the callback. This assumes your program is single threaded, in a multi threaded program it's slightly more complicated.

fallenlight12

Trent I haven't used the callbacks yet in the main app. I did test them in the skeleton app briefly.

But I will put them in the main app now.

Sorry bro if I touched feathers. Look, I've had a lot of troubles with this code and this has been a rough ride. I've not enjoyed myself. Please don't get too mad.

I love the help. I know I might be a tough student, but I'm trying.

Trent Gamblin

Ok ok, I got a little impatient. No worries.

fallenlight12

I'm using the callbacks now in the same way as your sample code.

But here's the problem... hail_main_thread is only true when I re-enter the application. Am I doing something wrong? What's happening is the device is getting lost before I get the lost event. And halt_main_thread is not true so the release_callback() isn't being called yet. So how am I supposed to prevent allegro functions from being used when the device is lost before it reaches the allegro message pump?

Well I'm just at a loss. Don't understand.

I'm trying to use al_is_d3d_device_lost() but it's not preventing it. I do use it to skip the main routine for the display, but somehow after that it fubbers. When I put it inside it oddly is somehow not recognized until the display flips.

As in:

#SelectExpand
1 if(b_redraw && !b_skipredraw) { 2 b_redraw = false; 3 if(!::al_is_d3d_device_lost(pdisplay)) { 4 fps_count++; 5 6 if(!Gui._Display(shp::crect(0,0,screenx,screeny))) { 7 dbg::LOG("...(Main Thread) display event caused error, exiting main loop.\n", true); 8 break; 9 } 10 if(::al_is_d3d_device_lost(pdisplay)) { 11 dbg::LOG("...(Main Thread) Device is lost inside display routines.\n"); 12 } 13 } 14 }

Can lock this thread. If I need anymore help and Trend has ignored me or something then I'll ask him. I've made too many threads already. This is going on and on and on. I'll shutup. Thanks.

Just.... this has been one of the worst time I've had programming. I've been programming for a long time. I'm 35 and so it has been more than 15 years off and on. And I'm just baffled at this. Maybe I need to learn more about direct 3d. But I'm already hating direct3d. Anyway, whatever. Don't like hitting my head against the wall.

Trent Gamblin

I'm having a bit of a hard time understanding the problem. You're talking about al_d3d_device_is_lost and message pumps and events, and I swear I've said more than once that those are useless for what you're trying to do.

I'm here to help, I'm not going anywhere. Maybe an explanation of what is happening behind the scenes will help (you can look at the code yourself in src/win/d3d_disp.cpp):

1) Allegro receives device lost from d3d. It sends the LOST event which is mostly useless.
2) It waits for d3d to tell it to reset the device
3) It calls your release callback if you've set one
4) It releases all bitmaps including ones with NO_PRESERVE (I may have told you different before)
5) It then resets the device
6) It recreates ALL textures but only restores the content of ones without NO_PRESERVE
7) It emits the FOUND event
8) it then calls your restore callback if you've set one

So with that said, do you have an example that doesn't work that I can test? The one you posted here worked at least enough that I couldn't get it to fail, so something that's more reproducible would be good but if that's all you've got...

And I apologize if I gave you any wrong information before... I want to fix this though so stick with it :P.

fallenlight12

Well first off the sample I posted in the OP fails on my machine about once every ~10 times. When I press alt-tab to re-enter it fails. I can still see the console window except it doesn't have focus. I press escape to exit.

As I said, the line that causes it to fail is the line that targets pbitmap. That's the line that will get executed first after the display is found and the timer sets b_redraw to true. If I remove that line, I get no failures.

The sample you posted in your first reply didn't get rid of it. The only change your sample adds is that when it fails to re-enter it goes into a hard loop and won't respond to me pressing ESC.

I'm using WinXP Sp3 with Direct 9.0c and the Allegro 5.1.4 binaries here:
https://www.allegro.cc/forums/thread/611248/969351#target

I'm using Microsoft Visual C++ 2010 Express to build the project. And no I'm not running any other code alongside the sample I gave in the OP. I just use a #ifdef...#endif in main.cpp to run the sample exclusively.

Peter Wang

Again, I fixed a number of issues with d3d lost devices in 5.1.5. Please test using that version or git.

edit: I tested your program with the current git version of Allegro (should be the same as 5.1.5 in this respect). No problems alt-tabbing in and out about 30 times or so.

fallenlight12

Peter, have you tested on older versions? I'm just wondering if this is an allegro ~5.1.4 problem or it's a problem on my system (hardware/software). Right now I am in a fog and just don't know.

Where can I get 5.1.5? Rather, how long will it be before a binary is released? I tried building sources a month ago but was only partially successful. Right now, I just wait until the binaries are availabe and use those. I do have the allegro source to look at, though.

Peter Wang

I didn't test 5.1.4 because I'd just be hitting the same bugs that I fixed in 5.1.5. I'm attaching the executed I tested with yesterday if you want to see if its fixed for you.

Milan might pop up with 5.1.5 binaries some time, or not. The only hard part about building Allegro is getting the dependencies, and Milan provided them here.

Thread #611924. Printed from Allegro.cc