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