|
Delay on event queue while on thread |
Juanse
Member #21,477
October 2021
|
Hello everyone, hope you are doing good. This is my first post here so please tell me if I should do something different when posting questions. 1void * game_loop(void * arg)
2{
3 al_set_new_window_title("Just Dance! Game");
4 al_set_new_display_refresh_rate(fr);
5 al_set_new_display_flags(ALLEGRO_WINDOWED);
6 game = al_create_display(gw, gh);
7
8 if (game == nullptr)
9 {
10 perror("Error reservando display.\n");
11 exit(-1);
12 }
13
14 if (!al_show_mouse_cursor(game) || !al_set_system_mouse_cursor(game, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW))
15 {
16 perror("Error mostrando cursor.\n");
17 exit(-1);
18 }
19
20 queue = al_create_event_queue();
21 if (queue == nullptr)
22 {
23 perror("Error creando cola de eventos.\n");
24 exit(-1);
25 }
26
27 al_register_event_source(queue, al_get_keyboard_event_source());
28 al_register_event_source(queue, al_get_mouse_event_source());
29
30 al_clear_to_color(al_map_rgb(255, 255, 255));
31
32 al_flip_display();
33
34 al_wait_for_event(g.queue, &g.in_event);
35
36 pthread_exit(NULL);
37}
|
Chris Katko
Member #1,881
January 2002
|
1) IIRC. drawing has to be on the main thread no matter what. It's a D3D/OpenGL limitation. 2) is game_loop called once (and "has a loop inside it"), or called every frame? Because I don't see a loop, or, you're doing setup every single frame? e.g. you would usually never be calling "setup event source" and "clear to color" right next to each other. -----sig: |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Some things to keep in mind when working with Allegro 5 and threads. ALLEGRO_EVENT_QUEUEs are thread safe and protected by a mutex. Displays are NOT, and they have thread local storage (TLS). This means a display will act differently when running on a thread other than the one it was created on. You can still do this, but you need to bind the display to a single thread at a time. You can do this with http://docs.liballeg.org/graphics.html#al_set_target_backbuffer . My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Juanse
Member #21,477
October 2021
|
Thanks for answering quickly. Chris, I'm sorry but I don't really know what IIRC is. The only drawing functions I'm using on this thread are al_clear_to_color and al_draw_bitmap. This game_loop function is only called once and a loop would be running on it, yes, but I cut it out for testing this code, my idea was to see this delay on a single loop, so when I get a signal I exit the code. Edgar, I'm not working with displays on other threads, matter of fact I'm not even using allegro on the main thread, so I think this shouldn't be a problem right? I know that what I'm doing might be confusing, but basically this is for a college project, which didn't need to be a game but I chose to, and I was required to work with another graphic interface. This interface was very limiting so I decided to do a "mash-up" with allegro, which I was already familiar with. This is why I run sort of a complete allegro code inside a thread, and I hoped it would work. If the problem is the fact that I'm using allegro on a thread then I'm kinda screwed. |
DanielH
Member #934
January 2001
|
IIRC - If I Recall Correctly Can you include loop code? Maybe your initialization also. |
Juanse
Member #21,477
October 2021
|
Yeah sure. For context, Element is a class with a bitmap and not much else. The Element.draw function is at the bottom. Background inherits from Element. 1void * game_loop(void * arg)
2{
3 Element mA1("media/mA1.png");
4 Element mA2("media/mA3.png");
5 Element mA3("media/mA5.png");
6 Element mA4("media/mA7.png");
7
8 al_set_new_window_title("Just Dance! Game");
9 al_set_new_display_refresh_rate(fr);
10 al_set_new_display_flags(ALLEGRO_WINDOWED);
11 ALLEGRO_DISPLAY *game = al_create_display(gw, gh);
12
13 if (game == nullptr)
14 {
15 perror("Error reservando display.\n");
16 exit(-1);
17 }
18
19 if (!al_show_mouse_cursor(game) || !al_set_system_mouse_cursor(game, ALLEGRO_SYSTEM_MOUSE_CURSOR_ARROW))
20 {
21 perror("Error mostrando cursor.\n");
22 exit(-1);
23 }
24
25 ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
26 if (queue == nullptr)
27 {
28 perror("Error creando cola de eventos.\n");
29 exit(-1);
30 }
31
32 al_register_event_source(queue, al_get_keyboard_event_source());
33 al_register_event_source(queue, al_get_mouse_event_source());
34
35 Element *elements = (Element *)malloc(sizeof(Element) * 4);
36
37 *elements = mA1;
38 *(elements + 1) = mA2;
39 *(elements + 2) = mA3;
40 *(elements + 3) = mA4;
41
42 Background *background = new Background("media/background.png");
43
44 bool flag = true;
45
46 do
47 {
48 al_clear_to_color(al_map_rgb(255, 255, 255));
49
50 background->draw(0, 0);
51
52 elements[0].draw(gh * 3 / 5, gh * 7 / 16, gh / 8, gh / 8);
53 elements[1].draw(gh * 7 / 16, gh * 3 / 5, gh / 8, gh / 8);
54 elements[2].draw(gh * 11 / 40, gh * 7 / 16, gh / 8, gh / 8);
55 elements[3].draw(gh * 7 / 16, gh * 11 / 40, gh / 8, gh / 8);
56
57 al_flip_display();
58
59 al_wait_for_event(queue, in_event);
60
61 switch (g.in_event.type)
62 {
63 case ALLEGRO_KEY_DOWN:
64 switch (g.in_event.keyboard.keycode)
65 {
66 case ALLEGRO_KEY_ESCAPE:
67 flag = false;
68 break;
69 }
70 break;
71 }
72
73 } while(flag);
74
75 pthread_exit(NULL);
76}
77
78void Element::draw (int x, int y) const
79{
80 al_draw_bitmap(image, x, y, 0);
81}
82
83void Element::draw (int x, int y, int win, int hin) const
84{
85 al_draw_scaled_bitmap(image, 0, 0, w, h, x, y, win, hin, 0);
86}
|
Edgar Reynaldo
Major Reynaldo
May 2007
|
In the first code example, you're waiting on the wrong event queue. In the second code example, flag will always be true and the loop will never quit. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Juanse
Member #21,477
October 2021
|
You are right, my bad. Let me clarify, I made the mistake while copying my code to the response, when compiling I got these things right. g.queue in the first example is the same as queue, I just cut off a Game class I made for simplicity's sake. On the second one I totally forgot the switch for the events, I'm adding it as an edit. If you think it may be part of the problem, I can write iteration of the code where I don't use classes so that everything is inside this game_loop function. |
DanielH
Member #934
January 2001
|
This is the issue with only seeing part of the process. From what I see, you are only processing one event per loop iteration. That in itself will slow down your program. How many events took place before you clicked the mouse? If you get any event, process all events until queue is empty before continuing loop. Also, I'm not an expert, but I believe that bitmaps should be loaded after display is created. This was to ensure they have the same format. If not, this can slow down a bit. Not quite sure on that one though. Please correct me if I'm wrong. ------------------- In your code, you create 4 static Elements. Element mA1("media/mA1.png"); Element mA2("media/mA3.png"); Element mA3("media/mA5.png"); Element mA4("media/mA7.png"); Later you copied them to 4 dynamic Elements? *elements = mA1; *(elements + 1) = mA2; *(elements + 2) = mA3; *(elements + 3) = mA4; Why copies? |
Juanse
Member #21,477
October 2021
|
Ok, thanks for the suggestion, next time I'm going to read the whole event queue before exiting the loop. However, I don't think that's the problem here, since what I'm doing is just opening the program and pressing escape once, so I should be getting just one event, and there's consistently a three second delay from when I press escape to when the program actually acknowledges it. The drawing is almost instant, the events are the problem. Also the bitmap thing shouldn't be the problem, I have run the program declaring the elements after creating the display and it was the same thing. About the dynamic/static elements... I've modified the program so many times to figure out what's going on that I don't even know what's the point of that declaration. I'm polishing everything when I get the event "engine"(?) running. By the way, when I run this program as a standalone, meaning I don't use threads, it works perfectly, so I'm 99% sure the problem is using events with threads. I just don't know if there's a solution to that, and I don't really have a workaround to using threads . Either way I'm really thankful for you guys helping me. Edit: I've used the words program and problem like a million times at this point, I'm not a native speaker, sorry. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
If the code is not too large, just put it in a zip file and we can look at it much faster. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Juanse
Member #21,477
October 2021
|
Yeah, sure. The program is compiled with QT creator, hopefully you are familiar with it, if not ask me anything you need. For the program to run correctly, you need to paste the media folder inside the QT build folder for the project. The game_loop function is inside game.cpp. The .zip is attached here. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I believe the delay is coming from extranneous events. In your game_loop function, you draw g once for every event. If there are a lot of mouse events it could be stuck drawing for several seconds. Always drain the event queue by processing all events. do { al_wait_for_event(g.queue , g.in_event); if (g.in_event.type == ALLEGRO_EVENT_KEYBOARD && g.in_event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) { break; } } while (!al_is_event_queue_empty(g.queue));
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Juanse
Member #21,477
October 2021
|
Ok, I'm going to try that and update, thank you. |
Chris Katko
Member #1,881
January 2002
|
I feel like an Allegro function called "how many events are left" (is there one)? that we could just have newbies post the results of, would identify 95% of these delay cases. And an assert in debug mode when the queue hits 1000 events stored because you'd never do that in 99.9999% of games. -----sig: |
torhu
Member #2,727
September 2002
|
That could make sense, but I suppose it would require keeping track of the count to avoid traversing the linked list of events every time the function is called, etc. Or if someone stores the number, unaware that it it's changed by a background thread, etc... Maybe just a log message in debug mode when the event count passes 100, 1000, etc. would be helpeful? |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Let the newbies learn the hard way Tough love, babe My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Juanse
Member #21,477
October 2021
|
Again, sorry for the late reply, I'm having a though month with college. I changed the game loop code to this one, and now the allegro window completely freezes, it doesn't respond to the escape key. 1void * game_loop(void * arg)
2{
3 Allegro al;
4 Game g;
5
6 bool flag = true;
7
8 do
9 {
10 g.draw();
11 do
12 {
13 al_wait_for_event(g.queue, &g.in_event);
14 switch (g.in_event.type)
15 {
16 case ALLEGRO_KEY_DOWN:
17 switch (g.in_event.keyboard.keycode) {
18 case ALLEGRO_KEY_ESCAPE:
19 flag = false;
20 break;
21 }
22 break;
23 }
24 } while (!al_is_event_queue_empty(g.queue));
25 } while(flag);
26
27 emit ((menu *)arg)->game_ended();
28
29 sleep(1);
30
31 pthread_exit(NULL);
32}
|
Izual
Member #2,756
September 2002
|
There is a mistake in your code. Change ALLEGRO_KEY_DOWN to ALLEGRO_EVENT_KEY_DOWN. See event system and key codes for reference. Edit: Added some links to documentation.
|
Juanse
Member #21,477
October 2021
|
Yeah you are right, sorry about that. I changed that and the program doesn't freeze anymore, but the delay is still present. Basically, the problem isn't that the queue is filled with events. |
DanielH
Member #934
January 2001
|
You could add this 1void * game_loop(void * arg)
2{
3 Allegro al;
4 Game g;
5
6 bool flag = true;
7
8 do
9 {
10 g.draw();
11 do
12 {
13 al_wait_for_event(g.queue, &g.in_event);
14 switch (g.in_event.type)
15 {
16 case ALLEGRO_KEY_DOWN:
17 switch (g.in_event.keyboard.keycode) {
18 case ALLEGRO_KEY_ESCAPE:
19 flag = false;
20 break;
21 }
22 break;
23 }
24
25 /**************************************/
26 if (flag) al_flush_event_queue(g.queue);
27 /**************************************/
28
29 } while (!al_is_event_queue_empty(g.queue));
30 } while(flag);
31
32 emit ((menu *)arg)->game_ended();
33
34 sleep(1);
35
36 pthread_exit(NULL);
37}
|
Juanse
Member #21,477
October 2021
|
Same outcome |
DanielH
Member #934
January 2001
|
What are you doing in the other thread? Are you using a lot of cycles? How about resting a bit. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Try littering your code with al_get_time calls. See how much time each portion of code is taking. That's the only way to find your delay. I notice in your thread that you initialize allegro, create a game, and create a background that is cloned. That all takes at least some time. The delay may not be in the event queue at all. A word of warning - globals are not good programming. You can use the data pointer in your thread process to pass anything you want into the thread. EDIT My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
|