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