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