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     // Create the torus objects
114     TorusInit();
115 
116     GXSetDispCopyGamma( GX_GM_1_0 );
117     GXSetCopyClear( Colors[0], GX_MAX_Z24 );
118 
119     // Must be last function before main loop
120     FifoInit();
121 
122     while( !(DEMOPadGetButton(0) & PAD_BUTTON_MENU) )
123     {
124         // AnimTick should not send any GX commands
125         AnimTick();
126 
127         // CameraInit and DrawInit commands should be processed by GP first,
128         // so pick the correct fifo to be drawn first depending on fifo modes
129         if( FifoMode == FIFO_0 || FifoMode == FIFO_0_1 )
130         {
131             FifoCPUSwitch( 0 );
132 
133             // GP should be idle, so allow GP to process early as possible
134             FifoGPSwitch( 0 );
135         }
136         else // ( FifoMode == FIFO_1 || FifoMode == FIFO_1_0 )
137         {
138             FifoCPUSwitch( 1 );
139 
140             // GP should be idle, so allow GP to process early as possible
141             FifoGPSwitch( 1 );
142         }
143 
144         // Initialize camera and GX state again (DrawUI changes GX state for fonts)
145         CameraInit( v );
146         DrawInit();
147 
148         DEMOBeforeRender();
149 
150         // Draw tori.  Switch fifos appropriately in this functions
151         DrawTick( v );
152 
153         // Should draw text last, so pick the correct fifo depending on fifo mode
154         if( FifoMode == FIFO_0 || FifoMode == FIFO_1_0 )
155             FifoCPUSwitch( 0 );
156         else // ( FifoMode == FIFO_0_1 || FifoMode == FIFO_1 )
157             FifoCPUSwitch( 1 );
158 
159         // Draw text onto the screen
160         DrawUI();
161 
162         // Finish drawing fifos, and copy EFB to XFB.
163         DoneRender();
164     }
165 
166     OSHalt("End of demo");
167 }
168 
169 
170 /*---------------------------------------------------------------------------*
171     Name:           FifoInit
172 
173     Description:    Initialize the two new fifos (reuse the default fifo).
174                     This function should be called just before the main loop
175                     since the top of the main loop will set the CPU and GP
176                     fifos.
177 
178     Arguments:      none
179 
180     Returns:        none
181 *----------------------------------------------------------------------------*/
182 static void
FifoInit()183 FifoInit( )
184 {
185     GXDrawDone();
186 
187     // Set Fifo0 to be the default fifo
188     GXGetGPFifo(&Fifo[0]);
189 
190     // Set Fifo1 to a newly allocated fifo
191     GXInitFifoBase( &Fifo[1], MEMAllocFromAllocator(&DemoAllocator1, FIFO_SIZE), FIFO_SIZE );
192 
193     // Default mode is Fifo0 then Fifo1 (draw opaque objects first, then transparent)
194     FifoMode = FIFO_0_1;
195 
196     FifoCPUID = 0;
197     FifoGPID = 0;
198 
199     // CPU and GP fifos will be updated at the top of the main loop
200 }
201 
202 
203 /*---------------------------------------------------------------------------*
204     Name:           TorusInit
205 
206     Description:    Initialize the torus objects.
207 
208     Arguments:      none
209 
210     Returns:        none
211 *----------------------------------------------------------------------------*/
212 static void
TorusInit()213 TorusInit()
214 {
215     u32 i;
216 
217     memset( Torus, 0, sizeof(GeomObj) * NUM_TORUS );
218     for( i = 0; i < NUM_TORUS; i++ )
219     {
220         if( i % 2 )
221             Torus[i].color = Colors[2];
222         else
223             Torus[i].color = Colors[1];
224 
225         Torus[i].translation.x = -5.0f + i;
226         Torus[i].rotation.x = i * 36.0f;
227     }
228 }
229 
230 
231 /*---------------------------------------------------------------------------*
232     Name:           CameraInit
233 
234     Description:    Initialize the projection matrix and load into hardware.
235                     Initialize the view matrix.
236 
237     Arguments:      v - view matrix
238 
239     Returns:        none
240  *---------------------------------------------------------------------------*/
241 static void
CameraInit(Mtx v)242 CameraInit( Mtx v )
243 {
244     Vec   camPt = {0.0F, 0.0F, 12.0F};
245     Vec   at    = {0.0F, 0.0F, 0.0F};
246     Vec   up    = {0.0F, 1.0F, 0.0F};
247     Mtx44 p;
248 
249     // Load the projection matrix
250     MTXPerspective( p, 45.0f, 4.0f / 3.0f, 1.0f, 1000.0f );
251     GXSetProjection( p, GX_PERSPECTIVE );
252 
253     // Create the camera (view) matrix
254     MTXLookAt( v, &camPt, &up, &at );
255 }
256 
257 
258 /*---------------------------------------------------------------------------*
259     Name:           DrawInit
260 
261     Description:    Initialize GX state for torus objects
262 
263     Arguments:      none
264 
265     Returns:        none
266 *----------------------------------------------------------------------------*/
267 static void
DrawInit()268 DrawInit()
269 {
270     // Set the blend mode for transparency
271     GXSetBlendMode( GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR );
272     GXSetAlphaCompare( GX_GREATER, 0, GX_AOP_AND, GX_GREATER, 0 );
273     GXSetZCompLoc( GX_FALSE );
274 
275     // Rasterize 1 material color (no light and texture)
276     GXSetTevOp( GX_TEVSTAGE0, GX_PASSCLR );
277     GXSetChanCtrl( GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE );
278     GXSetNumChans( 1 );
279     GXSetTevOrder( GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0 );
280     GXSetNumTexGens( 0 );
281 
282     // Clear the VCD (GxDrawTorus will set it manually)
283     GXClearVtxDesc();
284 
285     // Set the cull mode (controlled by user)
286     GXSetCullMode( CullMode );
287 }
288 
289 
290 /*---------------------------------------------------------------------------*
291     Name:           FifoCPUSwitch
292 
293     Description:    Switch the CPU fifo if different than current CPU fifo.
294 
295     Arguments:      fifoID - 0 for opaque fifo
296                              1 for transparent fifo
297 
298     Returns:        none
299 *----------------------------------------------------------------------------*/
300 static void
FifoCPUSwitch(u32 fifoID)301 FifoCPUSwitch( u32 fifoID )
302 {
303     if( FifoCPUID != fifoID )
304     {
305 		GXFlush();
306         GXGetCPUFifo( &Fifo[FifoCPUID] );
307         GXSetCPUFifo( &Fifo[fifoID] );
308         FifoCPUID = (s32)fifoID;
309     }
310 }
311 
312 
313 /*---------------------------------------------------------------------------*
314     Name:           FifoGPSwitch
315 
316     Description:    Swath the GP fifo if different than current GP fifo.
317                     Must make sure the GP is idle (should check with GXDrawDone,
318                     and not draw sync tokens) before switching GP.
319 
320     Arguments:      fifoID - 0 for opaque fifo
321                              1 for transparent fifo
322 
323     Returns:        none
324 *----------------------------------------------------------------------------*/
325 static void
FifoGPSwitch(u32 fifoID)326 FifoGPSwitch( u32 fifoID )
327 {
328     // GP should not be processing anything for safety
329 
330     if( FifoGPID != fifoID )
331     {
332         GXGetGPFifo( &Fifo[FifoGPID] );
333         GXSetGPFifo( &Fifo[fifoID] );
334         FifoGPID = (s32)fifoID;
335     }
336 }
337 
338 /*---------------------------------------------------------------------------*
339     Name:           FlushFifo
340 
341     Description:    Wait until all commands in specified fifo to be drawn.
342 
343     Arguments:      fifoID - 0 for opaque fifo
344                              1 for transparent fifo
345 
346     Returns:        none
347 *----------------------------------------------------------------------------*/
348 static void
FlushFifo(u32 fifoID)349 FlushFifo( u32 fifoID )
350 {
351 	FifoCPUSwitch( fifoID );
352 	FifoGPSwitch( fifoID );
353 	GXDrawDone();
354 }
355 
356 /*---------------------------------------------------------------------------*
357     Name:           DiscardFifo
358 
359     Description:    Discard all graphics commands in specified fifo.
360 
361     Arguments:      fifoID - 0 for opaque fifo
362                              1 for transparent fifo
363 
364     Returns:        none
365 *----------------------------------------------------------------------------*/
366 static void
DiscardFifo(u32 fifoID)367 DiscardFifo( u32 fifoID )
368 {
369     void *readPtr;
370     void *writePtr;
371 
372     GXGetFifoPtrs( &Fifo[fifoID], &readPtr, &writePtr );
373     GXInitFifoPtrs( &Fifo[fifoID], readPtr, readPtr );
374 }
375 
376 /*---------------------------------------------------------------------------*
377     Name:           AnimTick
378 
379     Description:    Animate the scene depending on user input.
380 
381     Arguments:      none
382 
383     Returns:        none
384 *----------------------------------------------------------------------------*/
385 static void
AnimTick()386 AnimTick()
387 {
388     DEMOPadRead();
389 
390     if( DEMOPadGetButtonDown(0) & PAD_BUTTON_A )
391     {
392         FifoMode = (FifoModeEnum)((FifoMode + 1) % 4);
393     }
394 
395     if( DEMOPadGetButtonDown(0) & PAD_BUTTON_B )
396     {
397         CullMode = (GXCullMode)((CullMode + 1) % 3);
398     }
399 
400     if( DEMOPadGetStickY(0) )
401     {
402         StartRotX += DEMOPadGetStickY(0) / 12.0f;
403     }
404 }
405 
406 
407 /*---------------------------------------------------------------------------*
408     Name:           DrawTick
409 
410     Description:    Draw the tori to the appropriate fifos.
411 
412     Arguments:      none
413 
414     Returns:        none
415 *----------------------------------------------------------------------------*/
416 static void
DrawTick(Mtx v)417 DrawTick( Mtx v )
418 {
419     Mtx         t;       // translation matrix
420     Mtx         rx;      // rotation matrix
421     u32         i;
422 
423     for( i = 0; i < NUM_TORUS; i++ )
424     {
425         if( Torus[i].color.a == 255 )
426         {
427             // Object is opaque but current fifo is transparent fifo,
428             // so switch to opaque fifo.
429             FifoCPUSwitch( 0 );
430         }
431         else if( Torus[i].color.a != 255 )
432         {
433             // Object is transparent but current fifo is opaque fifo,
434             // so switch to transparent fifo.
435             FifoCPUSwitch( 1 );
436         }
437 
438         // Change the material color of the torus
439         GXSetChanMatColor( GX_COLOR0A0, Torus[i].color );
440 
441         // Load in the modelview matrix
442         MTXRotDeg( rx, 'X', Torus[i].rotation.x + StartRotX );
443         MTXTrans( t, Torus[i].translation.x, Torus[i].translation.y, Torus[i].translation.z );
444         MTXConcat( t, rx, rx );
445         MTXConcat( v, rx, t );
446         GXLoadPosMtxImm( t, GX_PNMTX0 );
447 
448         // Draw torus
449         GXDrawTorus( 0.25f, 10, 17 );
450     }
451 }
452 
453 /*---------------------------------------------------------------------------*
454     Name:           DrawUI
455 
456     Description:    Draw text into the viewport to display current state.
457 
458     Arguments:      none
459 
460     Returns:        none
461 *----------------------------------------------------------------------------*/
462 static void
DrawUI()463 DrawUI()
464 {
465     s16   textX = 20;
466     s16   textY = 430;
467     char *text;
468 
469     // Initialize GX for drawing text
470     DEMOInitCaption( DM_FT_OPQ, RenderMode->fbWidth, RenderMode->xfbHeight );
471 
472     // So text is not culled out
473     GXSetCullMode( GX_CULL_NONE );
474 
475     // Print current cull mode
476     switch( CullMode )
477     {
478         case GX_CULL_NONE:
479             text = "GX_CULL_NONE";
480             break;
481         case GX_CULL_FRONT:
482             text = "GX_CULL_FRONT";
483             break;
484         case GX_CULL_BACK:
485             text = "GX_CULL_BACK";
486             break;
487         case GX_CULL_ALL:
488             text = "GX_CULL_ALL";
489             break;
490     }
491     DEMOPrintf( textX, textY, 0, "B button: Cull Mode: %s", text );
492 
493     // Print current fifo mode
494     textY += 9;
495     switch( FifoMode )
496     {
497         case FIFO_0_1:
498             text = "Fifo0 (opaque) then Fifo1 (transparent)";
499             break;
500         case FIFO_1_0:
501             text = "Fifo1 (transparent) then Fifo0 (opaque)";
502             break;
503         case FIFO_0:
504             text = "Fifo0 only";
505             break;
506         case FIFO_1:
507             text = "Fifo1 only";
508             break;
509     }
510     DEMOPrintf( textX, textY, 0, "A button: Fifo Mode: %s", text );
511 }
512 
513 
514 /*---------------------------------------------------------------------------*
515     Name:           DoneRender
516 
517     Description:    Finishes rendering fifos.  Copies copies embedded frame buffer (EFB)
518                     to external frame buffer (XFB).
519 
520     Arguments:      None
521 
522     Returns:        None
523  *---------------------------------------------------------------------------*/
524 static void
DoneRender()525 DoneRender( )
526 {
527     extern void *DemoCurrentBuffer;
528 
529     // Depending on current fifo mode, draw the fifos in proper order
530 
531     // Draw Fifo0
532     switch ( FifoMode )
533     {
534 	  case FIFO_0_1 :
535 	    {
536 			FlushFifo( 0 );
537 			FlushFifo( 1 );
538 		} break;
539 	  case FIFO_1_0 :
540 	    {
541 			FlushFifo( 1 );
542 			FlushFifo( 0 );
543 		} break;
544 	  case FIFO_0 :
545 	    {
546 			FlushFifo( 0 );
547 			DiscardFifo( 1 );
548 		} break;
549 	  case FIFO_1 :
550 	    {
551 			FlushFifo( 1 );
552 			DiscardFifo( 0 );
553 		} break;
554 	}
555 
556     // Set Z/Color update to make sure eFB will be cleared at GXCopyDisp.
557     GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE);
558     GXSetColorUpdate(GX_TRUE);
559 
560     // Issue display copy command
561     GXCopyDisp(DemoCurrentBuffer, GX_TRUE);
562 
563     // Wait until everything is drawn and copied into XFB.
564     GXDrawDone();
565 
566     // Set the next frame buffer
567     DEMOSwapBuffers();
568 }
569 
570 
571