1 /*---------------------------------------------------------------------------*
2   Project:  Dolphin/Revolution gx demo
3   File:     fill-perf.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   Fill-rate performance test
13 
14  *---------------------------------------------------------------------------*/
15 
16 #include <stdlib.h>
17 #include <string.h>
18 #include <demo.h>
19 #include <math.h>
20 
21 /*---------------------------------------------------------------------------*
22    Type definitions
23  *---------------------------------------------------------------------------*/
24 // statistic data display style
25 typedef enum
26 {
27     STAT_TL,       // top left
28     STAT_BL,       // bottom left
29     STAT_TLD,      // double-size font, top-left
30     STAT_BLD,      // double-size font, bottom-left
31     STAT_IO        // dump using OSReport
32 } StatDispMode;
33 
34 // statistic types
35 typedef enum
36 {
37     STAT_GP0,      // GXReadGP0Metric
38     STAT_GP1,      // GXReadGP1Metric
39     STAT_MEM,      // GXReadMemMetric
40     STAT_PIX,      // GXReadPixMetric
41     STAT_VC,       // GXReadVCacheMetric
42     STAT_FR,       // Fill rate calc
43     STAT_TBW,      // Texture bandwidth calc
44     STAT_TBP,      // Texture B/pixel
45     STAT_MYC,      // print out user-computed count
46     STAT_MYR       // print out user-computed rate (stat/count)
47 } StatType;
48 
49 // used as "stat" argument when stat_type == STAT_MEM
50 typedef enum
51 {
52     STAT_MEM_CP,   // GXReadMemMetric(CP Req.)
53     STAT_MEM_TC,   // GXReadMemMetric(TC Req.)
54     STAT_MEM_CPUR, // GXReadMemMetric(CPU Rd Req.)
55     STAT_MEM_CPUW, // GXReadMemMetric(CPU Wr Req.)
56     STAT_MEM_DSP,  // GXReadMemMetric(DSP Req.)
57     STAT_MEM_IO,   // GXReadMemMetric(IO Req.)
58     STAT_MEM_VI,   // GXReadMemMetric(VI Req.)
59     STAT_MEM_PE,   // GXReadMemMetric(PE Req.)
60     STAT_MEM_RF,   // GXReadMemMetric(RF Req.)
61     STAT_MEM_FI    // GXReadMemMetric(FI Req.)
62 } MemStatArg;
63 
64 // used as "stat" argument when stat_type == STAT_PIX
65 typedef enum
66 {
67     STAT_PIX_TI,   // GXReadPixMetric(Top Pixel In)
68     STAT_PIX_TO,   // GXReadPixMetric(Top Pixel Out)
69     STAT_PIX_BI,   // GXReadPixMetric(Bottom Pixel In)
70     STAT_PIX_BO,   // GXReadPixMetric(Bottom Pixel Out)
71     STAT_PIX_CI,   // GXReadPixMetric(Color Pixel In)
72     STAT_PIX_CC    // GXReadPixMetric(Copy Clocks)
73 } PixStatArg;
74 
75 // used as "stat" argument when stat_type == STAT_VC
76 typedef enum
77 {
78     STAT_VC_CHK,   // GXReadVCacheMetric(Check)
79     STAT_VC_MISS,  // GXReadVCacheMetric(Miss)
80     STAT_VC_STALL  // GXReadVCacheMetric(Stall)
81 } VcStatArg;
82 
83 typedef struct
84 {
85     char            text[48];  // 8 x 48 = 386 pixels
86     StatType        stat_type; // statics type
87     u32             stat;      // metric to measure
88     u32             count;     // count returned from metric function
89 } StatObj;
90 
91 /*---------------------------------------------------------------------------*
92    Forward references
93  *---------------------------------------------------------------------------*/
94 
95 void        main             ( void );
96 static void CameraInit       ( void );
97 static void ViewInit         ( void );
98 static void DrawInit         ( void );
99 static void InitDrawState    ( void );
100 static void DrawTick         ( void );
101 static void AnimTick         ( void );
102 static void MakeModelMtx     ( Vec xAxis, Vec yAxis, Vec zAxis, Mtx m );
103 static void PrintIntro       ( void );
104 static void DrawCubeIndx     ( void );
105 static void DrawCubeDirect   ( void );
106 static void DrawArrow        ( void );
107 static void init_rand        ( void );
108 static u32  lrand            ( void );
109 static f32  frand            ( void );
110 
111 static GXTexRegion*
112             MyTexRegionCallback( const GXTexObj* texObj, GXTexMapID mapID );
113 
114 
115 static void PrintStats      ( void );
116 static void UpdateStats     ( GXBool inc );
117 static void WriteStats      ( GXBool update );
118 static void SetStats        ( StatObj* stat, u32 nstats, StatDispMode disp );
119 
120 /*---------------------------------------------------------------------------*
121    Defines
122  *---------------------------------------------------------------------------*/
123 #define INDEXED_DATA    1 // comment out for direct data
124 
125 #define TCACHE_SZ       GX_TEXCACHE_32K
126 #define NUM_REGIONS     8 // number of caches
127 #define NUM_TEXOBJS     9 // for 8 tev stages, plus 1 to swap between
128 #define MAX_TEV         8 // for this test
129 #define NUM_ROTMATS    10 // just because
130 
131 #define STAT_SIZE       (sizeof(MyStats) / sizeof(StatObj))
132 #define SIDE            50.0F
133 
134 
135 /*---------------------------------------------------------------------------*
136    Global variables
137  *---------------------------------------------------------------------------*/
138 //
139 //  Cube data
140 //
141 f32 Vert[] ATTRIBUTE_ALIGN(32) =
142 {
143     -SIDE,  SIDE, -SIDE, //0
144     -SIDE,  SIDE,  SIDE, //1
145     -SIDE, -SIDE,  SIDE, //2
146     -SIDE, -SIDE, -SIDE, //3
147      SIDE,  SIDE, -SIDE, //4
148      SIDE, -SIDE, -SIDE, //5
149      SIDE, -SIDE,  SIDE, //6
150      SIDE,  SIDE,  SIDE, //7
151         0,     0, -SIDE, //8
152      SIDE/4,   0,     0, //9
153     -SIDE/4,   0,     0, //10
154         0, SIDE/4,    0  //11
155 };
156 
157 f32 Norm[] ATTRIBUTE_ALIGN(32) =
158 {
159     -1.0F,  0.0F,  0.0F, //0
160      0.0F, -1.0F,  0.0F, //1
161      0.0F,  0.0F, -1.0F, //2
162      1.0F,  0.0F,  0.0F, //3
163      0.0F,  1.0F,  0.0F, //4
164      0.0F,  0.0F,  1.0F  //5
165 };
166 
167 f32 TexCoord[] ATTRIBUTE_ALIGN(32) =
168 {
169     0.0F,  0.0F, //0
170     1.0F,  0.0F, //1
171     1.0F,  1.0F, //2
172     0.0F,  1.0F, //3
173 };
174 
175 u32 MyColors[] ATTRIBUTE_ALIGN(32) =
176 {
177     0xff0000ff, // red
178     0x00ff00ff, // green
179     0x0000ffff, // blue
180     0xffff00ff, // yellow
181     0xff00ffff, // magenta
182     0x00ffffff  // cyan
183 };
184 
185 //
186 //  Test structure
187 //
188 typedef struct
189 {
190     u32 numx;       // number of cubes in x direction
191     u32 numy;       // number of cubes in y direction
192     u32 numz;       // number of cubes in z direction
193     f32 dx;         // dist between cubes in x direction
194     f32 dy;         // dist between cubes in y direction
195     f32 dz;         // dist between cubes in z direction
196     u8  ntev;       // number of textures per cube (num tev stages)
197     u32 nc_tx;      // number of cubes per texture change
198     u32 tcb;        // texture region allocator callback
199     u32 tci;        // invalidate tex region on each GXLoadTexObj when tcb=1
200     f32 mods;       // model scale
201     f32 rot;        // model rotation
202     f32 dr;         // model rotation speed
203     Vec axis[NUM_ROTMATS];   // random rotation axis, initialized by DrawInit
204 } TestData;
205 
206 static TestData testData;
207 
208 //
209 //  Statistics
210 //
211 //
212 StatObj MyStats1[] =
213 {
214     // General Performance
215     {  "GP Clocks [1/60]..",  STAT_GP0, GX_PERF0_CLOCKS,    0 },
216     {  "Vertices..........",  STAT_GP1, GX_PERF1_VERTICES,  0 },
217     {  "Fill Rate [MP/Sec]",  STAT_FR,  GX_PERF0_NONE,      0 },
218     {  "TextureBW [MB/Sec]",  STAT_TBW, GX_PERF0_NONE,      0 },
219     {  "TexB/pix..........",  STAT_TBP, GX_PERF0_NONE,      0 },
220 };
221 
222 StatObj MyStats2[] =
223 {
224     // Texture Performance Detail
225     {  "Texels.........",  STAT_GP1, GX_PERF1_TEXELS,       0 },
226     {  "Tex 1-2 Lines..",  STAT_GP1, GX_PERF1_TC_CHECK1_2,  0 },
227     {  "Tex 3-4 Lines..",  STAT_GP1, GX_PERF1_TC_CHECK3_4,  0 },
228     {  "Tex 5-6 Lines..",  STAT_GP1, GX_PERF1_TC_CHECK5_6,  0 },
229     {  "Tex 7-8 Lines..",  STAT_GP1, GX_PERF1_TC_CHECK7_8,  0 },
230     {  "Tex Cache Miss.",  STAT_GP1, GX_PERF1_TC_MISS,      0 },
231     {  "Total Checks...",  STAT_MYC, GX_PERF1_NONE,         0 },
232     {  "Tex$ Miss Rate.",  STAT_MYR, GX_PERF1_NONE,         0 },
233 };
234 
235 StatObj MyStats3[] =
236 {
237     // Pixel Performance Detail
238     {  "Pixels Entered.",  STAT_PIX, STAT_PIX_TI,      0 },
239     {  "Pixels Z Passed",  STAT_PIX, STAT_PIX_TO,      0 },
240     {  "Pixels Blended.",  STAT_PIX, STAT_PIX_CI,      0 },
241     {  "Quads w>0 Cvg..",  STAT_GP0, GX_PERF0_QUAD_NON0CVG, 0 },
242     {  "Quads w/1 Cvg..",  STAT_GP0, GX_PERF0_QUAD_1CVG,    0 },
243     {  "Quads w/2 Cvg..",  STAT_GP0, GX_PERF0_QUAD_2CVG,    0 },
244     {  "Quads w/3 Cvg..",  STAT_GP0, GX_PERF0_QUAD_3CVG,    0 },
245     {  "Quads w/4 Cvg..",  STAT_GP0, GX_PERF0_QUAD_4CVG,    0 },
246 };
247 
248 StatObj MyStats4[] =
249 {
250     // Memory Access Detail
251     {  "CP Reqs........",  STAT_MEM, STAT_MEM_CP,      0 },
252     {  "TX Cache Reqs..",  STAT_MEM, STAT_MEM_TC,      0 },
253     {  "CPU Rd Reqs....",  STAT_MEM, STAT_MEM_CPUR,    0 },
254     {  "CPU Wr Reqs....",  STAT_MEM, STAT_MEM_CPUW,    0 },
255     {  "DSP Reqs.......",  STAT_MEM, STAT_MEM_DSP,     0 },
256     {  "IO Reqs........",  STAT_MEM, STAT_MEM_IO,      0 },
257     {  "VI Reqs........",  STAT_MEM, STAT_MEM_VI,      0 },
258     {  "PE Reqs........",  STAT_MEM, STAT_MEM_PE,      0 },
259     {  "Refresh Reqs...",  STAT_MEM, STAT_MEM_RF,      0 },
260     {  "Forced Idle....",  STAT_MEM, STAT_MEM_FI,      0 },
261 };
262 
263 StatObj MyStats5[] =
264 {
265     // Current Setting
266     {  "Num Of Cubes...",  STAT_MYC, 0,      0 },
267     {  "Cubes/Texture..",  STAT_MYC, 0,      0 },
268     {  "Num TevStages..",  STAT_MYC, 0,      0 },
269 };
270 
271 #define STAT_MENU0  0
272 #define STAT_MENU1  (sizeof(MyStats1)/sizeof(StatObj))
273 #define STAT_MENU2  (sizeof(MyStats2)/sizeof(StatObj))
274 #define STAT_MENU3  (sizeof(MyStats3)/sizeof(StatObj))
275 #define STAT_MENU4  (sizeof(MyStats4)/sizeof(StatObj))
276 #define STAT_MENU5  (sizeof(MyStats5)/sizeof(StatObj))
277 
278 static Mtx v, mv;
279 static u32 animMode  = 0;
280 static u32 showStats = 1; // show fill rate by default
281 static u32 stopAnim  = 0;
282 static void       (*testDraw)() = NULL; // function pointer for draw routine
283 static GXTexObj     texObj[NUM_TEXOBJS];  // texture object
284 static GXTexRegion  MyTexRegions[NUM_REGIONS]; // cache regions
285 
286 static GXTexRegionCallback oldCallback;
287 
288 static GXLightObj   MyLight; // light object
289 
290 static Vec CamX = {1.0F, 0.0F, 0.0F};
291 static Vec CamY = {0.0F, 1.0F, 0.0F};
292 static Vec CamZ = {0.0F, 0.0F, 1.0F};
293 static f32 CamS = 100.0F; // camera zoom factor
294 
295 static OSStopwatch myTotTime;
296 
297 // For stats
298 static GXBool StatEnable  = GX_FALSE;
299 
300 static StatObj* Stat   = NULL;
301 static u32 StatIndx    = 0;
302 static u32 StatMaxIndx = 0;
303 static u32 StatClocks  = 0;
304 
305 static u32 StatDisp    = 0;
306 static u32 StatStrLen  = 0;
307 
308 // other statistics counts that can be counted in parallel
309 static u32 topPixIn, topPixOut;
310 static u32 botPixIn, botPixOut;
311 static u32 clrPixIn, copyClks;
312 
313 static u32 vcCheck, vcMiss, vcStall;
314 
315 static u32 cpReq, tcReq, cpuRdReq, cpuWrReq, dspReq,
316            ioReq, viReq, peReq, rfReq, fiReq;
317 
318 
319 /*---------------------------------------------------------------------------*
320    Application main loop
321  *---------------------------------------------------------------------------*/
main(void)322 void main ( void )
323 {
324     DEMOInit(NULL);
325     DrawInit();
326     PrintIntro();
327 
328     OSInitStopwatch(&myTotTime, "myTotTime");
329     OSResetStopwatch(&myTotTime);
330 
331     testDraw = DrawCubeIndx;
332 
333     while (!(DEMOPadGetButton(0) & PAD_BUTTON_MENU))
334     {
335         DEMOPadRead();
336         AnimTick();
337 
338         InitDrawState();
339         CameraInit();
340 
341         OSStartStopwatch(&myTotTime);
342         DEMOBeforeRender();
343 
344         DrawTick();
345 
346         if ( showStats == 2 )
347         {
348             // total check count
349             MyStats2[6].count = MyStats2[1].count + MyStats2[2].count +
350                                 MyStats2[3].count + MyStats2[4].count;
351             // compute miss rate
352             MyStats2[7].stat  = MyStats2[5].count; // misses
353             MyStats2[7].count = MyStats2[6].count; // total checks
354         }
355         else if ( showStats == 5 )
356         {
357             MyStats5[0].count = testData.numx * testData.numy * testData.numz;
358             MyStats5[1].count = testData.nc_tx;
359             MyStats5[2].count = testData.ntev;
360         }
361 
362         GXDrawDone();
363         OSStopStopwatch(&myTotTime);
364 
365         if ( StatEnable )
366         {
367             UpdateStats(GX_TRUE);
368             PrintStats();
369             GXDrawDone();
370             UpdateStats(GX_FALSE);
371         }
372 
373         DEMODoneRender();
374     }
375 
376     OSHalt("End of test");
377 }
378 
379 /*---------------------------------------------------------------------------*
380    Functions
381  *---------------------------------------------------------------------------*/
382 
383 
384 /*---------------------------------------------------------------------------*
385     Name:           CameraInit
386 
387     Description:    Initialize the projection matrix and load into hardware.
388 
389     Arguments:      none
390 
391     Returns:        none
392  *---------------------------------------------------------------------------*/
CameraInit(void)393 static void CameraInit ( void )
394 {
395     Mtx44 p;
396 
397     MTXFrustum(p, .24F * CamS,-.24F * CamS,
398                -.32F * CamS, .32F * CamS,
399                .5F * CamS, 40.0F * CamS);
400 
401     GXSetProjection(p, GX_PERSPECTIVE);
402     ViewInit();
403 }
404 
405 
406 /*---------------------------------------------------------------------------*
407     Name:           ViewInit
408 
409     Description:    Initialize the view matrix.
410 
411     Arguments:      none
412 
413     Returns:        none
414  *---------------------------------------------------------------------------*/
ViewInit(void)415 static void ViewInit ( void )
416 {
417     Mtx trans;
418 
419     MakeModelMtx(CamX, CamY, CamZ, v);  // Make a new view matrix
420     MTXTranspose(v, v);
421     MTXTrans(trans, 0.0F, 0.0F, -8.0F * CamS);
422     MTXConcat(trans, v, v);
423 }
424 
425 
426 /*---------------------------------------------------------------------------*
427     Name:           DrawInit
428 
429     Description:    Initialize one-time state settings
430 
431     Arguments:      none
432 
433     Returns:        none
434  *---------------------------------------------------------------------------*/
DrawInit(void)435 static void DrawInit( void )
436 {
437     u32           i;
438     GXColor       color = {0, 255, 255, 255};
439     TPLPalettePtr tpl = 0; // texture palette
440 
441     //
442     //  Initialize test structure
443     //
444     testData.numx  = 1;
445     testData.numy  = 1;
446     testData.numz  = 1;
447     testData.nc_tx = testData.numx * testData.numz;
448     testData.tcb   = 0; // default texregion callback
449     testData.tci   = 0; // don't invalidate tex cache regions
450     testData.dx    = 2*SIDE + 10.0F;
451     testData.dy    = 2*SIDE + 10.0F;
452     testData.dz    = -(2*SIDE + 10.0F);
453     testData.ntev  = 1;      // num textures
454     testData.mods  = 1.0F;   // model scale
455     testData.rot   = 0.0F;   // model rotation
456     testData.dr    = 1.0F;   // rotation speed
457 
458     SetStats(MyStats1, STAT_MENU1, STAT_TLD);
459 
460     // init texture regions
461     for ( i = 0 ; i < NUM_REGIONS ; i++ )
462     {
463         // The region is used as a 32K cache.
464         GXInitTexCacheRegion(
465             &MyTexRegions[i],
466             GX_FALSE,               // 32b mipmap
467             0x00000 + i * 0x08000,  // tmem_even
468             TCACHE_SZ,              // size_even
469             0x80000 + i * 0x08000,  // tmem_odd
470             TCACHE_SZ );            // size_odd
471     }
472 
473     // initialize oldCallback to default callback
474     oldCallback = GXSetTexRegionCallback(MyTexRegionCallback);
475     GXSetTexRegionCallback(oldCallback);
476 
477     // model axis
478     init_rand();
479     for (i = 0; i < NUM_ROTMATS; i++)
480     {
481         // make random axis
482         testData.axis[i].x = frand();
483         testData.axis[i].y = frand();
484         testData.axis[i].z = frand();
485         VECNormalize(&testData.axis[i], &testData.axis[i]);
486     }
487 
488     GXInitLightPos(&MyLight, 0.0F, 0.0F, 0.0F);
489     GXInitLightColor(&MyLight, color);
490 
491     //  Load the texture palette
492     TPLGetPalette(&tpl, "gxTests/tex-07.tpl");
493 
494     //  Initialize a texture object to contain the correct texture
495     for (i = 0; i < NUM_TEXOBJS; i++)
496     {
497         OSReport("Reading tex obj %d\n", i);
498         TPLGetGXTexObjFromPalette(tpl, &texObj[i], i);
499         GXInitTexObjUserData(&texObj[i], (void*)i);
500     }
501 
502     InitDrawState();
503 
504     GXDrawDone(); // make sure state is in GP
505 }
506 
507 
508 /*---------------------------------------------------------------------------*
509     Name:           InitDrawState
510 
511     Description:    Sets drawing state that gets destroyed by DEMOPrintf
512                     when the statistics are printed.
513 
514     Arguments:      none
515 
516     Returns:        none
517  *---------------------------------------------------------------------------*/
InitDrawState(void)518 static void InitDrawState( void )
519 {
520     GXColor       color = {0, 255, 0, 255};
521 
522     GXSetCurrentMtx(0);
523     GXSetCullMode(GX_CULL_BACK);
524 
525     GXLoadLightObjImm(&MyLight, GX_LIGHT0);
526 
527     GXSetChanMatColor(GX_COLOR0A0, color);
528     GXSetChanCtrl(
529                 GX_COLOR0A0,
530                 GX_FALSE,       // enable channel
531                 GX_SRC_REG,     // amb source
532                 GX_SRC_VTX,     // mat source
533                 GX_LIGHT_NULL,  // light mask
534                 GX_DF_NONE,     // diffuse function
535                 GX_AF_NONE);
536 
537     //  Load the texture object; tex0 is used in stage 0
538 
539     GXSetNumChans(1);
540     GXSetNumTexGens(1);
541     GXSetNumTevStages(testData.ntev);
542 
543     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
544     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
545     GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL);
546     GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD0, GX_TEXMAP2, GX_COLOR_NULL);
547     GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD0, GX_TEXMAP3, GX_COLOR_NULL);
548     GXSetTevOrder(GX_TEVSTAGE4, GX_TEXCOORD0, GX_TEXMAP4, GX_COLOR_NULL);
549     GXSetTevOrder(GX_TEVSTAGE5, GX_TEXCOORD0, GX_TEXMAP5, GX_COLOR_NULL);
550     GXSetTevOrder(GX_TEVSTAGE6, GX_TEXCOORD0, GX_TEXMAP6, GX_COLOR_NULL);
551     GXSetTevOrder(GX_TEVSTAGE7, GX_TEXCOORD0, GX_TEXMAP7, GX_COLOR_NULL);
552     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
553     GXSetTevOp(GX_TEVSTAGE1, GX_REPLACE);
554     GXSetTevOp(GX_TEVSTAGE2, GX_REPLACE);
555     GXSetTevOp(GX_TEVSTAGE3, GX_REPLACE);
556     GXSetTevOp(GX_TEVSTAGE4, GX_REPLACE);
557     GXSetTevOp(GX_TEVSTAGE5, GX_REPLACE);
558     GXSetTevOp(GX_TEVSTAGE6, GX_REPLACE);
559     GXSetTevOp(GX_TEVSTAGE7, GX_REPLACE);
560 
561     GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR);
562     GXSetZMode(GX_ENABLE, GX_LEQUAL, GX_ENABLE);
563 
564     GXClearVtxDesc();
565 
566 #ifdef INDEXED_DATA
567     //OSReport("Using indexed data\n");
568     GXSetVtxDesc(GX_VA_POS,  GX_INDEX16);
569     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
570     GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8);
571 #else
572     //OSReport("Using direct data\n");
573     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
574     GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
575     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
576 #endif // INDEXED_DATA
577 
578     GXSetArray(GX_VA_POS,  Vert,     sizeof(f32)*3);
579     GXSetArray(GX_VA_CLR0, MyColors, sizeof(u32));
580     GXSetArray(GX_VA_TEX0, TexCoord, sizeof(f32)*2);
581 
582     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS,  GX_POS_XYZ,  GX_F32,   0);
583     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
584     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST,   GX_F32,   0);
585 }
586 
587 /*---------------------------------------------------------------------------*
588     Name:           DrawTick
589 
590     Description:    Draws spheres
591 
592     Arguments:      none
593 
594     Returns:        none
595  *---------------------------------------------------------------------------*/
DrawTick(void)596 static void DrawTick( void )
597 {
598     u32 i, j, k, cnt; // indices
599     u32 tx;  // offset of texture
600     Mtx m, t;
601     f32 x, z;
602 
603     // for now do only 2-D grid
604     // center grid on 0, 0, 0
605     z = 0.0F - ((testData.numz / 2) * testData.dz);
606     for (cnt = i = 0; i < testData.numz; i++)
607     {
608         x = 0.0F - ((testData.numx / 2) * testData.dx);
609         for (j = 0; j < testData.numx; j++, cnt++)
610         {
611             // Set texture state every n cubes
612             if ((cnt % testData.nc_tx) == 0)
613             {
614                 tx = ((cnt / testData.nc_tx) & 1) * (NUM_TEXOBJS - 1);
615                 for (k = 0; k < testData.ntev; k++)
616                 {
617                     if (tx)
618                         GXLoadTexObj(&texObj[tx], (GXTexMapID)k);
619                     else
620                         GXLoadTexObj(&texObj[k], (GXTexMapID)k);
621                 }
622             }
623             // build matrix
624             MTXScale(m, testData.mods, testData.mods, testData.mods);
625             MTXRotAxisDeg(t, &testData.axis[cnt%NUM_ROTMATS], testData.rot);
626             MTXConcat(t, m, m);  // scale, rotate
627             MTXTrans(t, x, 0.0F, z);
628             MTXConcat(t, m, m);  // translate
629             MTXConcat(v, m, mv); // concat view matrix
630 
631             GXLoadPosMtxImm(mv, 0);
632             GXLoadNrmMtxImm(mv, 0);
633 
634             testDraw();
635 
636             x += testData.dx;
637         }
638         z += testData.dz;
639     }
640 
641     // draw arrow on top-center
642     MTXScale(m, testData.mods, testData.mods, testData.mods);
643     MTXTrans(t, 0.0F, -100.0F*testData.mods, 0.0F);
644     MTXConcat(t, m, m);  // scale, translate
645     MTXConcat(v, m, mv); // concat view matrix
646 
647     GXLoadPosMtxImm(mv, 0);
648     DrawArrow();
649 }
650 
651 /*---------------------------------------------------------------------------*
652     Name:           AnimTick
653 
654     Description:    Animates the camera and object based on the joystick's
655                     state.
656 
657     Arguments:      v    view matrix
658                     m    model matrix
659 
660     Returns:        none
661  *---------------------------------------------------------------------------*/
AnimTick(void)662 static void AnimTick ( void )
663 {
664     Mtx rot;
665     Vec temp;
666     Vec yAxis = {0.0F, 1.0F, 0.0F};
667     f32 dot;
668 
669     // Get controller status through DEMOPad library
670     u16 buttons = DEMOPadGetButton(0);
671     u16 downs   = DEMOPadGetButtonDown(0);
672     u16 dirs    = DEMOPadGetDirsNew(0);
673     s8 stickX   = DEMOPadGetStickX(0);
674     s8 stickY   = DEMOPadGetStickY(0);
675 
676     // Scale model up/down
677     if (buttons & PAD_TRIGGER_L)
678     {
679         testData.mods *= 0.95F;
680         if (testData.mods < 0.001F)
681             testData.mods = 0.001F;
682     }
683     if (buttons & PAD_TRIGGER_R)
684     {
685         testData.mods *= 1.05F;
686     }
687 
688     // Model rotation
689     testData.rot += testData.dr;
690     if (testData.rot >= 360.0F)
691         testData.rot -= 360.0F;
692 
693     // change number of cubes
694     if (dirs & DEMO_SUBSTICK_UP)
695     {
696         testData.numz++;
697     }
698     if (dirs & DEMO_SUBSTICK_DOWN)
699     {
700         testData.numz--;
701         if (testData.numz <= 1)
702             testData.numz = 1;
703     }
704     if (dirs & DEMO_SUBSTICK_RIGHT)
705     {
706         testData.numx++;
707     }
708     if (dirs & DEMO_SUBSTICK_LEFT)
709     {
710         testData.numx--;
711         if (testData.numx <= 1)
712             testData.numx = 1;
713     }
714 
715     // Zoom camera in/out
716     if(buttons & PAD_BUTTON_Y)
717     {
718         CamS *= .95F;
719         if(CamS < 0.001F)
720         {
721             CamS = 0.001F;
722         }
723     }
724     if(buttons & PAD_BUTTON_A)
725     {
726         CamS *= 1.05F;
727     }
728 
729     // Rotate viewpoint
730     if(stickX || stickY)
731     {
732         if(stickX > 30 || stickX < -30)
733         {
734             if(stickX > 30)
735                 MTXRotDeg(rot, 'y', -1.0F);
736             else if(stickX < -30)
737                 MTXRotDeg(rot, 'y', 1.0F);
738 
739             MTXMultVec(rot, &CamX, &CamX);
740             MTXMultVec(rot, &CamY, &CamY);
741             MTXMultVec(rot, &CamZ, &CamZ);
742         }
743 
744         if(stickY > 30 || stickY < -30)
745         {
746             if(stickY > 30)
747                 MTXRotAxisDeg(rot, &CamX, -1.0F);
748             else if(stickY < -30)
749                 MTXRotAxisDeg(rot, &CamX, 1.0F);
750 
751             MTXMultVec(rot, &CamY, &temp);
752             dot = VECDotProduct(&temp, &yAxis);
753             if(dot > 0.05F && dot <= 1.0F)
754             {
755                 CamY = temp;
756                 MTXMultVec(rot, &CamZ, &CamZ);
757             }
758         }
759     }
760 
761     // change mode
762     if(downs & PAD_BUTTON_X)
763     {
764         animMode++;
765         animMode %= 6;
766 
767         switch (animMode)
768         {
769             case 0:
770                 OSReport("Button B increments the number of tev stages\n");
771                 break;
772             case 1:
773                 OSReport("Button B toggles the statistics display\n");
774                 break;
775             case 2:
776                 OSReport("Button B toggles the cube animation\n");
777                 break;
778             case 3:
779                 OSReport("Button B decrements the number of cubes per texture\n");
780                 break;
781             case 4:
782                 OSReport("Button B toggles the texture cache algorithm\n");
783                 break;
784             case 5:
785                 OSReport("Button B toggles texture invalidation mode\n");
786                 break;
787             default:
788                 break;
789         }
790     }
791 
792     // change param depending on mode
793     if (downs & PAD_BUTTON_B)
794     {
795         if (animMode == 0)
796         {
797             testData.ntev++;
798             if (testData.ntev > MAX_TEV)
799                 testData.ntev = 1;
800 
801         }
802         else if (animMode == 1)
803         {
804             showStats++;
805             switch(showStats)
806             {
807               case 1 :
808                 SetStats(MyStats1, STAT_MENU1, STAT_TLD);
809                 break;
810               case 2 :
811                 SetStats(MyStats2, STAT_MENU2, STAT_TLD);
812                 break;
813               case 3 :
814                 SetStats(MyStats3, STAT_MENU3, STAT_TLD);
815                 break;
816               case 4 :
817                 SetStats(MyStats4, STAT_MENU4, STAT_TLD);
818                 break;
819               case 5 :
820                 SetStats(MyStats5, STAT_MENU5, STAT_TLD);
821                 break;
822               default:
823                 SetStats(NULL, STAT_MENU0, STAT_TLD);
824                 showStats = 0;
825                 break;
826             }
827         }
828         else if (animMode == 2)
829         {
830             stopAnim ^= 1;
831             if (stopAnim)
832                 testData.dr   = 0.0F;   // rotation speed
833             else
834                 testData.dr   = 1.0F;   // rotation speed
835         }
836         else if (animMode == 3)
837         {
838             testData.nc_tx /= 2;
839             if (testData.nc_tx == 0)
840                 testData.nc_tx = testData.numx * testData.numz;
841         }
842         else if (animMode == 4)
843         {
844             testData.tcb ^= 1;
845             if (testData.tcb == 0)
846             {
847                 OSReport("Texture cache = round robin\n");
848                 GXSetTexRegionCallback(oldCallback);
849             }
850             else
851             {
852                 OSReport("Texture cache = mapID\n");
853                 oldCallback = GXSetTexRegionCallback(MyTexRegionCallback);
854             }
855             GXInvalidateTexAll();
856         }
857         else if (animMode == 5)
858         {
859             testData.tci ^= 1;
860             if (testData.tci && testData.tcb)
861                 OSReport("Invalidate tex region on each GXLoadTexObj\n");
862             else
863                 OSReport("Do not invalidate tex region on each GXLoadTexObj\n");
864         }
865     }
866 }
867 
868 
869 /*---------------------------------------------------------------------------*
870     Name:           MakeModelMtx
871 
872     Description:    computes a model matrix from 3 vectors representing an
873                     object's coordinate system.
874 
875     Arguments:      xAxis   vector for the object's X axis
876                     yAxis   vector for the object's Y axis
877                     zAxis   vector for the object's Z axis
878 
879     Returns:        none
880  *---------------------------------------------------------------------------*/
MakeModelMtx(Vec xAxis,Vec yAxis,Vec zAxis,Mtx m)881 static void MakeModelMtx ( Vec xAxis, Vec yAxis, Vec zAxis, Mtx m )
882 {
883     VECNormalize(&xAxis,&xAxis);
884     VECNormalize(&yAxis,&yAxis);
885     VECNormalize(&zAxis,&zAxis);
886 
887     m[0][0] = xAxis.x;
888     m[0][1] = xAxis.y;
889     m[0][2] = xAxis.z;
890     m[0][3] = 0.0F;
891 
892     m[1][0] = yAxis.x;
893     m[1][1] = yAxis.y;
894     m[1][2] = yAxis.z;
895     m[1][3] = 0.0F;
896 
897     m[2][0] = zAxis.x;
898     m[2][1] = zAxis.y;
899     m[2][2] = zAxis.z;
900     m[2][3] = 0.0F;
901 
902     MTXInverse(m, m);
903 }
904 
905 
906 /*---------------------------------------------------------------------------*
907     Name:           MyTexRegionCallback
908 
909     Description:    Tex cache allocator using simple round algorithm
910 
911     Arguments:      texObj : a pointer to texture object to be loaded
912                     mapID  : destination texmap ID (just same as GXLoadTexObj)
913 
914     Returns:        appropriate tex cache region for loading texture.
915  *---------------------------------------------------------------------------*/
MyTexRegionCallback(const GXTexObj * texObj,GXTexMapID mapID)916 static GXTexRegion* MyTexRegionCallback(const GXTexObj* texObj, GXTexMapID mapID)
917 {
918 #pragma unused(mapID)
919 
920     u32  regionNum, texID;
921 
922     texID     = (u32)GXGetTexObjUserData(texObj);
923     regionNum = texID % NUM_REGIONS;
924 
925     // see effect of cold cache load
926     if (testData.tci)
927         GXInvalidateTexRegion(&MyTexRegions[regionNum]);
928 
929     return &MyTexRegions[regionNum];
930 }
931 
932 
933 
934 /*---------------------------------------------------------------------------*
935     Name:           PrintIntro
936 
937     Description:    Print usage for test
938 
939     Arguments:      none
940 
941     Returns:        none
942  *---------------------------------------------------------------------------*/
PrintIntro(void)943 static void PrintIntro( void )
944 {
945     OSReport("\n");
946     OSReport("************************************\n");
947     OSReport(" Check fill-rate performance\n");
948     OSReport("************************************\n");
949     OSReport("\n");
950     OSReport("SUBSTICK:   Change the number of cubes\n");
951     OSReport("TRIGGER R:  Increase the size of the cubes\n");
952     OSReport("TRIGGER L:  Decrease the size of the cubes\n");
953     OSReport("\n");
954     OSReport("STICK:      Rotate camera\n");
955     OSReport("BUTTON A/Y: Zoom camera in/out\n");
956     OSReport("BUTTON X:   Change Button B mode\n");
957     OSReport("BUTTON B:   Controls various parameters depending on mode\n");
958     OSReport("\n");
959     OSReport("to quit hit the menu button\n");
960     OSReport("\n");
961 }
962 
963 
964 /*---------------------------------------------------------------------------*
965     Name:           DrawCubeIndx
966 
967     Description:
968 
969     Arguments:      none
970 
971     Returns:        none
972  *---------------------------------------------------------------------------*/
973 static
DrawCubeIndx(void)974 void DrawCubeIndx( void )
975 {
976     GXBegin(GX_QUADS, GX_VTXFMT0, 4*6);
977         GXPosition1x16(4);
978         GXColor1x8(0);
979         GXTexCoord1x8(0); //
980         GXPosition1x16(5);
981         GXColor1x8(0);
982         GXTexCoord1x8(1); //
983         GXPosition1x16(6);
984         GXColor1x8(0);
985         GXTexCoord1x8(2); //
986         GXPosition1x16(7);
987         GXColor1x8(0);
988         GXTexCoord1x8(3); //
989 
990         GXPosition1x16(2);
991         GXColor1x8(1);
992         GXTexCoord1x8(0); //
993         GXPosition1x16(6);
994         GXColor1x8(1);
995         GXTexCoord1x8(1); //
996         GXPosition1x16(5);
997         GXColor1x8(1);
998         GXTexCoord1x8(2); //
999         GXPosition1x16(3);
1000         GXColor1x8(1);
1001         GXTexCoord1x8(3); //
1002 
1003         GXPosition1x16(1);
1004         GXColor1x8(2);
1005         GXTexCoord1x8(0); //
1006         GXPosition1x16(0);
1007         GXColor1x8(2);
1008         GXTexCoord1x8(1); //
1009         GXPosition1x16(4);
1010         GXColor1x8(2);
1011         GXTexCoord1x8(2); //
1012         GXPosition1x16(7);
1013         GXColor1x8(2);
1014         GXTexCoord1x8(3); //
1015 
1016         GXPosition1x16(0);
1017         GXColor1x8(3);
1018         GXTexCoord1x8(0); //
1019         GXPosition1x16(1);
1020         GXColor1x8(3);
1021         GXTexCoord1x8(1); //
1022         GXPosition1x16(2);
1023         GXColor1x8(3);
1024         GXTexCoord1x8(2); //
1025         GXPosition1x16(3);
1026         GXColor1x8(3);
1027         GXTexCoord1x8(3); //
1028 
1029         GXPosition1x16(5);
1030         GXColor1x8(4);
1031         GXTexCoord1x8(0); //
1032         GXPosition1x16(4);
1033         GXColor1x8(4);
1034         GXTexCoord1x8(1); //
1035         GXPosition1x16(0);
1036         GXColor1x8(4);
1037         GXTexCoord1x8(2); //
1038         GXPosition1x16(3);
1039         GXColor1x8(4);
1040         GXTexCoord1x8(3); //
1041 
1042         GXPosition1x16(6);
1043         GXColor1x8(5);
1044         GXTexCoord1x8(0); //
1045         GXPosition1x16(2);
1046         GXColor1x8(5);
1047         GXTexCoord1x8(1); //
1048         GXPosition1x16(1);
1049         GXColor1x8(5);
1050         GXTexCoord1x8(2); //
1051         GXPosition1x16(7);
1052         GXColor1x8(5);
1053         GXTexCoord1x8(3); //
1054 
1055     GXEnd();
1056 }
1057 
1058 /*---------------------------------------------------------------------------*
1059     Name:           DrawCubeDirect
1060 
1061     Description:
1062 
1063     Arguments:      none
1064 
1065     Returns:        none
1066  *---------------------------------------------------------------------------*/
1067 static
DrawCubeDirect(void)1068 void DrawCubeDirect( void )
1069 {
1070     GXBegin(GX_QUADS, GX_VTXFMT0, 4*6);
1071         GXPosition3f32( SIDE, SIDE, -SIDE); //4
1072         GXColor1u32(0xff0000ff);// red
1073         GXTexCoord2f32(0.0F, 0.0F);//
1074         GXPosition3f32(SIDE, -SIDE, -SIDE);//5
1075         GXColor1u32(0xff0000ff);// red
1076         GXTexCoord2f32(1.0F, 0.0F);//
1077         GXPosition3f32(SIDE, -SIDE, SIDE); //6
1078         GXColor1u32(0xff0000ff);// red
1079         GXTexCoord2f32(1.0F, 1.0F);//
1080         GXPosition3f32(SIDE, SIDE, SIDE);  //7
1081         GXColor1u32(0xff0000ff);// red
1082         GXTexCoord2f32(0.0F, 1.0F);//
1083 
1084         GXPosition3f32(-SIDE, -SIDE, SIDE);//2
1085         GXColor1u32(0x00ff00ff);// green
1086         GXTexCoord2f32(0.0F, 0.0F);//
1087         GXPosition3f32(SIDE, -SIDE, SIDE); //6
1088         GXColor1u32(0x00ff00ff);// green
1089         GXTexCoord2f32(1.0F, 0.0F);//
1090         GXPosition3f32(SIDE, -SIDE, -SIDE);//5
1091         GXColor1u32(0x00ff00ff);// green
1092         GXTexCoord2f32(1.0F, 1.0F);//
1093         GXPosition3f32(-SIDE, -SIDE, -SIDE);//3
1094         GXColor1u32(0x00ff00ff);// green
1095         GXTexCoord2f32(0.0F, 1.0F);//
1096 
1097         GXPosition3f32(-SIDE, SIDE, SIDE); //1
1098         GXColor1u32(0x0000ffff);// blue
1099         GXTexCoord2f32(0.0F, 0.0F);//
1100         GXPosition3f32(-SIDE, SIDE, -SIDE);//0
1101         GXColor1u32(0x0000ffff);// blue
1102         GXTexCoord2f32(1.0F, 0.0F);//
1103         GXPosition3f32( SIDE, SIDE, -SIDE); //4
1104         GXColor1u32(0x0000ffff);// blue
1105         GXTexCoord2f32(1.0F, 1.0F);//
1106         GXPosition3f32(SIDE, SIDE, SIDE);  //7
1107         GXColor1u32(0x0000ffff);// blue
1108         GXTexCoord2f32(0.0F, 1.0F);//
1109 
1110         GXPosition3f32(-SIDE, SIDE, -SIDE);//0
1111         GXColor1u32(0xffff00ff);// yellow
1112         GXTexCoord2f32(0.0F, 0.0F);//
1113         GXPosition3f32(-SIDE, SIDE, SIDE); //1
1114         GXColor1u32(0xffff00ff);// yellow
1115         GXTexCoord2f32(1.0F, 0.0F);//
1116         GXPosition3f32(-SIDE, -SIDE, SIDE);//2
1117         GXColor1u32(0xffff00ff);// yellow
1118         GXTexCoord2f32(1.0F, 1.0F);//
1119         GXPosition3f32(-SIDE, -SIDE, -SIDE);//3
1120         GXColor1u32(0xffff00ff);// yellow
1121         GXTexCoord2f32(0.0F, 1.0F);//
1122 
1123         GXPosition3f32(SIDE, -SIDE, -SIDE);//5
1124         GXColor1u32(0xff00ffff);// magenta
1125         GXTexCoord2f32(0.0F, 0.0F);//
1126         GXPosition3f32( SIDE, SIDE, -SIDE); //4
1127         GXColor1u32(0xff00ffff);// magenta
1128         GXTexCoord2f32(1.0F, 0.0F);//
1129         GXPosition3f32(-SIDE, SIDE, -SIDE);//0
1130         GXColor1u32(0xff00ffff);// magenta
1131         GXTexCoord2f32(1.0F, 1.0F);//
1132         GXPosition3f32(-SIDE, -SIDE, -SIDE);//3
1133         GXColor1u32(0xff00ffff);// magenta
1134         GXTexCoord2f32(0.0F, 1.0F);//
1135 
1136         GXPosition3f32(SIDE, -SIDE, SIDE); //6
1137         GXColor1u32(0x00ffffff);// cyan
1138         GXTexCoord2f32(0.0F, 0.0F);//
1139         GXPosition3f32(-SIDE, -SIDE, SIDE);//2
1140         GXColor1u32(0x00ffffff);// cyan
1141         GXTexCoord2f32(1.0F, 0.0F);//
1142         GXPosition3f32(-SIDE, SIDE, SIDE); //1
1143         GXColor1u32(0x00ffffff);// cyan
1144         GXTexCoord2f32(1.0F, 1.0F);//
1145         GXPosition3f32(SIDE, SIDE, SIDE);  //7
1146         GXColor1u32(0x00ffffff);// cyan
1147         GXTexCoord2f32(0.0F, 1.0F);//
1148     GXEnd();
1149 }
1150 
1151 
1152 /*---------------------------------------------------------------------------*
1153     Name:           DrawArrow
1154 
1155     Description:    Draw arrow pointing in direction of Z sort (-Z axis)
1156 
1157     Arguments:      none
1158 
1159     Returns:        none
1160  *---------------------------------------------------------------------------*/
DrawArrow(void)1161 static void DrawArrow( void )
1162 {
1163     GXClearVtxDesc();
1164     GXSetVtxDesc(GX_VA_POS,  GX_INDEX16);
1165     GXSetVtxDesc(GX_VA_CLR0, GX_INDEX8);
1166 
1167     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
1168     GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
1169 
1170     GXSetNumChans(1);
1171     GXSetNumTexGens(0);
1172     GXSetNumTevStages(1);
1173 
1174     GXBegin(GX_TRIANGLES, GX_VTXFMT0, 3*4);
1175         // tri 0
1176         GXPosition1x16(10);
1177         GXColor1x8(1);// green
1178 
1179         GXPosition1x16(8);
1180         GXColor1x8(1);// green
1181 
1182         GXPosition1x16(11);
1183         GXColor1x8(1);// green
1184 
1185 
1186         // tri 1
1187         GXPosition1x16(10);
1188         GXColor1x8(0);// red
1189 
1190         GXPosition1x16(11);
1191         GXColor1x8(0);// red
1192 
1193         GXPosition1x16(9);
1194         GXColor1x8(0);// red
1195 
1196 
1197         // tri 2
1198         GXPosition1x16(9);
1199         GXColor1x8(1);// green
1200 
1201         GXPosition1x16(11);
1202         GXColor1x8(1);// green
1203 
1204         GXPosition1x16(8);
1205         GXColor1x8(1);// green
1206 
1207 
1208         // tri 3
1209         GXPosition1x16(10);
1210         GXColor1x8(1);// green
1211 
1212         GXPosition1x16(9);
1213         GXColor1x8(1);// green
1214 
1215         GXPosition1x16(8);
1216         GXColor1x8(1);// green
1217     GXEnd();
1218 }
1219 
1220 //
1221 //   My random functions
1222 //
1223 #define MAX_RAND    (0xffffffff)
1224 #define SEED        (0x38ba990e)
1225 
1226 static
init_rand(void)1227 void init_rand( void )
1228 {
1229     srand(SEED);
1230 }
1231 
1232 
1233 static
lrand(void)1234 u32 lrand( void )
1235 {
1236     u32 r;
1237     r = (u32) ((rand() & 0xffff) << 16) + (rand() & 0xffff);
1238     return(r);
1239 }
1240 
1241 
1242 static
frand(void)1243 f32 frand( void )
1244 {
1245     f32 f;
1246     f = (f32)lrand()/(f32)MAX_RAND;
1247     return (f);
1248 }
1249 
1250 
1251 /*---------------------------------------------------------------------------*
1252 
1253    Stats engine
1254 
1255  *---------------------------------------------------------------------------*/
1256 
1257 #define FLIPPER_CLOCK   162.0F // MHz
1258 
1259 #define STAT_TEXT_TOP   16
1260 #define STAT_TEXT_BOT   16
1261 #define STAT_TEXT_LFT   16
1262 #define STAT_TEXT_RHT   16
1263 
1264 #define STAT_CHAR_WD    8
1265 #define STAT_CHAR_HT    8
1266 #define STAT_CHAR_YSP   2  // vertical space
1267 
1268 /*---------------------------------------------------------------------------*
1269    Functions
1270  *---------------------------------------------------------------------------*/
1271 
1272 /*---------------------------------------------------------------------------*
1273     Name:           SetStats
1274 
1275     Description:    This function sets an array of GX performance metrics to
1276                     count. The name of each metric is specified in the text
1277                     array.  The current stat count is kept in the count array.
1278                     At the end of each loop, the metric will be printed at
1279                     the corner of the screen specified, either top-left, top-
1280                     right, bottom-left, or bottom-right.
1281 
1282                     If stat is NULL or nstats is zero, the performance
1283                     monitoring is disabled.
1284 
1285     Arguments:      stat  : An array of GXPerf metrics to count.
1286                     nstats: number of stats in the array or number you wish
1287                             to display.
1288                     disp  : display style of the stats:
1289                             0 = top-left
1290                             2 = bot-left
1291                             8 = serial output (OSReport)
1292 
1293     Returns:        None
1294  *---------------------------------------------------------------------------*/
SetStats(StatObj * stat,u32 nstats,StatDispMode disp)1295 static void SetStats( StatObj *stat, u32 nstats, StatDispMode disp )
1296 {
1297     if (stat == NULL || nstats == 0)
1298     {
1299         StatEnable = GX_DISABLE;
1300     }
1301     else
1302     {
1303         StatEnable  = GX_TRUE;
1304         Stat        = stat;
1305         StatIndx    = 0;
1306         StatMaxIndx = nstats;
1307         StatDisp    = disp;
1308         StatStrLen  = strlen(Stat[0].text);
1309     }
1310 }
1311 
1312 /*---------------------------------------------------------------------------*
1313     Name:           WriteStats
1314 
1315     Description:    This function calls a metric function for the next stat
1316                     to be counted.
1317 
1318     Arguments:      none
1319 
1320     Returns:        None
1321  *---------------------------------------------------------------------------*/
WriteStats(GXBool update)1322 static void WriteStats( GXBool update )
1323 {
1324     u32 cnt0, cnt1, cnt2, cnt3, cnt4;
1325     u32 cnt5, cnt6, cnt7, cnt8, cnt9;
1326 
1327     switch (Stat[StatIndx].stat_type)
1328     {
1329       case STAT_GP0:
1330         if (update)
1331         {
1332             cnt0 = GXReadGP0Metric();
1333             Stat[StatIndx].count = cnt0;
1334             GXSetGP0Metric(GX_PERF0_NONE);
1335         } else {
1336             GXSetGP0Metric((GXPerf0)Stat[StatIndx].stat);
1337             GXClearGP0Metric();
1338         }
1339 
1340         break;
1341 
1342       case STAT_GP1:
1343         if (update)
1344         {
1345             cnt0 = GXReadGP1Metric();
1346             Stat[StatIndx].count = cnt0;
1347             GXSetGP1Metric(GX_PERF1_NONE);
1348         } else {
1349             GXSetGP1Metric((GXPerf1)Stat[StatIndx].stat);
1350             GXClearGP1Metric();
1351         }
1352         break;
1353 
1354       case STAT_MEM:
1355         if (update)
1356         {
1357             GXReadMemMetric( &cnt0, &cnt1, &cnt2, &cnt3, &cnt4,
1358                              &cnt5, &cnt6, &cnt7, &cnt8, &cnt9 );
1359             cpReq     = cnt0;
1360             tcReq     = cnt1;
1361             cpuRdReq  = cnt2;
1362             cpuWrReq  = cnt3;
1363             dspReq    = cnt4;
1364             ioReq     = cnt5;
1365             viReq     = cnt6;
1366             peReq     = cnt7;
1367             rfReq     = cnt8;
1368             fiReq     = cnt9;
1369         } else {
1370             GXClearMemMetric();
1371         }
1372         break;
1373 
1374       case STAT_PIX:
1375         if (update)
1376         {
1377             GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5);
1378             topPixIn  = cnt0;
1379             topPixOut = cnt1;
1380             botPixIn  = cnt2;
1381             botPixOut = cnt3;
1382             clrPixIn  = cnt4;
1383             copyClks  = cnt5;
1384         } else {
1385             GXClearPixMetric();
1386         }
1387         break;
1388 
1389       case STAT_VC:
1390         if (update)
1391         {
1392             GXReadVCacheMetric(&cnt0, &cnt1, &cnt2);
1393             vcCheck = cnt0;
1394             vcMiss  = cnt1;
1395             vcStall = cnt2;
1396         } else {
1397             GXSetVCacheMetric(GX_VC_POS);
1398             GXClearVCacheMetric();
1399         }
1400         break;
1401 
1402       case STAT_FR: // fill rate info
1403         if (update)
1404         {
1405             GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5);
1406             topPixIn  = cnt0;
1407             topPixOut = cnt1;
1408             botPixIn  = cnt2;
1409             botPixOut = cnt3;
1410             clrPixIn  = cnt4;
1411             copyClks  = cnt5;
1412             StatClocks = GXReadGP0Metric();
1413             GXSetGP0Metric(GX_PERF0_NONE);
1414         } else {
1415             GXClearPixMetric();
1416             GXSetGP0Metric(GX_PERF0_CLOCKS);
1417             GXClearGP0Metric();
1418         }
1419         break;
1420 
1421       case STAT_TBP: // texture B/pixel
1422       case STAT_TBW: // texture bandwidth/pixel
1423         GXClearPixMetric();
1424         if (update)
1425         {
1426             GXReadPixMetric(&cnt0, &cnt1, &cnt2, &cnt3, &cnt4, &cnt5);
1427             topPixIn  = cnt0;
1428             topPixOut = cnt1;
1429             botPixIn  = cnt2;
1430             botPixOut = cnt3;
1431             clrPixIn  = cnt4;
1432             copyClks  = cnt5;
1433             StatClocks = GXReadGP0Metric();
1434             GXReadMemMetric( &cnt0, &cnt1, &cnt2, &cnt3, &cnt4,
1435                              &cnt5, &cnt6, &cnt7, &cnt8, &cnt9 );
1436             tcReq = cnt1;
1437             GXSetGP0Metric(GX_PERF0_NONE);
1438         } else {
1439             GXClearMemMetric();
1440             GXSetGP0Metric(GX_PERF0_CLOCKS);
1441             GXClearGP0Metric();
1442         }
1443         break;
1444 
1445       case STAT_MYC:
1446       case STAT_MYR:
1447         // do nothing, user will compute
1448         break;
1449       default:
1450         OSHalt("SetStats: Unknown demo stat type\n");
1451       break;
1452     }
1453 }
1454 
1455 /*---------------------------------------------------------------------------*
1456     Name:           UpdateStats
1457 
1458     Description:    This function calls GXPerfMetric for the next stat to be
1459                     counted.
1460 
1461     Arguments:      none
1462 
1463     Returns:        None
1464  *---------------------------------------------------------------------------*/
UpdateStats(GXBool inc)1465 static void UpdateStats( GXBool inc )
1466 {
1467     WriteStats(inc);
1468 
1469     if (inc)
1470     {
1471         StatIndx++;
1472         if (StatIndx == StatMaxIndx)
1473         {
1474             StatIndx = 0;
1475         }
1476     }
1477 }
1478 
1479 /*---------------------------------------------------------------------------*
1480     Name:           PrintStats
1481 
1482     Description:    This function prints the statistics currently being
1483                     counted. Only one statistic gets updated each frame,
1484                     but they are printed every frame.
1485 
1486     Arguments:      none
1487 
1488     Returns:        None
1489  *---------------------------------------------------------------------------*/
1490 #define StatPrintf(str, val) \
1491     DEMOPrintf(text_x, text_y, 0, str, Stat[i].text, val)
1492 
1493 #define StatOSReport(str, val) \
1494     OSReport(str, Stat[i].text, val)
1495 
PrintStats(void)1496 static void PrintStats( void )
1497 {
1498     GXRenderModeObj* rmode;
1499     u32              i;
1500     s16              text_x, text_y, text_yinc;
1501     u16              wd, ht;
1502     f32              rate;
1503 
1504     if (StatDisp == STAT_IO) // dump to serial output
1505     {
1506         for (i = 0; i < StatMaxIndx; i++)
1507         {
1508             switch (Stat[i].stat_type)
1509             {
1510               case STAT_PIX:
1511                 switch(Stat[i].stat)
1512                 {
1513                   case STAT_PIX_TI:
1514                     StatOSReport("%s: %8d\n", topPixIn);
1515                     break;
1516                   case STAT_PIX_TO:
1517                     StatOSReport("%s: %8d\n", topPixOut);
1518                     break;
1519                   case STAT_PIX_BI:
1520                     StatOSReport("%s: %8d\n", botPixIn);
1521                     break;
1522                   case STAT_PIX_BO:
1523                     StatOSReport("%s: %8d\n", botPixOut);
1524                     break;
1525                   case STAT_PIX_CI:
1526                     StatOSReport("%s: %8d\n", clrPixIn);
1527                     break;
1528                   case STAT_PIX_CC:
1529                     StatOSReport("%s: %8d\n", copyClks);
1530                     break;
1531                 }
1532                 break;
1533 
1534               case STAT_FR:
1535                 rate = FLIPPER_CLOCK * (f32)(topPixIn + botPixIn) /
1536                                        (f32)(StatClocks - copyClks);
1537                 StatOSReport("%s: %8.2f\n", rate);
1538                 break;
1539 
1540               case STAT_TBW:
1541                 rate = FLIPPER_CLOCK * (f32)(tcReq*32) /
1542                                        (f32)(StatClocks - copyClks);
1543                 StatOSReport("%s: %8.2f\n", rate);
1544                 break;
1545 
1546               case STAT_TBP:
1547                 rate = (f32)(tcReq*32) / (topPixIn + botPixIn);
1548                 StatOSReport("%s: %8.2f\n", rate);
1549                 break;
1550 
1551               case STAT_VC:
1552                 switch(Stat[i].stat)
1553                 {
1554                   case STAT_VC_CHK:
1555                     StatOSReport("%s: %8d\n", vcCheck);
1556                     break;
1557                   case STAT_VC_MISS:
1558                     StatOSReport("%s: %8d\n", vcMiss);
1559                     break;
1560                   case STAT_VC_STALL:
1561                     StatOSReport("%s: %8d\n", vcStall);
1562                     break;
1563                 }
1564                 break;
1565 
1566               case STAT_MYR: // use stat as a second input
1567                 rate = (f32) Stat[i].stat / (f32) Stat[i].count;
1568                 StatOSReport("%s: %8.2f\n", rate);
1569                 break;
1570 
1571               case STAT_MEM:
1572                 switch(Stat[i].stat)
1573                 {
1574                   case STAT_MEM_CP:
1575                     StatOSReport("%s: %8d\n", cpReq);
1576                     break;
1577                   case STAT_MEM_TC:
1578                     StatOSReport("%s: %8d\n", tcReq);
1579                     break;
1580                   case STAT_MEM_CPUR:
1581                     StatOSReport("%s: %8d\n", cpuRdReq);
1582                     break;
1583                   case STAT_MEM_CPUW:
1584                     StatOSReport("%s: %8d\n", cpuWrReq);
1585                     break;
1586                   case STAT_MEM_DSP:
1587                     StatOSReport("%s: %8d\n", dspReq);
1588                     break;
1589                   case STAT_MEM_IO:
1590                     StatOSReport("%s: %8d\n", ioReq);
1591                     break;
1592                   case STAT_MEM_VI:
1593                     StatOSReport("%s: %8d\n", viReq);
1594                     break;
1595                   case STAT_MEM_PE:
1596                     StatOSReport("%s: %8d\n", peReq);
1597                     break;
1598                   case STAT_MEM_RF:
1599                     StatOSReport("%s: %8d\n", rfReq);
1600                     break;
1601                   case STAT_MEM_FI:
1602                     StatOSReport("%s: %8d\n", fiReq);
1603                     break;
1604                 }
1605                 break;
1606 
1607               default:
1608                 StatOSReport("%s: %8d\n", Stat[i].count);
1609                 break;
1610             }
1611         }
1612     }
1613     else  // dump to screen
1614     {
1615         rmode = DEMOGetRenderModeObj();
1616 
1617         switch (StatDisp)
1618         {
1619           case STAT_TL:
1620             // text origin is top-left
1621             text_x = STAT_TEXT_LFT;
1622             text_y = STAT_TEXT_TOP;
1623             text_yinc = STAT_CHAR_HT + STAT_CHAR_YSP;
1624             wd = rmode->fbWidth;
1625             ht = rmode->xfbHeight;
1626             break;
1627           case STAT_BL:
1628             // text origin is bottom-left
1629             text_x = STAT_TEXT_LFT;
1630             text_y = (s16)(rmode->xfbHeight - STAT_TEXT_BOT - STAT_CHAR_HT);
1631             text_yinc = -(STAT_CHAR_HT + STAT_CHAR_YSP);
1632             wd = rmode->fbWidth;
1633             ht = rmode->xfbHeight;
1634             break;
1635           case STAT_TLD:
1636             // double-sized fonts, text origin is top-left
1637             text_x = (s16)(STAT_TEXT_LFT / 2);
1638             text_y = (s16)(STAT_TEXT_TOP / 2);
1639             text_yinc = STAT_CHAR_HT + STAT_CHAR_YSP / 2;
1640             wd = (u16)(rmode->fbWidth / 2);
1641             ht = (u16)(rmode->xfbHeight / 2);
1642             break;
1643           case STAT_BLD:
1644             // double-sized fonts, text origin is bottom-left
1645             text_x = (s16)(STAT_TEXT_LFT / 2);
1646             text_y = (s16)((rmode->xfbHeight - STAT_TEXT_BOT - STAT_CHAR_HT) / 2);
1647             text_yinc = -(STAT_CHAR_HT + STAT_CHAR_YSP / 2);
1648             wd = (u16)(rmode->fbWidth / 2);
1649             ht = (u16)(rmode->xfbHeight / 2);
1650             break;
1651         }
1652 
1653         // Init DEMOPuts library fonts
1654         DEMOInitCaption(DM_FT_OPQ, wd, ht);
1655 
1656         for ( i = 0; i < StatMaxIndx; i++ )
1657         {
1658             switch (Stat[i].stat_type)
1659             {
1660               case STAT_PIX:
1661                 // Pix Metric
1662                 switch(Stat[i].stat)
1663                 {
1664                   case STAT_PIX_TI:
1665                     StatPrintf("%s: %8d\n", topPixIn);
1666                     break;
1667                   case STAT_PIX_TO:
1668                     StatPrintf("%s: %8d\n", topPixOut);
1669                     break;
1670                   case STAT_PIX_BI:
1671                     StatPrintf("%s: %8d\n", botPixIn);
1672                     break;
1673                   case STAT_PIX_BO:
1674                     StatPrintf("%s: %8d\n", botPixOut);
1675                     break;
1676                   case STAT_PIX_CI:
1677                     StatPrintf("%s: %8d\n", clrPixIn);
1678                     break;
1679                   case STAT_PIX_CC:
1680                     StatPrintf("%s: %8d\n", copyClks);
1681                 }
1682                 break;
1683 
1684               case STAT_FR:
1685                 // Fill rate (MPixels/Sec)
1686                 rate = FLIPPER_CLOCK * (f32)(topPixIn + botPixIn) /
1687                                        (f32)(StatClocks - copyClks);
1688                 StatPrintf("%s: %8.2f\n", rate);
1689                 break;
1690 
1691               case STAT_TBW:
1692                 // Texture bandwidth (MB/sec)
1693                 rate = FLIPPER_CLOCK * (f32)(tcReq*32) /
1694                                        (f32)(StatClocks - copyClks);
1695                 StatPrintf("%s: %8.2f\n", rate);
1696                 break;
1697 
1698               case STAT_TBP:
1699                 // Texture bandwidth per pixel
1700                 rate = (f32)(tcReq*32) /
1701                        (f32)(topPixIn - botPixIn);
1702                 StatPrintf("%s: %8.3f\n", rate);
1703                 break;
1704 
1705               case STAT_VC:
1706                 // VertexCache Metric
1707                 switch(Stat[i].stat)
1708                 {
1709                   case STAT_VC_CHK:
1710                     StatPrintf("%s: %8d\n", vcCheck);
1711                     break;
1712                   case STAT_VC_MISS:
1713                     StatPrintf("%s: %8d\n", vcMiss);
1714                     break;
1715                   case STAT_VC_STALL:
1716                     StatPrintf("%s: %8d\n", vcStall);
1717                 }
1718                 break;
1719 
1720               case STAT_MEM:
1721                 // Mem Access Metric
1722                 switch(Stat[i].stat)
1723                 {
1724                   case STAT_MEM_CP:
1725                     StatPrintf("%s: %8d\n", cpReq);
1726                     break;
1727                   case STAT_MEM_TC:
1728                     StatPrintf("%s: %8d\n", tcReq);
1729                     break;
1730                   case STAT_MEM_CPUR:
1731                     StatPrintf("%s: %8d\n", cpuRdReq);
1732                     break;
1733                   case STAT_MEM_CPUW:
1734                     StatPrintf("%s: %8d\n", cpuWrReq);
1735                     break;
1736                   case STAT_MEM_DSP:
1737                     StatPrintf("%s: %8d\n", dspReq);
1738                     break;
1739                   case STAT_MEM_IO:
1740                     StatPrintf("%s: %8d\n", ioReq);
1741                     break;
1742                   case STAT_MEM_VI:
1743                     StatPrintf("%s: %8d\n", viReq);
1744                     break;
1745                   case STAT_MEM_PE:
1746                     StatPrintf("%s: %8d\n", peReq);
1747                     break;
1748                   case STAT_MEM_RF:
1749                     StatPrintf("%s: %8d\n", rfReq);
1750                     break;
1751                   case STAT_MEM_FI:
1752                     StatPrintf("%s: %8d\n", fiReq);
1753                     break;
1754                 }
1755                 break;
1756 
1757               case STAT_GP0:
1758               case STAT_GP1:
1759               case STAT_MYC:
1760                 StatPrintf("%s: %8d", Stat[i].count);
1761                 break;
1762 
1763               case STAT_MYR: // use stat as a second input
1764                 rate = (f32) Stat[i].stat / (f32) Stat[i].count;
1765                 StatPrintf("%s: %8.3f", rate);
1766                 break;
1767 
1768               default:
1769                 OSReport("Undefined stat type %d in PrintStats()\n",
1770                          Stat[i].stat_type);
1771                 break;
1772             }
1773 
1774             // update current line
1775             text_y += text_yinc;
1776         }
1777     } // screen dump
1778 }
1779 
1780 /*===========================================================================*/
1781 
1782