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