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