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