|
[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: 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. 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 |
Trent Gamblin
Member #261
April 2000
|
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
|
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 |
kazzmir
Member #1,786
December 2001
|
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 |
kazzmir
Member #1,786
December 2001
|
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 |
kazzmir
Member #1,786
December 2001
|
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 |
|