Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
profiling.c
Go to the documentation of this file.
1// Stolen from HackerSM64
2
3#include "profiling.h"
4#include "dx/utils.h"
5#include "game_modes.h"
6#include "PR/os_internal_reg.h"
7
8#ifdef USE_PROFILER
9
10#define RDP_CYCLE_CONV(x) ((10 * (x)) / 625) // 62.5 million cycles per frame
11
12ProfileTimeData all_profiling_data[PROFILER_TIME_COUNT];
13
14int profile_buffer_index = -1;
15int rsp_buffer_indices[PROFILER_RSP_COUNT];
16// Holds either the start time if the task is running, or the amount of time the task has run for so far if yielded
17u32 rsp_pending_times[PROFILER_RSP_COUNT];
18u32 prev_start;
19u32 cur_start;
20u32 prev_time;
21u32 gfx_start;
22u32 gfx_buffer_index;
23u32 audio_start;
24u32 audio_buffer_index;
25u32 preempted_time;
26u32 collision_time = 0;
27
28#ifdef GFX_PROFILING
31#endif
32#ifdef AUDIO_PROFILING
33u32 audio_subset_starts[AUDIO_SUBSET_SIZE];
34u32 audio_subset_tallies[AUDIO_SUBSET_SIZE];
35#endif
36
37static void buffer_update(ProfileTimeData* data, u32 new, int buffer_index) {
38 u32 old = data->counts[buffer_index];
39 data->total -= old;
40 data->total += new;
41 data->counts[buffer_index] = new;
42}
43
44void profiler_update(enum ProfilerTime which, u32 delta) {
45 u32 cur_time = osGetCount();
46 u32 diff;
47 ProfileTimeData* cur_data = &all_profiling_data[which];
48
49 diff = cur_time - prev_time - delta;
50
51 u32 saved = __osDisableInt();
52 u32 cur_preempted_time = preempted_time;
53 preempted_time = 0;
54 __osRestoreInt(saved);
55 if (cur_preempted_time > 0) {
56 diff -= cur_preempted_time;
57 cur_start += cur_preempted_time;
58 }
59
60 buffer_update(cur_data, diff, profile_buffer_index);
61 prev_time = cur_time;
62}
63
65 rsp_pending_times[which] = osGetCount();
66}
67
69 ProfileTimeData* cur_data = &all_profiling_data[PROFILER_TIME_RSP_GFX + which];
70 int cur_index = rsp_buffer_indices[which];
71 u32 time = osGetCount() - rsp_pending_times[which];
72 rsp_pending_times[which] = 0;
73
74 buffer_update(cur_data, time, cur_index);
75 cur_index++;
76 if (cur_index >= PROFILING_BUFFER_SIZE) {
77 cur_index = 0;
78 }
79 rsp_buffer_indices[which] = cur_index;
80}
81
83 rsp_pending_times[PROFILER_RSP_GFX] = osGetCount() - rsp_pending_times[PROFILER_RSP_GFX];
84}
85
86// This ends up being the same math as resumed, so we just use resumed for both
87// void profiler_rsp_yielded() {
88// rsp_pending_times[PROFILER_RSP_GFX] = osGetCount() - rsp_pending_times[PROFILER_RSP_GFX];
89// }
90
91void profiler_gfx_started() {
92 gfx_start = osGetCount();
93
94#ifdef GFX_PROFILING
95 for (s32 i = 0; i < GFX_SUBSET_SIZE; i++) {
96 gfx_subset_tallies[i] = 0;
97 }
98
100#endif
101}
102
104 audio_start = osGetCount();
105
106#ifdef AUDIO_PROFILING
107 for (s32 i = 0; i < AUDIO_SUBSET_SIZE; i++) {
108 audio_subset_tallies[i] = 0;
109 }
110
111 audio_subset_starts[PROFILER_TIME_SUB_AUDIO_UPDATE - PROFILER_TIME_SUB_AUDIO_START] = audio_start;
112#endif
113}
114
115#ifdef PUPPYPRINT_DEBUG
116
118 collision_time = 0;
119}
120
121void profiler_collision_update(u32 time) {
122 collision_time += osGetCount() - time;
123}
124
126 ProfileTimeData* cur_data = &all_profiling_data[PROFILER_TIME_COLLISION];
127 buffer_update(cur_data, collision_time, profile_buffer_index);
128}
129
130#endif
131
133 if (which == PROFILER_DELTA_COLLISION) {
134 return collision_time;
135 } else {
136 return 0;
137 }
138}
139
140void profiler_gfx_completed() {
141 ProfileTimeData* cur_data = &all_profiling_data[PROFILER_TIME_GFX];
142 u32 time = osGetCount();
143 u32 cur_index = gfx_buffer_index;
144
145 preempted_time = time - gfx_start;
146 buffer_update(cur_data, time - gfx_start, cur_index);
147
148#ifdef GFX_PROFILING
150
151 for (s32 i = 0; i < GFX_SUBSET_SIZE; i++) {
152 cur_data = &all_profiling_data[i + PROFILER_TIME_SUB_GFX_START];
153 buffer_update(cur_data, gfx_subset_tallies[i], cur_index);
154 }
155#endif
156
157 cur_index++;
158 if (cur_index >= PROFILING_BUFFER_SIZE) {
159 cur_index = 0;
160 }
161
162 gfx_buffer_index = cur_index;
163}
164
165
167 ProfileTimeData* cur_data = &all_profiling_data[PROFILER_TIME_AUDIO];
168 u32 time = osGetCount();
169 u32 cur_index = audio_buffer_index;
170
171 preempted_time = time - audio_start;
172 buffer_update(cur_data, time - audio_start, cur_index);
173
174#ifdef AUDIO_PROFILING
176
177 for (s32 i = 0; i < AUDIO_SUBSET_SIZE; i++) {
178 cur_data = &all_profiling_data[i + PROFILER_TIME_SUB_AUDIO_START];
179 buffer_update(cur_data, audio_subset_tallies[i], cur_index);
180 }
181#endif
182
183 cur_index++;
184 if (cur_index >= PROFILING_BUFFER_SIZE) {
185 cur_index = 0;
186 }
187
188 audio_buffer_index = cur_index;
189}
190
191static void update_fps_timer() {
192 u32 diff = cur_start - prev_start;
193
194 buffer_update(&all_profiling_data[PROFILER_TIME_FPS], diff, profile_buffer_index);
195 prev_start = cur_start;
196}
197
198static void update_total_timer() {
199 u32 saved = __osDisableInt();
200 u32 cur_preempted_time = preempted_time;
201 preempted_time = 0;
202 __osRestoreInt(saved);
203
204 prev_time = cur_start + cur_preempted_time;
206}
207
208#ifdef PUPPYPRINT_DEBUG
209extern u8 sPPDebugPage;
210extern u8 fDebug;
211#endif
212
213static void update_rdp_timers() {
214 u32 tmem = IO_READ(DPC_TMEM_REG);
215 u32 cmd = IO_READ(DPC_BUFBUSY_REG);
216 u32 pipe = IO_READ(DPC_PIPEBUSY_REG);
217
218 if (gGameStatus.frameCounter > 5) {
219 IO_WRITE(DPC_STATUS_REG, (DPC_CLR_CLOCK_CTR | DPC_CLR_CMD_CTR | DPC_CLR_PIPE_CTR | DPC_CLR_TMEM_CTR));
220 }
221
222 buffer_update(&all_profiling_data[PROFILER_TIME_TMEM], tmem, profile_buffer_index);
223 buffer_update(&all_profiling_data[PROFILER_TIME_CMD], cmd, profile_buffer_index);
224 buffer_update(&all_profiling_data[PROFILER_TIME_PIPE], pipe, profile_buffer_index);
225}
226
227float profiler_get_fps() {
228 return (1000000.0f * PROFILING_BUFFER_SIZE) / (OS_CYCLES_TO_USEC(all_profiling_data[PROFILER_TIME_FPS].total));
229}
230
231u32 profiler_get_cpu_cycles() {
232 u32 cpu_normal_time = all_profiling_data[PROFILER_TIME_TOTAL].total / PROFILING_BUFFER_SIZE;
233 u32 cpu_audio_time = all_profiling_data[PROFILER_TIME_AUDIO].total / PROFILING_BUFFER_SIZE;
234 return cpu_normal_time + cpu_audio_time * 2;
235}
236
237u32 profiler_get_rsp_cycles() {
238 u32 rsp_graphics_time = all_profiling_data[PROFILER_TIME_RSP_GFX].total / PROFILING_BUFFER_SIZE;
239 u32 rsp_audio_time = all_profiling_data[PROFILER_TIME_RSP_AUDIO].total / PROFILING_BUFFER_SIZE;
240 return rsp_graphics_time + rsp_audio_time;
241}
242
243u32 profiler_get_rdp_cycles() {
244 u32 rdp_pipe_cycles = all_profiling_data[PROFILER_TIME_PIPE].total;
245 u32 rdp_tmem_cycles = all_profiling_data[PROFILER_TIME_TMEM].total;
246 u32 rdp_cmd_cycles = all_profiling_data[PROFILER_TIME_CMD].total;
247
248 u32 rdp_max_cycles = MAX(MAX(rdp_pipe_cycles, rdp_tmem_cycles), rdp_cmd_cycles);
249
250 return rdp_max_cycles / PROFILING_BUFFER_SIZE;
251}
252
254 u32 cpu_normal_time = OS_CYCLES_TO_USEC(all_profiling_data[PROFILER_TIME_TOTAL].total / PROFILING_BUFFER_SIZE);
255 u32 cpu_audio_time = OS_CYCLES_TO_USEC(all_profiling_data[PROFILER_TIME_AUDIO].total / PROFILING_BUFFER_SIZE);
256 return cpu_normal_time + cpu_audio_time * 2;
257}
258
260 u32 rsp_graphics_time = OS_CYCLES_TO_USEC(all_profiling_data[PROFILER_TIME_RSP_GFX].total / PROFILING_BUFFER_SIZE);
261 u32 rsp_audio_time = OS_CYCLES_TO_USEC(all_profiling_data[PROFILER_TIME_RSP_AUDIO].total / PROFILING_BUFFER_SIZE);
262 return rsp_graphics_time + rsp_audio_time;
263}
264
266 u32 rdp_pipe_cycles = all_profiling_data[PROFILER_TIME_PIPE].total;
267 u32 rdp_tmem_cycles = all_profiling_data[PROFILER_TIME_TMEM].total;
268 u32 rdp_cmd_cycles = all_profiling_data[PROFILER_TIME_CMD].total;
269
270 u32 rdp_max_cycles = MAX(MAX(rdp_pipe_cycles, rdp_tmem_cycles), rdp_cmd_cycles);
271
272 return RDP_CYCLE_CONV(rdp_max_cycles / PROFILING_BUFFER_SIZE);
273}
274
276 u32 microseconds[PROFILER_TIME_COUNT];
277 char text_buffer_labels[196];
278 char text_buffer_time[196];
279
280 update_fps_timer();
281 update_total_timer();
282 update_rdp_timers();
283
284#ifndef PUPPYPRINT_DEBUG
285 static u8 show_profiler = 0;
286 if ((gPlayerStatus.pressedButtons & (L_TRIG | U_JPAD)) && (gPlayerStatus.curButtons & L_TRIG) && (gPlayerStatus.curButtons & U_JPAD)) {
287 show_profiler ^= 1;
288 }
289#endif
290
291#ifdef PUPPYPRINT_DEBUG
292 if (fDebug && sPPDebugPage == PUPPYPRINT_PAGE_PROFILER) {
293#else
294 if (show_profiler) {
295#endif
296 for (int i = 0; i < PROFILER_TIME_COUNT; i++) {
297 if (i < PROFILER_TIME_TMEM) {
298 microseconds[i] = OS_CYCLES_TO_USEC(all_profiling_data[i].total / PROFILING_BUFFER_SIZE);
299 } else {
300 microseconds[i] = RDP_CYCLE_CONV(all_profiling_data[i].total / PROFILING_BUFFER_SIZE);
301 }
302 }
303
304 // audio time is removed from the main thread profiling, so add it back here
305 u32 total_cpu = microseconds[PROFILER_TIME_TOTAL] + microseconds[PROFILER_TIME_AUDIO] * 2;
306#ifndef GFX_PROFILING
307 u32 total_rsp = microseconds[PROFILER_TIME_RSP_GFX] + microseconds[PROFILER_TIME_RSP_AUDIO] * 2;
308 u32 max_rdp = MAX(MAX(microseconds[PROFILER_TIME_TMEM], microseconds[PROFILER_TIME_CMD]), microseconds[PROFILER_TIME_PIPE]);
309#endif
310
311 s32 text_buffer_labels_len = sprintf(
312 text_buffer_labels,
313 " " // space for prepend
314 "FPS: %5.2f\n"
315 "CPU\t\t%lu (%lu%%)\n"
316 " Input\n"
317 " Workers\n"
318 " Triggers\n"
319 " EVT\n"
320 " Messages\n"
321 " HUD elements\n"
322 " Entities\n"
323 " Gfx\n"
324 " Audio\n",
325 1000000.0f / microseconds[PROFILER_TIME_FPS],
326 total_cpu, total_cpu / 333
327 );
328 s32 text_buffer_time_len = sprintf(
329 text_buffer_time,
330 " " // space for prepend
331 "\n"
332 "\n"
333 "%lu\n"
334 "%lu\n"
335 "%lu\n"
336 "%lu\n"
337 "%lu\n"
338 "%lu\n"
339 "%lu\n"
340 "%lu\n"
341 "%lu\n",
342 microseconds[PROFILER_TIME_CONTROLLERS],
343 microseconds[PROFILER_TIME_WORKERS],
344 microseconds[PROFILER_TIME_TRIGGERS],
345 microseconds[PROFILER_TIME_EVT],
346 microseconds[PROFILER_TIME_MESSAGES],
347 microseconds[PROFILER_TIME_HUD_ELEMENTS],
348 microseconds[PROFILER_TIME_ENTITIES],
349 microseconds[PROFILER_TIME_GFX],
350 microseconds[PROFILER_TIME_AUDIO] * 2 // audio is 60Hz, so double the average
351 );
352
353 switch (get_game_mode()) {
354 case GAME_MODE_WORLD:
355 sprintf(&text_buffer_labels[text_buffer_labels_len],
356 " Encounters\n"
357 " NPCs\n"
358 " Player\n"
359 " Item entities\n"
360 " Effects\n"
361 " Cameras\n"
362 );
363 sprintf(&text_buffer_time[text_buffer_time_len],
364 "%lu\n"
365 "%lu\n"
366 "%lu\n"
367 "%lu\n"
368 "%lu\n"
369 "%lu\n",
370 microseconds[PROFILE_TIME_WORLD_ENCOUNTERS],
371 microseconds[PROFILE_TIME_WORLD_NPCS],
372 microseconds[PROFILE_TIME_WORLD_PLAYER],
374 microseconds[PROFILE_TIME_WORLD_EFFECTS],
375 microseconds[PROFILE_TIME_WORLD_CAMERAS]
376 );
377 break;
378 default:
379 sprintf(&text_buffer_labels[text_buffer_labels_len],
380 " Game mode step\n"
381 );
382 sprintf(&text_buffer_time[text_buffer_time_len],
383 "%lu\n",
384 microseconds[PROFILER_TIME_STEP_GAME_MODE]
385 );
386 break;
387 }
388
389 dx_string_to_msg((u8*)&text_buffer_labels, (u8*)&text_buffer_labels);
390 dx_string_to_msg((u8*)&text_buffer_time, (u8*)&text_buffer_time);
391 text_buffer_labels[0] = text_buffer_time[0] = MSG_CHAR_READ_FUNCTION;
392 text_buffer_labels[1] = text_buffer_time[1] = MSG_READ_FUNC_SIZE;
393 text_buffer_labels[2] = text_buffer_time[2] = 14;
394 text_buffer_labels[3] = text_buffer_time[3] = 14;
395 draw_msg((s32)&text_buffer_labels, 3, 0, 255, 0, 0);
396 draw_msg((s32)&text_buffer_time, 110, 0, 255, 0, 0);
397
398#ifdef GFX_PROFILING
399 s32 time_offset = 100;
400 sprintf(
401 text_buffer_labels,
402 " " // space for prepend
403 "\n"
404 "Gfx breakdown\n"
405 " Entities\n"
406 " Models\n"
407 " Player\n"
408 " Workers\n"
409 " NPCs\n"
410 " Effects\n"
411 " Render tasks\n"
412 " Hud elements\n"
413 " Back UI\n"
414 " Front UI\n"
415 );
416 sprintf(
417 text_buffer_time,
418 " " // space for prepend
419 "\n"
420 "\n"
421 "%lu\n"
422 "%lu\n"
423 "%lu\n"
424 "%lu\n"
425 "%lu\n"
426 "%lu\n"
427 "%lu\n"
428 "%lu\n"
429 "%lu\n"
430 "%lu\n",
431 microseconds[PROFILER_TIME_SUB_GFX_ENTITIES],
432 microseconds[PROFILER_TIME_SUB_GFX_MODELS],
433 microseconds[PROFILER_TIME_SUB_GFX_PLAYER],
434 microseconds[PROFILER_TIME_SUB_GFX_WORKERS],
435 microseconds[PROFILER_TIME_SUB_GFX_NPCS],
436 microseconds[PROFILER_TIME_SUB_GFX_EFFECTS],
439 microseconds[PROFILER_TIME_SUB_GFX_BACK_UI],
441 );
442#else
443 s32 time_offset = 50;
444 sprintf(text_buffer_labels,
445 " " // space for prepend
446 "\n"
447 "RDP\t\t\t%lu (%lu%%)\n"
448 " Tmem\n"
449 " Cmd\n"
450 " Pipe\n"
451 "\n"
452 "RSP\t\t%lu (%lu%%)\n"
453 " Gfx\n"
454 " Audio\n",
455 max_rdp, max_rdp / 333,
456 total_rsp, total_rsp / 333
457 );
458 sprintf(text_buffer_time,
459 " " // space for prepend
460 "\n"
461 "\n"
462 "%lu\n"
463 "%lu\n"
464 "%lu\n"
465 "\n"
466 "\n"
467 "%lu\n"
468 "%lu\n",
469 microseconds[PROFILER_TIME_TMEM],
470 microseconds[PROFILER_TIME_CMD],
471 microseconds[PROFILER_TIME_PIPE],
472 microseconds[PROFILER_TIME_RSP_GFX],
473 microseconds[PROFILER_TIME_RSP_AUDIO] * 2
474 );
475#endif
476 dx_string_to_msg((u8*)&text_buffer_labels, (u8*)&text_buffer_labels);
477 dx_string_to_msg((u8*)&text_buffer_time, (u8*)&text_buffer_time);
478 text_buffer_labels[0] = text_buffer_time[0] = MSG_CHAR_READ_FUNCTION;
479 text_buffer_labels[1] = text_buffer_time[1] = MSG_READ_FUNC_SIZE;
480 text_buffer_labels[2] = text_buffer_time[2] = 14;
481 text_buffer_labels[3] = text_buffer_time[3] = 14;
482 draw_msg((s32)&text_buffer_labels, SCREEN_WIDTH/2, 0, 255, 0, 0);
483 draw_msg((s32)&text_buffer_time, SCREEN_WIDTH/2 + time_offset, 0, 255, 0, 0);
484 }
485}
486
488 profile_buffer_index++;
489 preempted_time = 0;
490
491 if (profile_buffer_index >= PROFILING_BUFFER_SIZE) {
492 profile_buffer_index = 0;
493 }
494
495 prev_time = cur_start = osGetCount();
496}
497
498#endif
#define draw_msg
@ MSG_READ_FUNC_SIZE
Definition enums.h:6095
@ MSG_CHAR_READ_FUNCTION
Definition enums.h:6058
s32 get_game_mode(void)
Definition game_modes.c:123
@ GAME_MODE_WORLD
Definition game_modes.h:12
#define profiler_get_cpu_microseconds()
Definition profiling.h:170
#define profiler_frame_setup()
Definition profiling.h:159
ProfilerRSPTime
Definition profiling.h:97
@ PROFILER_RSP_COUNT
Definition profiling.h:100
@ PROFILER_RSP_GFX
Definition profiling.h:98
#define PROFILING_BUFFER_SIZE
Definition profiling.h:21
#define profiler_update(which, delta)
Definition profiling.h:157
#define profiler_rsp_resumed()
Definition profiling.h:162
#define profiler_collision_completed()
Definition profiling.h:167
u32 gfx_subset_starts[PROFILER_TIME_SUB_GFX_END - PROFILER_TIME_SUB_GFX_START]
ProfilerDeltaTime
Definition profiling.h:103
@ PROFILER_DELTA_COLLISION
Definition profiling.h:104
#define profiler_get_rsp_microseconds()
Definition profiling.h:171
ProfilerTime
Definition profiling.h:52
@ PROFILER_TIME_CMD
Definition profiling.h:84
@ PROFILER_TIME_TMEM
Definition profiling.h:82
@ PROFILER_TIME_SUB_GFX_HUD_ELEMENTS
Definition profiling.h:67
@ PROFILER_TIME_TOTAL
Definition profiling.h:79
@ PROFILE_TIME_WORLD_PLAYER
Definition profiling.h:89
@ PROFILER_TIME_CONTROLLERS
Definition profiling.h:54
@ PROFILER_TIME_SUB_GFX_BACK_UI
Definition profiling.h:67
@ PROFILER_TIME_PIPE
Definition profiling.h:83
@ PROFILER_TIME_FPS
Definition profiling.h:53
@ PROFILER_TIME_ENTITIES
Definition profiling.h:61
@ PROFILE_TIME_WORLD_EFFECTS
Definition profiling.h:91
@ PROFILER_TIME_GFX
Definition profiling.h:68
@ PROFILER_TIME_SUB_GFX_START
Definition profiling.h:67
@ PROFILER_TIME_RSP_AUDIO
Definition profiling.h:81
@ PROFILER_TIME_SUB_GFX_ENTITIES
Definition profiling.h:67
@ PROFILER_TIME_MESSAGES
Definition profiling.h:58
@ PROFILE_TIME_WORLD_ENCOUNTERS
Definition profiling.h:87
@ PROFILER_TIME_SUB_GFX_FRONT_UI
Definition profiling.h:67
@ PROFILE_TIME_WORLD_ITEM_ENTITIES
Definition profiling.h:90
@ PROFILER_TIME_SUB_GFX_WORKERS
Definition profiling.h:67
@ PROFILER_TIME_SUB_GFX_PLAYER
Definition profiling.h:67
@ PROFILER_TIME_SUB_GFX_EFFECTS
Definition profiling.h:67
@ PROFILER_TIME_HUD_ELEMENTS
Definition profiling.h:59
@ PROFILE_TIME_WORLD_NPCS
Definition profiling.h:88
@ PROFILER_TIME_TRIGGERS
Definition profiling.h:56
@ PROFILER_TIME_COUNT
Definition profiling.h:94
@ PROFILER_TIME_RSP_GFX
Definition profiling.h:80
@ PROFILER_TIME_SUB_GFX_MODELS
Definition profiling.h:67
@ PROFILER_TIME_STEP_GAME_MODE
Definition profiling.h:60
@ PROFILER_TIME_SUB_GFX_RENDER_TASKS
Definition profiling.h:67
@ PROFILER_TIME_WORKERS
Definition profiling.h:55
@ PROFILER_TIME_EVT
Definition profiling.h:57
@ PROFILER_TIME_SUB_GFX_NPCS
Definition profiling.h:67
@ PROFILE_TIME_WORLD_CAMERAS
Definition profiling.h:92
@ PROFILER_TIME_AUDIO
Definition profiling.h:77
@ PROFILER_TIME_SUB_GFX_UPDATE
Definition profiling.h:67
#define profiler_collision_update(time)
Definition profiling.h:168
#define GFX_SUBSET_SIZE
Definition profiling.h:176
#define profiler_rsp_started(which)
Definition profiling.h:160
u32 gfx_subset_tallies[PROFILER_TIME_SUB_GFX_END - PROFILER_TIME_SUB_GFX_START]
#define profiler_print_times()
Definition profiling.h:158
#define profiler_rsp_completed(which)
Definition profiling.h:161
#define PROFILER_DELTA_PUPPYPRINT2
Definition profiling.h:115
#define profiler_get_delta(which)
Definition profiling.h:169
#define profiler_audio_completed()
Definition profiling.h:164
@ PROFILER_TIME_SUB_AUDIO_START
Definition profiling.h:276
@ PROFILER_TIME_SUB_AUDIO_UPDATE
Definition profiling.h:276
#define profiler_get_rdp_microseconds()
Definition profiling.h:172
#define profiler_collision_reset()
Definition profiling.h:166
#define profiler_audio_started()
Definition profiling.h:163
#define PROFILER_TIME_PUPPYPRINT1
Definition profiling.h:112
#define SCREEN_WIDTH
Definition macros.h:105
u8 * dx_string_to_msg(u8 *msg, const u8 *str)
Definition utils.c:16
GameStatus gGameStatus
Definition main_loop.c:21
PlayerStatus gPlayerStatus
Definition 77480.c:39