1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     mgt-fifo-brkpt.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 based on the smp-texexample demo, except we animate to make
17   it clear that this code actually works.
18 
19   We use ONE fifo to hold TWO frames' data.  One of the frames is
20   being consumed by the GP.  The other is being produced by the CPU.
21 
22   We prevent the GP from starting on the second frame prematurely by
23   placing a FIFO breakpoint right where the CPU is about to start
24   writing the next frame (see FifoTick).
25 
26   We prevent the CPU from starting on a third frame by synchronizing
27   with the GP.  Since we cannot rely on GXDrawDone, we poll with
28   GXReadDrawSync (see MyDEMODoneRender).
29 
30   There is no need to worry about the CPU trampling over the data the
31   GP hasn't read yet - the high watermark interrupt will get triggered
32   before that.
33 
34   Look at FifoInit to see how we re-allocate the FIFO object, because
35   in a real application, the default fifo might not be large enough to
36   hold 2 frames worth of command data.
37  *---------------------------------------------------------------------------*/
38 
39 #include <demo.h>
40 
41 #define BALL64_TEX_ID        8
42 
43 #define BIG_FIFO_SIZE        (512*1024)
44 #define FIFO_DRAWDONE_TOKEN  0xBEEF
45 #define FIFO_DRAWING_TOKEN   0xB00B
46 
47 /*---------------------------------------------------------------------------*
48   Model Data
49  *---------------------------------------------------------------------------*/
50 
51 static s8 Vert_s8[] ATTRIBUTE_ALIGN(32) =
52 {
53     -100,  100, 0,  // 0
54      100,  100, 0,  // 1
55     -100, -100, 0   // 2
56 };
57 
58 static u32 Colors_u32[] ATTRIBUTE_ALIGN(32) =
59 {
60 //    r g b a
61     0xff0000ff, // 0
62     0x00ff00ff, // 1
63     0x0000ffff  // 2
64 };
65 
66 //  Array of texture coordinates
67 static u8 TexCoords_u8[] ATTRIBUTE_ALIGN(32) =
68 {
69     0x00, 0x00, // 0
70 //    s     t        fixed point format is unsigned 8.0
71     0x01, 0x00, // 1
72     0x00, 0x01  // 2
73 };
74 
75 /*---------------------------------------------------------------------------*
76    Forward references
77  *---------------------------------------------------------------------------*/
78 static void FifoInit            ( GXFifoObj* fifo );
79 static void FifoTick            ( void );
80 static void MyDEMODoneRender    ( void );
81 static void CameraInit          ( Mtx v );
82 
83 /*---------------------------------------------------------------------------*
84    Application main loop
85  *---------------------------------------------------------------------------*/
main(void)86 void main ( void )
87 {
88     PADStatus     pad[4];  // game pad state
89     GXFifoObj     appFifo; // fifo object
90     GXTexObj      texObj;  // texture object
91     Mtx           v;       // view matrix
92     Mtx           r;       // rotation matrix
93     u8            i;       // loop variable
94     u32           deg;     // rotation angle
95     TPLPalettePtr tpl = 0; // texture palette
96 
97     pad[0].button = 0;
98 
99     DEMOInit(NULL);    // Init os, pad, gx, vi
100     FifoInit(&appFifo);
101 
102     CameraInit(v);
103 
104     GXSetNumChans(1);  // Enable light channel; by default = vertex color
105 
106     GXClearVtxDesc();
107     GXSetVtxDesc(GX_VA_POS,  GX_INDEX8);
108     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
109     // Add an indexed texture coordinate to the vertex description
110     GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
111 
112     GXSetArray(GX_VA_POS,  Vert_s8, 3*sizeof(s8));
113     GXSetArray(GX_VA_CLR0, Colors_u32, 1*sizeof(u32));
114     GXSetArray(GX_VA_TEX0, TexCoords_u8, 2*sizeof(u8));
115 
116     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS,  GX_POS_XYZ,  GX_S8,    0);
117     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
118     //  Describe the texture coordinate format
119     //  fixed point format is unsigned 8.0
120     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST,   GX_U8,    0);
121 
122     //  Load the texture palette
123     TPLGetPalette(&tpl, "gxTextrs.tpl");
124     //  Initialize a texture object to contain the correct texture
125     TPLGetGXTexObjFromPalette(tpl, &texObj, BALL64_TEX_ID);
126     //  Load the texture object; tex0 is used in stage 0
127     GXLoadTexObj(&texObj, GX_TEXMAP0);
128 
129     //  Set the Texture Environment (Tev) Mode for stage 0
130     //  GXInit sets default of 1 TexCoordGen
131     //  Default TexCoordGen is texcoord(n) from tex(n) with 2x4 identity mtx
132     //  Default number of tev stages is 1
133     //  Default stage0 uses texcoord0, texmap0, color0a0
134     //  Only need to change the tevop
135     GXSetTevOp(GX_TEVSTAGE0, GX_DECAL);
136 
137     OSReport("\n\n********************************\n");
138     OSReport("to quit:\n");
139     OSReport("     hit the start button\n");
140     OSReport("********************************\n");
141 
142     deg = 0;
143 
144     while(!(pad[0].button & PAD_BUTTON_MENU))
145     {
146         FifoTick();
147 
148         DEMOBeforeRender();
149 
150         MTXRotDeg( r, 'Y', deg++);
151         MTXConcat(v, r, r);
152         GXLoadPosMtxImm(r, GX_PNMTX0);
153 
154         // Draw a triangle, front and back
155         GXBegin(GX_TRIANGLES, GX_VTXFMT0, 3);
156         for (i = 0; i < 3; i++)
157         {
158             GXPosition1x8(i);
159             GXColor1x8(i);
160             // Add texture coordinate
161             GXTexCoord1x8(i);
162         }
163         GXEnd();
164         GXBegin(GX_TRIANGLES, GX_VTXFMT0, 3);
165         for (i = 0; i < 3; i++)
166         {
167             GXPosition1x8   ((u8)(2 - i));
168             GXColor1x8      ((u8)(2 - i));
169             // Add texture coordinate
170             GXTexCoord1x8   ((u8)(2 - i));
171         }
172         GXEnd();
173         MyDEMODoneRender();
174         PADRead(pad);
175     }
176 
177     OSHalt("End of demo");
178 }
179 
180 /*---------------------------------------------------------------------------*
181    Functions
182  *---------------------------------------------------------------------------*/
183 
184 /*---------------------------------------------------------------------------*
185     Name:           CameraInit
186 
187     Description:    Initialize the projection matrix and load into hardware.
188                     Initialize the view matrix
189 
190     Arguments:      v    view matrix
191 
192     Returns:        none
193  *---------------------------------------------------------------------------*/
194 
CameraInit(Mtx v)195 static void CameraInit ( Mtx v )
196 {
197     Mtx44 p;
198     Vec   camPt = {0.0F, 0.0F, 800.0F};
199     Vec   at    = {0.0F, 0.0F, -100.0F};
200     Vec   up    = {0.0F, 1.0F, 0.0F};
201 
202     MTXFrustum(p, 240.0F,-240.0F,-320.0F, 320.0F, 500, 2000);
203     GXSetProjection(p, GX_PERSPECTIVE);
204     MTXLookAt(v, &camPt, &up, &at);
205 }
206 
207 /*---------------------------------------------------------------------------*
208     Name:           MyDEMODoneRender()
209 
210     Description:    rewrite of DEMODoneRender function - performs post-rendering operations.
211                     receives a stopwatch activated at the top of the 'main' demoloop.
212                     checks stopwatch after GXDrawDone and before VIWaitForRetrace to
213                     compute actual frame rendering time in milliseconds.
214 
215     Arguments:      globals:  writes DemoFrameBuffer1,
216                               writes DemoFrameBuffer2,
217                               writes DemoCurrentBuffer
218 
219     Returns:        none
220  *---------------------------------------------------------------------------*/
MyDEMODoneRender(void)221 static void MyDEMODoneRender ( void )
222 {
223     extern void*  DemoFrameBuffer1;   // static global variables from DEMOInit.c
224     extern void*  DemoFrameBuffer2;
225     extern void*  DemoCurrentBuffer;
226 
227 
228     // copy out the other framebuffer since GP is a frame behind
229     if( DemoCurrentBuffer == DemoFrameBuffer1 )
230         GXCopyDisp(DemoFrameBuffer2, GX_TRUE);
231     else
232         GXCopyDisp(DemoFrameBuffer1, GX_TRUE);
233 
234     GXSetDrawSync( FIFO_DRAWDONE_TOKEN );
235 
236     // wait until GP is finished by polling for the drawdone token in
237     // current GP Fifo (previously processed by CPU)
238     while( (GXReadDrawSync()) != FIFO_DRAWDONE_TOKEN )
239     {
240     }
241 
242     //============================
243 
244     // Wait for vertical retrace and set the next frame buffer
245     // Display the buffer which was just filled by GXCopyDisplay
246     DEMOSwapBuffers();
247 
248 }
249 
250 /*---------------------------------------------------------------------------*
251     Name:           FifoTick
252 
253     Description:    changes the GP breakpoint so CPU can calculate next frame
254                     while GP processes last frame. should be called before any
255                     commands are sent to GP (at the top of the main loop)
256                     since this function assumes that both the CPU and GP are
257                     not processing.
258 
259     Arguments:      none
260 
261     Returns:        none
262 *----------------------------------------------------------------------------*/
FifoTick(void)263 static void FifoTick( void )
264 {
265     GXFifoObj currFifoObj;
266     void *readPtr, *writePtr;
267 
268     // Set a breakpoint at the current point in the CPU
269     // and disable the previous one to let the GP start processing
270     GXGetCPUFifo( &currFifoObj );
271 
272     GXGetFifoPtrs( &currFifoObj, &readPtr, &writePtr );
273     GXEnableBreakPt( writePtr );
274 
275     GXSetDrawSync( FIFO_DRAWING_TOKEN );
276 }
277 
278 /*---------------------------------------------------------------------------*
279     Name:           FifoInit
280 
281     Description:    Resizes the default FIFO from DEMOInit.
282 
283     Arguments:      fifo : GX fifo object to use in this app.
284 
285     Returns:        none
286 *----------------------------------------------------------------------------*/
FifoInit(GXFifoObj * fifo)287 static void FifoInit( GXFifoObj* fifo )
288 {
289     // get the default fifo and free it later
290     GXSetDrawDone();
291 
292     // allocate new fifo
293     GXInitFifoBase( fifo, MEMAllocFromAllocator(&DemoAllocator1, BIG_FIFO_SIZE), BIG_FIFO_SIZE );
294 
295     // set the CPU and GP fifo to this new one
296     GXSetCPUFifo( fifo );
297     GXSetGPFifo( fifo );
298 
299     // so that the first fifo will fire off immediately
300     GXSetDrawSync( FIFO_DRAWDONE_TOKEN );
301 
302     // Default fifo area allocated in the demo library is left unused.
303 }
304