Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [A5] Need help with loading screens and multithreading

Credits go to kazzmir for helping out!
This thread is locked; no one can reply to it. rss feed Print
[A5] Need help with loading screens and multithreading
ryancoboy
Member #14,468
July 2012

Hello all, I have questions regarding multithreading. I’ve tried for quite a while now to get a loading screen set-up. I think I’m really close to getting it to work but I can’t figure out what’s going wrong.

My idea for how it should work conceptually is like so:

Make a thread that will:
sit idle till i need it
deletes the old map
loads the new one
changes the player's stats as needed (loacation, etc...)
repeat

while my main simply takes care of all the normal stuff: updating animations, drawing, input, etc...

My code mostly works. When my character enters a new area for the first time, the loading screen is displayed and the animation runs smoothly. When it’s done loading the new map is displayed but my game becomes extremely laggy and jumpy. My FPS counter stays at around 90, when I have it set to run at 60. When i attempt to move my character back through the door he came in the screen goes black and no animation is displayed. But the map does load and I can walk around but the game is still extremely laggy. When I attempt to go back through the door the loading screen shows, and plays smoothly.

I’ve tried a lot of different things but I cannot figure this one out. Here’s the thread related code I have currently:

NOTE: I am using mappy to handle all the map loading stuff.
NOTE: The lines of "......." in my code are simply areas of code that I deleted.

#SelectExpand
1................................................. 2 3void *Load(ALLEGRO_THREAD *thr, void *arg); 4 5int main(int argc, char **argv) 6{ 7 //============================================== 8 //SHELL VARIABLES 9 //============================================== 10 bool done = false; 11 bool render = false; 12 13 float gameTime = 0; 14 int frames = 0; 15 int gameFPS = 0; 16 17 //============================================== 18 //PROJECT VARIABLES 19 //============================================== 20 SystemState Temp_State; 21 22 SystemState Sys_State; 23 MapState Map_State; 24 25 StateMachine State(&Map_State, &Sys_State); 26 27 ................................................. 28 29 char MapName[] = "10000.fmp"; 30 31 //============================================== 32 //ALLEGRO VARIABLES 33 //============================================== 34 ALLEGRO_DISPLAY *display = NULL; 35 36 ................................................. 37 38 ALLEGRO_BITMAP *LoadingImage; 39 ALLEGRO_THREAD *Thread1; 40 41 //============================================== 42 //ALLEGRO INIT FUNCTIONS 43 //============================================== 44 if(!al_init()) //initialize Allegro 45 return -1; 46 47 display = al_create_display(WIDTH, HEIGHT); //create display object 48 49 if(!display) //test display object 50 return -1; 51 52 //============================================== 53 //ADDON INSTALL 54 //============================================== 55 ................................................. 56 57 58 //============================================== 59 //PROJECT INIT 60 //============================================== 61 ................................................. 62 63 if(MapLoad(MapName, 1)) 64 return -5; 65 66 Sys_State.Set_CurState(PLAYING); 67 Map_State.Set_MapState(EXPLORE); 68 69 LoadingImage = al_load_bitmap("Loading_Screen.png"); 70 71 ................................................. 72 73 //============================================== 74 //LOADING SCREEN INIT 75 //============================================== 76 Loading_bg Load_BG(LoadingInit(LoadingImage)); 77 78 //============================================== 79 //Thread data INIT 80 //============================================== 81 ThreadInfo Info(&State, &Character); 82 83 //============================================== 84 //TIMER INIT AND STARTUP 85 //============================================== 86 ................................................. 87 timer = al_create_timer(1.0 / 60); 88 89 ................................................. 90 91 Thread1 = al_create_thread(Load, &Info); 92 al_start_thread(Thread1); 93 94 al_start_timer(timer); 95 gameTime = al_current_time(); 96 97 while(!done) 98 { 99 ALLEGRO_EVENT ev; 100 101 al_wait_for_event(event_queue, &ev); 102 //============================================== 103 //INPUT 104 //============================================== 105 if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 106 { 107 ................................................. 108 } 109 else if(ev.type == ALLEGRO_EVENT_KEY_UP) 110 { 111 ................................................. 112 } 113 //============================================== 114 //GAME UPDATE 115 //============================================== 116 else if(ev.type == ALLEGRO_EVENT_TIMER) 117 { 118 render = true; 119 120 Temp_State.Set_CurState(Sys_State.Get_CurState()); 121 122 if(Temp_State.Get_CurState() == PLAYING) 123 { 124 ................................................. 125 126 if(CheckForCollision(Character) == 1) 127 { 128 al_lock_mutex(Info.Get_Mutex()); 129 130 Sys_State.Set_CurState(LOADING); 131 al_broadcast_cond(Info.Get_Cond()); 132 133 al_unlock_mutex(Info.Get_Mutex()); 134 } 135 136 //============================================== 137 //Update camera 138 //============================================== 139 ................................................. 140 } 141 else if(Temp_State.Get_CurState() == LOADING) 142 { 143 //============================================== 144 //Update loading background animation 145 //============================================== 146 ................................................. 147 } 148 149 //UPDATE FPS=========== 150 frames++; 151 if(al_current_time() - gameTime >= 1) 152 { 153 gameTime = al_current_time(); 154 gameFPS = frames; 155 frames = 0; 156 } 157 //===================== 158 } 159 160 //============================================== 161 //RENDER 162 //============================================== 163 if(render && al_is_event_queue_empty(event_queue)) 164 { 165 render = false; 166 167 al_lock_mutex(Info.Get_Mutex()); 168 Temp_State.Set_CurState(Sys_State.Get_CurState()); 169 al_unlock_mutex(Info.Get_Mutex()); 170 171 if(Temp_State.Get_CurState() == PLAYING) 172 { 173 //============================================== 174 //Draw the map etc.. 175 //============================================== 176 ................................................. 177 } 178 else if(Temp_State.Get_CurState() == LOADING) 179 { 180 //============================================== 181 //Draw the loading screen 182 //============================================== 183 ................................................. 184 } 185 186 ................................................. 187 188 //FLIP BUFFERS======================== 189 al_flip_display(); 190 al_clear_to_color(al_map_rgb(0,0,0)); 191 } 192 } 193 194 al_set_thread_should_stop(Thread1); 195 196 //============================================== 197 //DESTROY PROJECT OBJECTS 198 //============================================== 199 ................................................. 200 201 return 0; 202} 203 204void *Load(ALLEGRO_THREAD *thr, void *arg) 205{ 206 ThreadInfo *Info = (ThreadInfo*) arg; 207 208 while(!al_get_thread_should_stop(thr)) 209 { 210 if(Info->Get_State()->Get_SysState()->Get_CurState() == LOADING) 211 { 212 al_lock_mutex(Info->Get_Mutex()); 213 214 Sprite *sprite = Info->Get_Player(); 215 StateMachine *State = Info->Get_State(); 216 BLKSTR *MapData = Info->Get_State()->Get_MapState()->Get_CurrBlock(sprite); 217 218 al_unlock_mutex(Info->Get_Mutex()); 219 220 LoadNewMap(sprite, MapData); 221 222 al_lock_mutex(Info->Get_Mutex()); 223 State->Get_SysState()->Set_CurState(PLAYING); 224 al_unlock_mutex(Info->Get_Mutex()); 225 } 226 } 227 return NULL; 228}

If anyone would like to see any other parts of my code, ask. I hope there's just a stupid thing that missed in there. If anyone see's any potential logic errors in my code please tell me.

also, I'm new to this multithreading stuff, so any pointers/tips with using them are welcomed.

Thanks for any and all help,
-Ryan

-Ryan
----------------------------------------------------
If I'm asking, it's because I failed for over 2 hours trying to find the answer on Google / trying to fix it myself.

Trent Gamblin
Member #261
April 2000
avatar

You can't access graphics stuff from two threads at the same time, or without releasing the display from one thread and claiming it in the other. I've never tried this with Direct3D so I don't know if it works there, but you can do something like:

thread 1

al_set_target_bitmap(NULL); // release context
// signal other thread it's ok to grab context

thread 2

// receive signal from thread 1
al_set_target_bitmap(some_bitmap_or_backbuffer);

Then when you're done do it in reverse.

But the problem here is, it may be pointless. If thread 1 can't do anything (drawing) while thread 2 is loading the level, it's not going to give you a speed boost and will just complicate your code. That may not be the case for you though, I don't know... threading is just pointless when both threads can't execute at the same time.

kazzmir
Member #1,786
December 2001
avatar

If LoadMap is creating ALLEGRO_BITMAP's and passing them to the main thread then that will cause the game to slow down a lot during rendering. Make sure you convert memory bitmaps to video on the main thread where you render stuff.

You can use al_convert_bitmap as long as the new bitmap flags are set up properly (the default is ok).

if (al_get_bitmap_flags(b) & ALLEGRO_MEMORY_BITMAP){
  al_convert_bitmap(b);
}

Converting to memory to video bitmap is relatively fast and only needs to be done once.

ryancoboy
Member #14,468
July 2012

@kazzmir: Seems like that might be what's causing me problems. I'll check it out when i get home tonight. Thank you for pointing that out to me.

-Ryan

-Ryan
----------------------------------------------------
If I'm asking, it's because I failed for over 2 hours trying to find the answer on Google / trying to fix it myself.

kazzmir
Member #1,786
December 2001
avatar

I see now that my post doesn't have enough context, so for anyone else reading if you create an ALLEGRO_BITMAP in a thread that doesn't have a context set (because the target bitmap is NULL) then Allegro will create a memory bitmap by default.

Bitmaps created in threads that have a target bitmap set with a display will generally create a video bitmap (although you can change this by setting the new bitmap flags).

ryancoboy
Member #14,468
July 2012

Sorry for the late reply (got caught up with family stuff last night). I just did some checks in my code and it turns out that the bitmaps that it is drawing after the first loading sequence are indeed memory bitmaps.

Now my problem is how do I convert them to video bitmaps? I'm using Allegro 5.0.5 at the moment. And it looks like the al_convert_bitmap(); feature is only in version 5.1. Any advice? Should I just switch to using 5.1? I'm not too deep into this project so switching now would be the best time, I think.

-Ryan
----------------------------------------------------
If I'm asking, it's because I failed for over 2 hours trying to find the answer on Google / trying to fix it myself.

kazzmir
Member #1,786
December 2001
avatar

I think you can just call al_clone_bitmap then and destroy the old one.

ALLEGRO_BITMAP* video = al_clone_bitmap(b);
al_destroy_bitmap(b);
b = video;

ryancoboy
Member #14,468
July 2012

@kazzmir: THANK YOU SO MUCH! That completely took away the lag/unresponsive problem. I've never needed to convert bitmaps before so that was new to me. Thank you for explaining the converting process.

I've got a new problem now but I'll try to hammer that out on my own.

Thanks again,
-Ryan

-Ryan
----------------------------------------------------
If I'm asking, it's because I failed for over 2 hours trying to find the answer on Google / trying to fix it myself.

kazzmir
Member #1,786
December 2001
avatar

Yes the difference between video and memory bitmaps was the most painful thing I had to get accustomed to when using A5.

You can read more about my experience here: http://www.allegro.cc/forums/thread/607477

ryancoboy
Member #14,468
July 2012

@kazzmir: That was a good read, thanks. I feel I'm starting to understand this converting stuff a lot better now.

-Ryan

-Ryan
----------------------------------------------------
If I'm asking, it's because I failed for over 2 hours trying to find the answer on Google / trying to fix it myself.

Go to: