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