1 /*---------------------------------------------------------------------------*
2 Project: Dolphin/Revolution gx demo
3 File: mgt-fifo-dual.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 *---------------------------------------------------------------------------*/
14
15 /*---------------------------------------------------------------------------*
16 This demo is a more difficult method to implement dual fifos.
17 Normally, dual fifos are necessary to implement frame-staggered
18 rendering, where the CPU is writing commands to one fifo, while the GP is
19 reading commands from another fifo from the previous frame. An example of
20 this is provided in mgt-fifo-brkpt using ONE single fifo with a breakpoint.
21
22 However, this example of dual fifos is used not to show how to do
23 frame-staggered rendering, but rather to have a basic way of sorting opaque and
24 transparent geometry into two separate fifos. Because GameCube is a
25 Z-buffer machine, in order to draw transparent objects correctly,
26 non-transparent objects need to be rendered first, and then the transparent
27 objects must be rendered according to its depth (from back to front). While this demo does
28 not depth-sort its transparent geometry objects, nor does it work per polygon,
29 it will show how to use two separate fifos for this simple purpose.
30
31 *---------------------------------------------------------------------------*/
32
33 // Local includes
34 #include <demo.h>
35 #include <string.h>
36 #include <stdarg.h>
37
38 // Local constants
39 #define FIFO_SIZE (256*1024)
40 #define NUM_TORUS 11
41
42 // Local structures
43 typedef enum
44 {
45 FIFO_0_1 = 0,
46 FIFO_1_0,
47 FIFO_0,
48 FIFO_1,
49 FIFO_NONE // Not a valid option for this demo
50
51 } FifoModeEnum;
52
53 typedef struct
54 {
55 GXColor color; // Used to test for transparency as well
56
57 Vec translation;
58 Vec rotation;
59
60 } GeomObj;
61
62 // Forward references
63 static void FifoInit ( );
64 static void TorusInit ( );
65 static void CameraInit ( Mtx v );
66 static void DrawInit ( );
67 static void FifoCPUSwitch ( u32 fifoID );
68 static void FifoGPSwitch ( u32 fifoID );
69 static void FlushFifo ( u32 fifoID );
70 static void DiscardFifo ( u32 fifoID );
71 static void AnimTick ( );
72 static void DrawTick ( Mtx v );
73 static void DrawUI ( );
74 static void DoneRender ( );
75
76 // Local variables
77 static GXRenderModeObj *RenderMode = &GXNtsc480Int;
78
79 static GXFifoObj Fifo[2]; // Fifo0 is for opaque objects, Fifo1 for transparent
80 static s32 FifoCPUID = -1; // Current CPU Fifo ID
81 static s32 FifoGPID = -1; // Current GP Fifo ID
82 static FifoModeEnum FifoMode = FIFO_NONE; // Current Fifo Mode
83
84 static f32 StartRotX = 0.0f; // starting rotation angle on x-axis for torus
85 static GXCullMode CullMode = GX_CULL_BACK;
86 static GeomObj Torus[NUM_TORUS];
87
88 static GXColor Colors[] ATTRIBUTE_ALIGN(32) =
89 {
90 { 0, 0, 0, 255 }, // 0 black
91 { 0, 0, 255, 255 }, // 1 blue
92 { 255, 128, 0, 128 }, // 2 orange
93 };
94
95
96 /*---------------------------------------------------------------------------*
97 Name: main
98
99 Description: The main application loop
100
101 Arguments: none
102
103 Returns: none
104 *----------------------------------------------------------------------------*/
105 void
main(void)106 main ( void )
107 {
108 Mtx v; // view matrix
109
110 // Init os, pad, gx, vi
111 DEMOInit( RenderMode );
112
113 OSReport("\n\n");
114 OSReport("**********************************************\n");
115 OSReport("mgt-fifo-dual: Dual FIFO demo\n");
116 OSReport("**********************************************\n");
117 OSReport("To quit hit the start button.\n");
118 OSReport("\n");
119 OSReport("Main stick rotates model.\n");
120 OSReport("Press the A button to switch FIFO modes.\n");
121 OSReport("Press the B button to switch cull modes.\n");
122 OSReport("**********************************************\n");
123 OSReport("\n\n");
124
125 // Create the torus objects
126 TorusInit();
127
128 GXSetDispCopyGamma( GX_GM_1_0 );
129 GXSetCopyClear( Colors[0], GX_MAX_Z24 );
130
131 // Must be last function before main loop
132 FifoInit();
133
134 while( !(DEMOPadGetButton(0) & PAD_BUTTON_MENU) )
135 {
136 // AnimTick should not send any GX commands
137 AnimTick();
138
139 // CameraInit and DrawInit commands should be processed by GP first,
140 // so pick the correct fifo to be drawn first depending on fifo modes
141 if( FifoMode == FIFO_0 || FifoMode == FIFO_0_1 )
142 {
143 FifoCPUSwitch( 0 );
144
145 // GP should be idle, so allow GP to process early as possible
146 FifoGPSwitch( 0 );
147 }
148 else // ( FifoMode == FIFO_1 || FifoMode == FIFO_1_0 )
149 {
150 FifoCPUSwitch( 1 );
151
152 // GP should be idle, so allow GP to process early as possible
153 FifoGPSwitch( 1 );
154 }
155
156 // Initialize camera and GX state again (DrawUI changes GX state for fonts)
157 CameraInit( v );
158 DrawInit();
159
160 DEMOBeforeRender();
161
162 // Draw toruses. Switch fifos appropriately in this functions
163 DrawTick( v );
164
165 // Should draw text last, so pick the correct fifo depending on fifo mode
166 if( FifoMode == FIFO_0 || FifoMode == FIFO_1_0 )
167 FifoCPUSwitch( 0 );
168 else // ( FifoMode == FIFO_0_1 || FifoMode == FIFO_1 )
169 FifoCPUSwitch( 1 );
170
171 // Draw text onto the screen
172 DrawUI();
173
174 // Finish drawing fifos, and copy EFB to XFB.
175 DoneRender();
176 }
177
178 OSHalt("End of demo");
179 }
180
181
182 /*---------------------------------------------------------------------------*
183 Name: FifoInit
184
185 Description: Initialize the two new fifos (reuse the default fifo).
186 This function should be called just before the main loop
187 since the top of the main loop will set the CPU and GP
188 fifos.
189
190 Arguments: none
191
192 Returns: none
193 *----------------------------------------------------------------------------*/
194 static void
FifoInit()195 FifoInit( )
196 {
197 GXDrawDone();
198
199 // Set Fifo0 to be the default fifo
200 GXGetGPFifo(&Fifo[0]);
201
202 // Set Fifo1 to a newly allocated fifo
203 GXInitFifoBase( &Fifo[1], MEMAllocFromAllocator(&DemoAllocator1, FIFO_SIZE), FIFO_SIZE );
204
205 // Default mode is Fifo0 then Fifo1 (draw opaque objects first, then transparent)
206 FifoMode = FIFO_0_1;
207
208 FifoCPUID = 0;
209 FifoGPID = 0;
210
211 // CPU and GP fifos will be updated at the top of the main loop
212 }
213
214
215 /*---------------------------------------------------------------------------*
216 Name: TorusInit
217
218 Description: Initialize the torus objects.
219
220 Arguments: none
221
222 Returns: none
223 *----------------------------------------------------------------------------*/
224 static void
TorusInit()225 TorusInit()
226 {
227 u32 i;
228
229 memset( Torus, 0, sizeof(GeomObj) * NUM_TORUS );
230 for( i = 0; i < NUM_TORUS; i++ )
231 {
232 if( i % 2 )
233 Torus[i].color = Colors[2];
234 else
235 Torus[i].color = Colors[1];
236
237 Torus[i].translation.x = -5.0f + i;
238 Torus[i].rotation.x = i * 36.0f;
239 }
240 }
241
242
243 /*---------------------------------------------------------------------------*
244 Name: CameraInit
245
246 Description: Initialize the projection matrix and load into hardware.
247 Initialize the view matrix.
248
249 Arguments: v - view matrix
250
251 Returns: none
252 *---------------------------------------------------------------------------*/
253 static void
CameraInit(Mtx v)254 CameraInit( Mtx v )
255 {
256 Vec camPt = {0.0F, 0.0F, 12.0F};
257 Vec at = {0.0F, 0.0F, 0.0F};
258 Vec up = {0.0F, 1.0F, 0.0F};
259 Mtx44 p;
260
261 // Load the projection matrix
262 MTXPerspective( p, 45.0f, 4.0f / 3.0f, 1.0f, 1000.0f );
263 GXSetProjection( p, GX_PERSPECTIVE );
264
265 // Create the camera (view) matrix
266 MTXLookAt( v, &camPt, &up, &at );
267 }
268
269
270 /*---------------------------------------------------------------------------*
271 Name: DrawInit
272
273 Description: Initialize GX state for torus objects
274
275 Arguments: none
276
277 Returns: none
278 *----------------------------------------------------------------------------*/
279 static void
DrawInit()280 DrawInit()
281 {
282 // Set the blend mode for transparency
283 GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR );
284 GXSetAlphaCompare( GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 );
285 GXSetZCompLoc( GX_FALSE );
286
287 // Rasterize 1 material color (no light and texture)
288 GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
289 GXSetChanCtrl( GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
290 GXSetNumChans( 1 );
291 GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
292 GXSetNumTexGens( 0 );
293
294 // Clear the VCD (GxDrawTorus will set it manually)
295 GXClearVtxDesc();
296
297 // Set the cull mode (controlled by user)
298 GXSetCullMode( CullMode );
299 }
300
301
302 /*---------------------------------------------------------------------------*
303 Name: FifoCPUSwitch
304
305 Description: Switch the CPU fifo if different than current CPU fifo.
306
307 Arguments: fifoID - 0 for opaque fifo
308 1 for transparent fifo
309
310 Returns: none
311 *----------------------------------------------------------------------------*/
312 static void
FifoCPUSwitch(u32 fifoID)313 FifoCPUSwitch( u32 fifoID )
314 {
315 if( FifoCPUID != fifoID )
316 {
317 GXFlush();
318 GXGetCPUFifo( &Fifo[FifoCPUID] );
319 GXSetCPUFifo( &Fifo[fifoID] );
320 FifoCPUID = (s32)fifoID;
321 }
322 }
323
324
325 /*---------------------------------------------------------------------------*
326 Name: FifoGPSwitch
327
328 Description: Swith the GP fifo if different than current GP fifo.
329 Must make sure the GP is idle (should check with GXDrawDone,
330 and not draw sync tokens) before switching GP.
331
332 Arguments: fifoID - 0 for opaque fifo
333 1 for transparent fifo
334
335 Returns: none
336 *----------------------------------------------------------------------------*/
337 static void
FifoGPSwitch(u32 fifoID)338 FifoGPSwitch( u32 fifoID )
339 {
340 // GP should not be processing anything for safety
341
342 if( FifoGPID != fifoID )
343 {
344 GXGetGPFifo( &Fifo[FifoGPID] );
345 GXSetGPFifo( &Fifo[fifoID] );
346 FifoGPID = (s32)fifoID;
347 }
348 }
349
350 /*---------------------------------------------------------------------------*
351 Name: FlushFifo
352
353 Description: Wait until all commands in specified fifo to be drawn.
354
355 Arguments: fifoID - 0 for opaque fifo
356 1 for transparent fifo
357
358 Returns: none
359 *----------------------------------------------------------------------------*/
360 static void
FlushFifo(u32 fifoID)361 FlushFifo( u32 fifoID )
362 {
363 FifoCPUSwitch( fifoID );
364 FifoGPSwitch( fifoID );
365 GXDrawDone();
366 }
367
368 /*---------------------------------------------------------------------------*
369 Name: DiscardFifo
370
371 Description: Discard all graphics commands in specified fifo.
372
373 Arguments: fifoID - 0 for opaque fifo
374 1 for transparent fifo
375
376 Returns: none
377 *----------------------------------------------------------------------------*/
378 static void
DiscardFifo(u32 fifoID)379 DiscardFifo( u32 fifoID )
380 {
381 void *readPtr;
382 void *writePtr;
383
384 GXGetFifoPtrs( &Fifo[fifoID], &readPtr, &writePtr );
385 GXInitFifoPtrs( &Fifo[fifoID], readPtr, readPtr );
386 }
387
388 /*---------------------------------------------------------------------------*
389 Name: AnimTick
390
391 Description: Animate the scene depending on user input.
392
393 Arguments: none
394
395 Returns: none
396 *----------------------------------------------------------------------------*/
397 static void
AnimTick()398 AnimTick()
399 {
400 DEMOPadRead();
401
402 if( DEMOPadGetButtonDown(0) & PAD_BUTTON_A )
403 {
404 FifoMode = (FifoModeEnum)((FifoMode + 1) % 4);
405 }
406
407 if( DEMOPadGetButtonDown(0) & PAD_BUTTON_B )
408 {
409 CullMode = (GXCullMode)((CullMode + 1) % 3);
410 }
411
412 if( DEMOPadGetStickY(0) )
413 {
414 StartRotX += DEMOPadGetStickY(0) / 12.0f;
415 }
416 }
417
418
419 /*---------------------------------------------------------------------------*
420 Name: DrawTick
421
422 Description: Draw the toruses to the appropriate fifos.
423
424 Arguments: none
425
426 Returns: none
427 *----------------------------------------------------------------------------*/
428 static void
DrawTick(Mtx v)429 DrawTick( Mtx v )
430 {
431 Mtx t; // translation matrix
432 Mtx rx; // rotation matrix
433 u32 i;
434
435 for( i = 0; i < NUM_TORUS; i++ )
436 {
437 if( Torus[i].color.a == 255 )
438 {
439 // Object is opaque but current fifo is transparent fifo,
440 // so switch to opaque fifo.
441 FifoCPUSwitch( 0 );
442 }
443 else if( Torus[i].color.a != 255 )
444 {
445 // Object is transparent but current fifo is opaque fifo,
446 // so switch to transparent fifo.
447 FifoCPUSwitch( 1 );
448 }
449
450 // Change the material color of the torus
451 GXSetChanMatColor( GX_COLOR0A0, Torus[i].color );
452
453 // Load in the modelview matrix
454 MTXRotDeg( rx, 'X', Torus[i].rotation.x + StartRotX );
455 MTXTrans( t, Torus[i].translation.x, Torus[i].translation.y, Torus[i].translation.z );
456 MTXConcat( t, rx, rx );
457 MTXConcat( v, rx, t );
458 GXLoadPosMtxImm( t, GX_PNMTX0 );
459
460 // Draw torus
461 GXDrawTorus( 0.25f, 10, 17 );
462 }
463 }
464
465 /*---------------------------------------------------------------------------*
466 Name: DrawUI
467
468 Description: Draw text into the viewport to display current state.
469
470 Arguments: none
471
472 Returns: none
473 *----------------------------------------------------------------------------*/
474 static void
DrawUI()475 DrawUI()
476 {
477 s16 textX = 20;
478 s16 textY = 430;
479 char *text;
480
481 // Initialize GX for drawing text
482 DEMOInitCaption( DM_FT_OPQ, RenderMode->fbWidth, RenderMode->xfbHeight );
483
484 // So text is not culled out
485 GXSetCullMode( GX_CULL_NONE );
486
487 // Print current cull mode
488 switch( CullMode )
489 {
490 case GX_CULL_NONE:
491 text = "GX_CULL_NONE";
492 break;
493 case GX_CULL_FRONT:
494 text = "GX_CULL_FRONT";
495 break;
496 case GX_CULL_BACK:
497 text = "GX_CULL_BACK";
498 break;
499 case GX_CULL_ALL:
500 text = "GX_CULL_ALL";
501 break;
502 }
503 DEMOPrintf( textX, textY, 0, "B button: Cull Mode: %s", text );
504
505 // Print current fifo mode
506 textY += 9;
507 switch( FifoMode )
508 {
509 case FIFO_0_1:
510 text = "Fifo0 (opaque) then Fifo1 (transparent)";
511 break;
512 case FIFO_1_0:
513 text = "Fifo1 (transparent) then Fifo0 (opaque)";
514 break;
515 case FIFO_0:
516 text = "Fifo0 only";
517 break;
518 case FIFO_1:
519 text = "Fifo1 only";
520 break;
521 }
522 DEMOPrintf( textX, textY, 0, "A button: Fifo Mode: %s", text );
523 }
524
525
526 /*---------------------------------------------------------------------------*
527 Name: DoneRender
528
529 Description: Finishes rendering fifos. Copies copies embedded frame buffer (EFB)
530 to external frame buffer (XFB).
531
532 Arguments: None
533
534 Returns: None
535 *---------------------------------------------------------------------------*/
536 static void
DoneRender()537 DoneRender( )
538 {
539 extern void *DemoCurrentBuffer;
540
541 // Depending on current fifo mode, draw the fifos in proper order
542
543 // Draw Fifo0
544 switch ( FifoMode )
545 {
546 case FIFO_0_1 :
547 {
548 FlushFifo( 0 );
549 FlushFifo( 1 );
550 } break;
551 case FIFO_1_0 :
552 {
553 FlushFifo( 1 );
554 FlushFifo( 0 );
555 } break;
556 case FIFO_0 :
557 {
558 FlushFifo( 0 );
559 DiscardFifo( 1 );
560 } break;
561 case FIFO_1 :
562 {
563 FlushFifo( 1 );
564 DiscardFifo( 0 );
565 } break;
566 }
567
568 // Set Z/Color update to make sure eFB will be cleared at GXCopyDisp.
569 GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
570 GXSetColorUpdate(GX_TRUE);
571
572 // Issue display copy command
573 GXCopyDisp(DemoCurrentBuffer, GX_TRUE);
574
575 // Wait until everything is drawn and copied into XFB.
576 GXDrawDone();
577
578 // Set the next frame buffer
579 DEMOSwapBuffers();
580 }
581
582
583