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