1 /*---------------------------------------------------------------------------*
2 Project: Revolution Demo Library
3 File: DEMOInit.c
4
5 Copyright 1998-2006 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: DEMOInit.c,v $
14 Revision 1.8.2.1 2008/07/29 09:27:17 nakano_yoshinobu
15 Added DemoUseMEM_HEAP_OPT_THREAD_SAFE option.
16 This option uses MEMCreateExpHeapEx(..., MEM_HEAP_OPT_THREAD_SAFE) in DEMOInit().
17
18 Revision 1.8 2008/05/19 01:19:30 nakano_yoshinobu
19 Added GXFlush() for GXGetCPUFifo changing.
20
21 Revision 1.7 2007/06/15 23:03:14 carlmu
22 Allow XFB to be allocated from MEM2.
23 Allow creation of extra large XFB's (eg, for panning).
24
25 Revision 1.6 2007/02/07 23:54:57 johnc
26 Removed static scope from functions and variables inside DEMOInit.
27
28 Revision 1.5 2006/04/06 07:29:39 johnc
29 Fixed bug in creation of heap for MEM2 when DemoUseMEMHeap is true.
30
31 Revision 1.4 2006/03/11 06:56:02 hirose
32 Integrated MEMAllocator, added switch to use heap defined in MEM library.
33
34 Revision 1.3 2006/02/06 05:07:24 hirose
35 Changes due to Fifo API updates.
36
37 Revision 1.2 2006/01/07 06:47:39 hirose
38 Reconstruction from simpler form.
39
40 Revision 1.1.1.1 2005/05/12 02:15:48 yasuh-to
41
42 $NoKeywords: $
43 *---------------------------------------------------------------------------*/
44
45 /*---------------------------------------------------------------------------*
46 This DEMO library provides a common application
47 framework that is used in all the GX demos distributed
48 with the Revolution SDK.
49 *---------------------------------------------------------------------------*/
50
51
52 #include <demo.h>
53
54 /*---------------------------------------------------------------------------*
55 Static variables
56 *---------------------------------------------------------------------------*/
57 static GXBool DemoFirstFrame = GX_TRUE;
58
59 #define DEFAULT_FIFO_SIZE (256 * 1024)
60
61 void* DemoFifoBuffer;
62 GXFifoObj* DemoFifoObj;
63
64 static GXRenderModeObj *Rmode;
65 static GXRenderModeObj Rmodeobj;
66
67 static u32 allocatedFrameBufferSize = 0;
68
69 /*---------------------------------------------------------------------------*
70 Global variables
71 *---------------------------------------------------------------------------*/
72 void* DemoFrameBuffer1;
73 void* DemoFrameBuffer2;
74 void* DemoCurrentBuffer;
75
76 // Set to 1 before DEMOInit() if MEMHeap is prefered rather than OSHeap.
77 u32 DemoUseMEMHeap = 0;
78
79 // Set to TRUE before DEMOInit() if XFBs should be in MEM2 rather than MEM1.
80 BOOL DemoUseMEM2XFB = FALSE;
81
82 // Set to TRUE before DEMOInit() if use MEM_HEAP_OPT_THREAD_SAFE.
83 BOOL DemoUseMEM_HEAP_OPT_THREAD_SAFE = FALSE;
84
85 MEMAllocator DemoAllocator1;
86 MEMAllocator DemoAllocator2;
87
88 /*---------------------------------------------------------------------------*
89 Functions
90 *---------------------------------------------------------------------------*/
91
92 /*===========================================================================*
93
94
95 Initialization
96
97
98 *===========================================================================*/
99
100 /*---------------------------------------------------------------------------*
101 Name: DEMOInit
102
103 Description: This function initializes the components of
104 the operating system and its device drivers.
105 The mode parameter allows the application to
106 override the default render mode. It then allocates
107 all of main memory except the area for external
108 framebuffer into a heap than can be managed
109 with OSAlloc. This function initializes the video
110 controller to run at 640x480 interlaced display,
111 with 60Hz refresh (actually, 640x448; see below).
112
113 Arguments: mode : render mode
114 Default render mode will be used when
115 NULL is given as this argument.
116
117 Returns: None
118 *---------------------------------------------------------------------------*/
119 void (DEMOInit)( GXRenderModeObj *mode );
120
121 void (DEMOInit)( GXRenderModeObj *mode )
122 {
123 DEMOInit_Real(mode);
124 }
125
126 /*---------------------------------------------------------------------------*/
DEMOInit_Real(GXRenderModeObj * mode)127 void DEMOInit_Real( GXRenderModeObj *mode )
128 {
129 // Initializes OS.
130 // OSInit(); // called inside the startup routine.
131
132 // Initializes disc drive interface.
133 DVDInit(); // Initializes disc.
134
135 // Initializes video interface.
136 VIInit();
137
138 // Initializes game PADs (controllers)
139 DEMOPadInit(); // PADInit() is called inside.
140
141 // Set up rendering mode
142 // (which reflects the GX/VI configurations and XFB size below)
143 DEMOSetRenderMode(mode);
144
145 // Memory configuration (framebuffers / GX Fifo / heap)
146 DEMOConfigureMem();
147
148 // Initializes graphics
149 DemoFifoObj = GXInit(DemoFifoBuffer, DEFAULT_FIFO_SIZE);
150 DEMOInitGX();
151
152 // Starts VI
153 DEMOStartVI();
154 }
155
156 /*---------------------------------------------------------------------------*
157 Name: DEMOSetRenderMode
158
159 Description: This function sets up rendering mode which configures
160 GX and VI. If mode == NULL, this function use a default
161 rendering mode according to the TV format.
162
163 Arguments: None
164
165 Returns: None
166 *---------------------------------------------------------------------------*/
DEMOSetRenderMode(GXRenderModeObj * mode)167 void DEMOSetRenderMode( GXRenderModeObj* mode )
168 {
169 // If an application specific render mode is provided,
170 // override the default render mode
171 if (mode != NULL)
172 {
173 Rmodeobj = *mode;
174 Rmode = &Rmodeobj;
175 }
176 else
177 {
178 switch (VIGetTvFormat())
179 {
180 case VI_NTSC:
181 Rmode = &GXNtsc480IntDf;
182 break;
183 case VI_PAL:
184 Rmode = &GXPal528IntDf;
185 break;
186 case VI_EURGB60:
187 Rmode = &GXEurgb60Hz480IntDf;
188 break;
189 case VI_MPAL:
190 Rmode = &GXMpal480IntDf;
191 break;
192 default:
193 OSHalt("DEMOInit: invalid TV format\n");
194 break;
195 }
196
197 // Trim off from top & bottom 16 scanlines (which will be overscanned).
198 // So almost all demos actually render only 448 lines (in NTSC case.)
199 // Since this setting is just for SDK demos, you can specify this
200 // in order to match your application requirements.
201 GXAdjustForOverscan(Rmode, &Rmodeobj, 0, 16);
202
203 Rmode = &Rmodeobj;
204 }
205 }
206
207 /*---------------------------------------------------------------------------*
208 Name: DEMOConfigureMem
209
210 Description: This function allocates external framebuffers and GX
211 FIFO buffers from arena. This function also sets up an
212 OS standard heap.
213
214 Note that this memory configuration only uses MEM1 region.
215
216 Arguments: None
217
218 Returns: None
219 *---------------------------------------------------------------------------*/
DEMOConfigureMem(void)220 void DEMOConfigureMem( void )
221 {
222 void* arenaLo;
223 void* arenaHi;
224 u32 fbSize;
225
226 /*----------------------------------------------------------------*
227 * Allocate GX FIFO buffer in MEM1 *
228 *----------------------------------------------------------------*/
229
230 arenaLo = OSGetMEM1ArenaLo();
231 DemoFifoBuffer = (void*)OSRoundUp32B((u32)arenaLo);
232 arenaLo = (void*)OSRoundUp32B((u32)DemoFifoBuffer + DEFAULT_FIFO_SIZE);
233 OSSetMEM1ArenaLo(arenaLo);
234
235 /*----------------------------------------------------------------*
236 * Allocate external framebuffers *
237 *----------------------------------------------------------------*/
238
239 if (DemoUseMEM2XFB) {
240 arenaLo = OSGetMEM2ArenaLo();
241 } else {
242 arenaLo = OSGetMEM1ArenaLo();
243 }
244 fbSize = VIPadFrameBufferWidth(Rmode->fbWidth) * Rmode->xfbHeight *
245 (u32)VI_DISPLAY_PIX_SZ;
246 allocatedFrameBufferSize = fbSize;
247 DemoFrameBuffer1 = (void*)OSRoundUp32B((u32)arenaLo);
248 DemoFrameBuffer2 = (void*)OSRoundUp32B((u32)DemoFrameBuffer1 + fbSize);
249 arenaLo = (void*)OSRoundUp32B((u32)DemoFrameBuffer2 + fbSize);
250 if (DemoUseMEM2XFB) {
251 OSSetMEM2ArenaLo(arenaLo);
252 } else {
253 OSSetMEM1ArenaLo(arenaLo);
254 }
255
256 /*----------------------------------------------------------------*
257 * Create a heap *
258 *----------------------------------------------------------------*/
259
260 if ( DemoUseMEMHeap )
261 {
262 // Memory allocation managed by MEM library. (recommended)
263
264 MEMHeapHandle heapHandle;
265
266 // Heap on MEM1
267 arenaLo = OSGetMEM1ArenaLo();
268 arenaHi = OSGetMEM1ArenaHi();
269
270 if (DemoUseMEM_HEAP_OPT_THREAD_SAFE)
271 {
272 heapHandle = MEMCreateExpHeapEx(arenaLo, (u32)arenaHi - (u32)arenaLo, MEM_HEAP_OPT_THREAD_SAFE);
273 }
274 else
275 {
276 heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo);
277 }
278
279 if ( heapHandle == MEM_HEAP_INVALID_HANDLE )
280 {
281 OSHalt("MEM1 heap allocation error.\n");
282 }
283 OSSetMEM1ArenaLo(arenaHi);
284 MEMInitAllocatorForExpHeap(&DemoAllocator1, heapHandle, 32);
285
286 // Heap on MEM2
287 arenaLo = OSGetMEM2ArenaLo();
288 arenaHi = OSGetMEM2ArenaHi();
289
290 if (DemoUseMEM_HEAP_OPT_THREAD_SAFE)
291 {
292 heapHandle = MEMCreateExpHeapEx(arenaLo, (u32)arenaHi - (u32)arenaLo, MEM_HEAP_OPT_THREAD_SAFE);
293 }
294 else
295 {
296 heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo);
297 }
298
299 if ( heapHandle == MEM_HEAP_INVALID_HANDLE )
300 {
301 OSHalt("MEM2 heap allocation error.\n");
302 }
303 OSSetMEM2ArenaLo(arenaHi);
304 MEMInitAllocatorForExpHeap(&DemoAllocator2, heapHandle, 32);
305 }
306 else
307 {
308 // Memory allocation managed by conventional OSAlloc framework
309 // for compatibilities.
310
311 OSHeapHandle heapHandle;
312
313 // OSInitAlloc should only ever be invoked once.
314 arenaLo = OSGetMEM1ArenaLo();
315 arenaHi = OSGetMEM1ArenaHi();
316 arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); // 1 heap
317 OSSetMEM1ArenaLo(arenaLo);
318
319 // Ensure boundaries are 32B aligned
320 arenaLo = (void*)OSRoundUp32B(arenaLo);
321 arenaHi = (void*)OSRoundDown32B(arenaHi);
322
323 // The boundaries given to OSCreateHeap should be 32B aligned
324 heapHandle = OSCreateHeap(arenaLo, arenaHi);
325 if ( heapHandle == -1 )
326 {
327 OSHalt("OS heap allocation error.\n");
328 }
329 // From here on out, OSAlloc and OSFree behave like malloc and free
330 // respectively
331 OSSetMEM1ArenaLo(arenaLo=arenaHi);
332
333 OSSetCurrentHeap(heapHandle);
334 MEMInitAllocatorForOSHeap(&DemoAllocator1, heapHandle);
335 MEMInitAllocatorForOSHeap(&DemoAllocator2, heapHandle);
336 }
337 }
338
339 /*---------------------------------------------------------------------------*
340 Name: DEMOInitGX
341
342 Description: This function performs GX initialization and configuration
343 by using current rendering mode
344
345 Arguments: None
346
347 Returns: None
348 *---------------------------------------------------------------------------*/
DEMOInitGX(void)349 void DEMOInitGX( void )
350 {
351 u16 fbWidth;
352 u16 xfbHeight;
353 f32 yScale;
354
355 /*----------------------------------------------------------------*
356 * GX configuration by a render mode obj *
357 *----------------------------------------------------------------*/
358 // These are necessary function calls to take a render mode
359 // object and set up relevant GX configuration.
360
361 // Check for unusual configuration
362 fbWidth = Rmode->fbWidth;
363 if (fbWidth > 640) {
364 fbWidth = 640;
365 }
366 xfbHeight = Rmode->xfbHeight;
367 if (xfbHeight > 528) {
368 xfbHeight = Rmode->efbHeight;
369 }
370
371 GXSetViewport(0.0F, 0.0F, (f32)fbWidth, (f32)Rmode->efbHeight,
372 0.0F, 1.0F);
373 GXSetScissor(0, 0, (u32)fbWidth, (u32)Rmode->efbHeight);
374
375 yScale = GXGetYScaleFactor(Rmode->efbHeight, xfbHeight);
376 xfbHeight = (u16)GXSetDispCopyYScale(yScale);
377 GXSetDispCopySrc(0, 0, fbWidth, Rmode->efbHeight); // use adjusted width
378 GXSetDispCopyDst(Rmode->fbWidth, Rmode->xfbHeight); // use original width
379
380 GXSetCopyFilter(Rmode->aa, Rmode->sample_pattern, GX_TRUE, Rmode->vfilter);
381 GXSetDispCopyGamma(GX_GM_1_0);
382
383 if (Rmode->aa)
384 GXSetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR);
385 else
386 GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR);
387
388 // Note that following is an appropriate setting for full-frame AA mode.
389 // You should use "xfbHeight" instead of "efbHeight" to specify actual
390 // view size. Since this library doesn't support such special case, please
391 // call these in each application to override the normal setting.
392 #if 0
393 GXSetViewport(0.0F, 0.0F, (f32)Rmode->fbWidth, (f32)Rmode->xfbHeight,
394 0.0F, 1.0F);
395 GXSetDispCopyYScale(1.0F);
396 #endif
397
398 // Clear embedded framebuffer for the first frame
399 GXCopyDisp(DemoFrameBuffer2, GX_TRUE);
400 }
401
402 /*---------------------------------------------------------------------------*
403 Name: DEMOStartVI
404
405 Description: This function performs VI start up settings that are
406 necessary at the beginning of each demo
407
408 Arguments: None
409
410 Returns: None
411 *---------------------------------------------------------------------------*/
DEMOStartVI(void)412 void DEMOStartVI( void )
413 {
414 // Configure VI with given render mode
415 VIConfigure(Rmode);
416
417 // Double-buffering initialization
418 VISetNextFrameBuffer(DemoFrameBuffer1);
419 DemoCurrentBuffer = DemoFrameBuffer2;
420
421 // Tell VI device driver to write the current VI settings so far
422 VIFlush();
423
424 // Wait for retrace to start first frame
425 VIWaitForRetrace();
426
427 // Because of hardware restriction, we need to wait one more
428 // field to make sure mode is safely changed when we change
429 // INT->DS or DS->INT. (VIInit() sets INT mode as a default)
430 if ( (u32)Rmode->viTVmode & 1 )
431 VIWaitForRetrace();
432 }
433
434
435 /*===========================================================================*
436
437
438 Basic demo framework control functions
439
440
441 *===========================================================================*/
442
443 /*---------------------------------------------------------------------------*
444 Name: DEMOBeforeRender
445
446 Description: This function sets up the viewport to render the
447 appropriate field if field rendering is enabled.
448 Field rendering is a property of the render mode.
449
450 Arguments: None
451
452 Returns: None
453 *---------------------------------------------------------------------------*/
DEMOBeforeRender(void)454 void DEMOBeforeRender( void )
455 {
456 // Set up viewport (This is inappropriate for full-frame AA.)
457 if (Rmode->field_rendering)
458 {
459 GXSetViewportJitter(
460 0.0F, 0.0F, (float)Rmode->fbWidth, (float)Rmode->efbHeight,
461 0.0F, 1.0F, VIGetNextField());
462 }
463 else
464 {
465 GXSetViewport(
466 0.0F, 0.0F, (float)Rmode->fbWidth, (float)Rmode->efbHeight,
467 0.0F, 1.0F);
468 }
469
470 // Invalidate vertex cache in GP
471 GXInvalidateVtxCache();
472 // Invalidate texture cache in GP
473 GXInvalidateTexAll();
474 }
475
476 /*---------------------------------------------------------------------------*
477 Name: DEMODoneRender
478
479 Description: This function copies the embedded frame buffer (EFB)
480 to the external frame buffer (XFB) via GXCopyDisp,
481 and then calls DEMOSwapBuffers.
482
483 Arguments: None
484
485 Returns: None
486 *---------------------------------------------------------------------------*/
DEMODoneRender(void)487 void DEMODoneRender( void )
488 {
489 // Set Z/Color update to make sure eFB will be cleared at GXCopyDisp.
490 // (If you want to control these modes by yourself in your application,
491 // please comment out this part.)
492 GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
493 GXSetColorUpdate(GX_TRUE);
494
495 // Issue display copy command
496 GXCopyDisp(DemoCurrentBuffer, GX_TRUE);
497
498 // Wait until everything is drawn and copied into XFB.
499 GXDrawDone();
500
501 // Set the next frame buffer
502 DEMOSwapBuffers();
503 }
504
505 /*---------------------------------------------------------------------------*
506 Name: DEMOSwapBuffers
507
508 Description: This function finishes copying via GXDrawDone, sets
509 the next video frame buffer, waits for vertical
510 retrace, and swaps internal rendering buffers.
511
512 Arguments: None
513
514 Returns: None
515 *---------------------------------------------------------------------------*/
DEMOSwapBuffers(void)516 void DEMOSwapBuffers( void )
517 {
518 // Display the buffer which was just filled by GXCopyDisplay
519 VISetNextFrameBuffer(DemoCurrentBuffer);
520
521 // If this is the first frame, turn off VIBlack
522 if(DemoFirstFrame)
523 {
524 VISetBlack(FALSE);
525 DemoFirstFrame = GX_FALSE;
526 }
527
528 // Tell VI device driver to write the current VI settings so far
529 VIFlush();
530
531 // Wait for vertical retrace.
532 VIWaitForRetrace();
533
534 // Swap buffers
535 if(DemoCurrentBuffer == DemoFrameBuffer1)
536 DemoCurrentBuffer = DemoFrameBuffer2;
537 else
538 DemoCurrentBuffer = DemoFrameBuffer1;
539 }
540
541 /*---------------------------------------------------------------------------*
542 Name: DEMOGetRenderModeObj
543
544 Description: This function returns the current rendering mode.
545 It is most useful to inquire what the default
546 rendering mode is.
547
548 Arguments: None
549
550 Returns: None
551 *---------------------------------------------------------------------------*/
DEMOGetRenderModeObj(void)552 GXRenderModeObj* DEMOGetRenderModeObj( void )
553 {
554 return Rmode;
555 }
556
557 /*---------------------------------------------------------------------------*
558 Name: DEMOGetCurrentBuffer
559
560 Description: This function returns the pointer to external
561 framebuffer currently active. Since this library
562 swiches double buffer DemoFrameBuffer1/DemoFrameBuffer2,
563 the returned pointer will be one of them.
564
565 Arguments: None
566
567 Returns: None
568 *---------------------------------------------------------------------------*/
DEMOGetCurrentBuffer(void)569 void* DEMOGetCurrentBuffer( void )
570 {
571 return DemoCurrentBuffer;
572 }
573
574 /*---------------------------------------------------------------------------*
575 Name: DEMOReInit
576
577 Description: Re-initializes the graphics pipe. Makes no assumptions
578 about the Fifo (allowing you to change it in your program
579 if needed).
580
581 Arguments: mode render mode object
582
583 Returns: None
584 *---------------------------------------------------------------------------*/
DEMOReInit(GXRenderModeObj * mode)585 void DEMOReInit( GXRenderModeObj *mode )
586 {
587 u32 fbSize;
588
589 GXFifoObj realFifoObj;
590 void* realFifoBase;
591 u32 realFifoSize;
592
593 // Get data on current Fifo.
594 GXFlush();
595 GXGetCPUFifo(&realFifoObj);
596 realFifoBase = GXGetFifoBase(&realFifoObj);
597 realFifoSize = GXGetFifoSize(&realFifoObj);
598
599 // Abort the GP
600 GXAbortFrame();
601
602 /*----------------------------------------------------------------*
603 * Initialize Graphics again
604 *----------------------------------------------------------------*/
605 DEMOSetRenderMode(mode);
606
607 // Verify that the previously allocated frame buffer can hold
608 // the new render mode size (Rmode is the global variable).
609 fbSize = VIPadFrameBufferWidth(Rmode->fbWidth) * Rmode->xfbHeight *
610 (u32)VI_DISPLAY_PIX_SZ;
611 ASSERTMSG( fbSize <= allocatedFrameBufferSize, "DEMOReInit - Previously "
612 "allocated frame buffer is too small for the new render mode." );
613
614 // This will re-initialize the pointers for the original FIFO.
615 DemoFifoObj = GXInit(realFifoBase, realFifoSize);
616 DEMOInitGX();
617
618 // NOTE: the VI settings do not necessarily have to be reset, but
619 // just to be safe, we do so anyway
620 DEMOStartVI();
621
622 }
623
624
625 /*===========================================================================*/
626