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