1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - tips - SwapCrossOver
3   File:     main.c
4 
5   Copyright 2003-2008 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   $Date:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 //---------------------------------------------------------------------------
19 // A sample for detect SwapBuffer of geometry engine cross over vblank.
20 //
21 // If you send SwapBuffer command to geometry command FIFO just before the vblank,
22 // you need detect the command will be executed before vblank or after vblank
23 // to sync 2D and 3D graphics.
24 // This sample detect SwapBuffer has been executed by the vblank.
25 //
26 // HOWTO:
27 // 1. If it is possible that no polygon are drawn, you draw invisible polygon
28 //    by DrawDummyPolygon().
29 // 2. If SwapBuffer has been executed by the vblank, polygon list RAM and vertex
30 //    list RAM count become 0. you can check these counts after 8 cycle from vblank.
31 //
32 // Operation:
33 //    Left, Right : Move a cube.
34 //    A           : Print parameters at the time called swapbuffer and after vblank.
35 //    B           : Send SwapBuffer command just before vblank, and print parameters.
36 //    Select      : Switch BG on/off.
37 //---------------------------------------------------------------------------
38 
39 #include <nitro.h>
40 #include "DEMO.h"
41 #include "data.h"
42 
43 
44 static void VCountEqIntr();
45 
46 static vs32 frame_cnt = 0;
47 
48 typedef struct
49 {
50     s32     vcount;                    // VCount
51     s32     fifo_cnt;                  // Geometry command fifo count.
52     s32     frame_cnt;                 // frame count
53     s32     polygon_num;               // count of PolygonList RAM.
54     s32     vertex_num;                // count of VertexList RAM.
55 }
56 t_geometry_stat;
57 
58 
59 
60 s16     gCubeGeometry[3 * 8] = {
61     FX16_ONE, FX16_ONE, FX16_ONE,
62     FX16_ONE, FX16_ONE, -FX16_ONE,
63     FX16_ONE, -FX16_ONE, FX16_ONE,
64     FX16_ONE, -FX16_ONE, -FX16_ONE,
65     -FX16_ONE, FX16_ONE, FX16_ONE,
66     -FX16_ONE, FX16_ONE, -FX16_ONE,
67     -FX16_ONE, -FX16_ONE, FX16_ONE,
68     -FX16_ONE, -FX16_ONE, -FX16_ONE
69 };
70 
71 
72 
73 
74 /*---------------------------------------------------------------------------*
75   Name:         DrawDummyPolygon
76 
77   Description:  Set a unvisible polygon, to Polygon List RAM and Vertex RAM.
78                 Please call this function with any POSITION VECTOR matrix stack.
79 
80   Arguments:    0 if PROJECTION matrix stack is full.
81                 1 if PROJECTION matrix stack has more area.
82 
83   Returns:      none
84  *---------------------------------------------------------------------------*/
DrawDummyPolygon(s32 pj_stacked)85 static void DrawDummyPolygon(s32 pj_stacked)
86 {
87     MtxFx44 mtx_pj;
88 
89     // move current matrix, and load identity matrix.
90     G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
91     G3_PushMtx();
92     G3_Identity();
93 
94     G3_MtxMode(GX_MTXMODE_PROJECTION);
95 
96     if (pj_stacked)
97     {
98         /* if stack is full, load current matrix */
99         while (G3X_GetClipMtx(&mtx_pj) != 0)
100         {
101         };
102     }
103     else
104     {
105         /* if stack has more area push matrix. */
106         G3_PushMtx();
107     }
108     G3_Identity();
109 
110     // draw unvisible polygon.
111     G3_PolygonAttr(GX_LIGHTMASK_NONE,  // no lights
112                    GX_POLYGONMODE_MODULATE,     // modulation mode
113                    GX_CULL_NONE,       // cull back
114                    0,                  // polygon ID(0 - 63)
115                    0,                  // alpha(0 - 31)
116                    GX_POLYGON_ATTR_MISC_DISP_1DOT       // OR of GXPolygonAttrMisc's value
117         );
118 
119     G3_Begin(GX_BEGIN_TRIANGLES);
120     {
121         G3_Vtx(0, 0, -FX32_ONE);
122         G3_Vtx(0, 0, -FX32_ONE);
123         G3_Vtx(0, 0, -FX32_ONE);
124     }
125     G3_End();
126 
127 
128     // restore current matrix.
129     G3_MtxMode(GX_MTXMODE_PROJECTION);
130     if (pj_stacked)
131     {
132         G3_LoadMtx44(&mtx_pj);
133     }
134     else
135     {
136         G3_PopMtx(1);
137     }
138     G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
139     G3_PopMtx(1);
140 }
141 
142 
143 
144 
145 //---------------------------------------------------------------------------
146 // Translate many geometry command to make time lag.
147 //---------------------------------------------------------------------------
PushHugeCommands()148 static void PushHugeCommands()
149 {
150     s32     i;
151     enum
152     { COMMAND_NUM = 95 };
153 
154     for (i = 0; i < COMMAND_NUM; i++)
155     {
156         G3_Direct3(G3OP_BOX_TEST, 0, 0, 0);
157     }
158 }
159 
160 
161 //---------------------------------------------------------------------------
162 // Send vertex data from table.
163 //---------------------------------------------------------------------------
vtx(int idx)164 static void vtx(int idx)
165 {
166     G3_Vtx(gCubeGeometry[idx * 3], gCubeGeometry[idx * 3 + 1], gCubeGeometry[idx * 3 + 2]);
167 }
168 
169 
170 //---------------------------------------------------------------------------
171 // Send quad polygon data.
172 //---------------------------------------------------------------------------
quad(int idx0,int idx1,int idx2,int idx3)173 static void quad(int idx0, int idx1, int idx2, int idx3)
174 {
175     vtx(idx0);
176     vtx(idx1);
177     vtx(idx2);
178     vtx(idx3);
179 }
180 
181 
182 //---------------------------------------------------------------------------
183 // Draw cube function.
184 //---------------------------------------------------------------------------
drawCube(int alpha,u16 Rotate)185 static void drawCube(int alpha, u16 Rotate)
186 {
187 
188     {
189         fx16    s = FX_SinIdx(Rotate);
190         fx16    c = FX_CosIdx(Rotate);
191 
192         G3_RotX(s, c);
193         G3_RotY(s, c);
194         G3_RotZ(s, c);
195     }
196     G3_MaterialColorDiffAmb(GX_RGB(31, 31, 31), // diffuse
197                             GX_RGB(16, 16, 16), // ambient
198                             TRUE       // use diffuse as vtx color if TRUE
199         );
200 
201     G3_MaterialColorSpecEmi(GX_RGB(16, 16, 16), // specular
202                             GX_RGB(0, 0, 0),    // emission
203                             FALSE      // use shininess table if TRUE
204         );
205 
206     G3_PolygonAttr(GX_LIGHTMASK_NONE,  // no lights
207                    GX_POLYGONMODE_MODULATE,     // modulation mode
208                    GX_CULL_BACK,       // cull back
209                    0,                  // polygon ID(0 - 63)
210                    alpha,              // alpha(0 - 31)
211                    0                   // OR of GXPolygonAttrMisc's value
212         );
213 
214 
215     G3_Begin(GX_BEGIN_QUADS);
216     {
217         quad(2, 0, 4, 6);
218         quad(7, 5, 1, 3);
219         quad(6, 4, 5, 7);
220         quad(3, 1, 0, 2);
221         quad(5, 4, 0, 1);
222         quad(6, 7, 3, 2);
223     }
224     G3_End();
225 }
226 
227 
228 //---------------------------------------------------------------------------
229 // Init display settings.
230 //---------------------------------------------------------------------------
InitDisplay()231 static void InitDisplay()
232 {
233 
234     G3X_Init();                        // initialize the 3D graphics states
235     G3X_InitTable();                   // initialize tables
236 
237     G3X_InitMtxStack();                // initialize the matrix stack
238 
239     GX_SetBankForTex(GX_VRAM_TEX_0_A); // VRAM-A for texture images
240 
241     GX_SetBankForBG(GX_VRAM_BG_128_D); // VRAM-D for BGs
242 
243     GX_SetBankForTexPltt(GX_VRAM_TEXPLTT_0123_E);       // VRAM-E for texture palettes
244 
245     GX_SetBankForOBJ(GX_VRAM_OBJ_32_FG);        // VRAM-FG for OBJ
246 
247     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS,    // graphics mode
248                        GX_BGMODE_0,    // BGMODE is 0
249                        GX_BG0_AS_3D);  // BG #0 is for 3D
250 
251     GX_SetVisiblePlane(GX_PLANEMASK_BG0 |       // BG #0 for 3D
252                        GX_PLANEMASK_BG1 |       // BG #1 for text
253                        GX_PLANEMASK_OBJ // OBJ
254         );
255 
256     G2_SetBG0Priority(0);
257 
258     G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256,        // 256pix x 256pix text
259                      GX_BG_COLORMODE_256,       // use 16 colors mode
260                      GX_BG_SCRBASE_0x0000,      // screen base offset + 0x3800 is the address for BG #1 screen
261                      GX_BG_CHARBASE_0x04000,    // character base offset + 0x00000 is the address for BG #1 characters
262                      GX_BG_EXTPLTT_01  // use BGExtPltt slot #1 if BGExtPltt is enabled
263         );
264 
265     G2_SetBG1Priority(1);
266 
267     G2_BG1Mosaic(FALSE);
268 
269     G3X_SetShading(GX_SHADING_TOON);   // shading mode is toon
270 
271     G3X_AntiAlias(TRUE);               // enable antialias(without additional computing costs)
272 
273     G2_BlendNone();                    // no 2D alpha blending or brightness change
274 
275     //---------------------------------------------------------------------------
276     // After you start the geometry engine and the rendering one
277     // (by GX_SetPower etc.), G3_SwapBuffers must be called once before use
278     //---------------------------------------------------------------------------
279     G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
280 
281     //---------------------------------------------------------------------------
282     // Set clear color, depth and polygon ID.
283     //---------------------------------------------------------------------------
284     G3X_SetClearColor(GX_RGB(0, 0, 0), // clear color
285                       0,               // clear alpha
286                       0x7fff,          // clear depth
287                       63,              // clear polygon ID
288                       FALSE            // fog
289         );
290 
291     G3_ViewPort(0, 0, 255, 191);       // Viewport
292 
293     //---------------------------------------------------------------------------
294     // Set up the projection matrix
295     //---------------------------------------------------------------------------
296     {
297         fx32    right = FX32_ONE * 2;
298         fx32    left = FX32_ONE;
299         fx32    top = FX32_ONE * 3 / 4;
300         fx32    bottom = 0;
301         fx32    near = FX32_ONE;
302         fx32    far = FX32_ONE * 400;
303 
304         //---------------------------------------------------------------------------
305         // Switch MTXMODE to GX_MTXMODE_PROJECTION, and
306         // set a projection matrix onto the current projection matrix on the matrix stack
307         //---------------------------------------------------------------------------
308         G3_Perspective(FX32_SIN30, FX32_COS30,  // sine and cosine of FOVY
309                        FX32_ONE * 4 / 3,        // aspect
310                        near,           // near
311                        far,            // far
312                        NULL            // a pointer to a matrix if you use it
313             );
314 
315         G3_StoreMtx(0);
316     }
317 }
318 
319 
320 
321 
322 
323 //---------------------------------------------------------------------------
324 // Record current geometry state.
325 //---------------------------------------------------------------------------
RecordCurrentStat(t_geometry_stat * stat)326 static void RecordCurrentStat(t_geometry_stat * stat)
327 {
328 
329     stat->vcount = GX_GetVCount();
330     stat->fifo_cnt = G3X_GetCommandFifoCount();
331     stat->frame_cnt = frame_cnt;
332 }
333 
334 //---------------------------------------------------------------------------
335 // Print geometry stat.
336 //---------------------------------------------------------------------------
PrintStat(t_geometry_stat * stat1,t_geometry_stat * stat2)337 static void PrintStat(t_geometry_stat * stat1, t_geometry_stat * stat2)
338 {
339 #ifdef SDK_FINALROM
340 #pragma unused( stat1, stat2 )
341 #endif
342 
343     OS_Printf("[Before VBlank]\n");
344     OS_Printf("PolygonListRAM = %d/2048\t", stat1->polygon_num);
345     OS_Printf("VertexListRAM  = %d/6144\n", stat1->vertex_num);
346     OS_Printf("fr%x: VCOUNT=%d, FIFO_COUNT=%d\n", stat1->frame_cnt, stat1->vcount, stat1->fifo_cnt);
347 
348     OS_Printf("[After VBlank]\n");
349     OS_Printf("PolygonListRAM = %d/2048\t", stat2->polygon_num);
350     OS_Printf("VertexListRAM  = %d/6144\n", stat2->vertex_num);
351     OS_Printf("fr%x: VCOUNT=%d, FIFO_COUNT=%d\n", stat2->frame_cnt, stat2->vcount, stat2->fifo_cnt);
352 }
353 
354 
355 //---------------------------------------------------------------------------
356 // Main Loop.
357 //---------------------------------------------------------------------------
NitroMain(void)358 void NitroMain(void)
359 {
360     u16     Rotate = 0;                // for rotating cubes(0-65535)
361     u32     bg = 1;
362     s32     vp_x1 = 0, vp_y1 = 0, vp_x2 = 255, vp_y2 = 191;
363     fx32    cam_y = FX32_ONE, cam_z = FX32_ONE;
364     t_geometry_stat stat_before, stat_after;
365 
366     //---------------------------------------------------------------------------
367     // Initialize:
368     // They enable IRQ interrupts, initialize VRAM, and set BG #0 for 3D mode,
369     // and BG #1 for 2D mode.
370     //---------------------------------------------------------------------------
371     DEMOInitCommon();
372     DEMOInitVRAM();
373     InitDisplay();
374 
375     OS_SetIrqFunction(OS_IE_V_COUNT, VCountEqIntr);
376     GX_SetVCounterEqVal(191);
377     (void)OS_EnableIrqMask(OS_IE_V_COUNT);
378     (void)GX_VCounterEqIntr(TRUE);
379 
380     // Load 2D graphic data
381     GX_LoadBG1Char(d_natsunoumi_schDT, 0, sizeof(d_natsunoumi_schDT));
382     GX_LoadBGPltt(d_natsunoumi_sclDT, 0, sizeof(d_natsunoumi_sclDT));
383     GX_LoadBG1Scr(d_natsunoumi_sscDT, 0, sizeof(d_natsunoumi_sscDT));
384 
385     // not displayed if alpha is equal or less than 24
386     DEMOStartDisplay();
387 
388     while (1)
389     {
390         G3_ViewPort(vp_x1, vp_y1, vp_x2, vp_y2);
391 
392         DEMOReadKey();
393 
394         // switch BG ON/OFF.
395         if (DEMO_IS_TRIG(PAD_BUTTON_SELECT))
396         {
397             bg = !bg;
398         }
399 
400         if (bg)
401         {
402             GX_SetVisiblePlane(GX_PLANEMASK_BG0 |       // BG #0 for 3D
403                                GX_PLANEMASK_BG1 |       // BG #1 for text
404                                GX_PLANEMASK_OBJ // OBJ
405                 );
406         }
407         else
408         {
409             GX_SetVisiblePlane(GX_PLANEMASK_BG0 |       // BG #0 for 3D
410                                GX_PLANEMASK_OBJ // OBJ
411                 );
412         }
413 
414         // move position of cube.
415         if (DEMO_IS_PRESS(PAD_KEY_LEFT))
416         {
417             cam_y += FX32_ONE;
418         }
419         else if (DEMO_IS_PRESS(PAD_KEY_RIGHT))
420         {
421             cam_y -= FX32_ONE;
422         }
423 
424 
425         G3X_Reset();
426 
427         // Draw invisible polygon to Polygon RAM.
428         DrawDummyPolygon(FALSE);
429 
430         //---------------------------------------------------------------------------
431         // Set up the camera matrix
432         //---------------------------------------------------------------------------
433         {
434             VecFx32 Eye = { 0, 4 * FX32_ONE, FX32_ONE };        // camera position
435             VecFx32 at = { 0, 0, -5 * FX32_ONE };       // Viewpoint
436             VecFx32 vUp = { 0, FX32_ONE, 0 };   // Up
437 
438             at.x = cam_y / 16;
439             at.x = cam_y / 16;
440 
441             G3_LookAt(&Eye, &vUp, &at, NULL);   // set camera
442 
443         }
444 
445         G3_PushMtx();
446         G3_Translate(0, 0, -5 * FX32_ONE);
447         //---------------------------------------------------------------------------
448         // Send Cube
449         //---------------------------------------------------------------------------
450         Rotate += 256;
451 
452         G3_PushMtx();
453         G3_Translate(3 * (FX32_ONE >> 1), 0, 0);
454 
455         drawCube(31, Rotate);
456 
457         G3_PopMtx(1);
458 
459         G3_PopMtx(1);
460 
461         // If B button pushed, Wait vcount just before VBlank Inter.
462         if (DEMO_IS_PRESS(PAD_BUTTON_B))
463         {
464             OS_WaitInterrupt(1, OS_IE_V_COUNT);
465         }
466 
467         PushHugeCommands();
468 
469         stat_before.polygon_num = G3X_GetPolygonListRamCount();
470         stat_before.vertex_num = G3X_GetVtxListRamCount();
471 
472         // swapping the polygon list RAM, the vertex RAM, etc.
473         G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
474 
475         RecordCurrentStat(&stat_before);
476 
477         OS_WaitVBlankIntr();           // Waiting the end of VBlank interrupt
478 
479         RecordCurrentStat(&stat_after);
480 
481         // get PolygonListRAM count after more than 8 cycle from vblank.
482         stat_after.polygon_num = G3X_GetPolygonListRamCount();
483         stat_after.vertex_num = G3X_GetVtxListRamCount();
484 
485         // if vertex_num is not 0, SwapBuffers executed after VBlank.
486         if (stat_after.vertex_num != 0)
487         {
488             PrintStat(&stat_before, &stat_after);
489 
490             OS_Printf(" SwapBuffer cross over a vblank!\n\n");
491         }
492         else if (DEMO_IS_PRESS(PAD_BUTTON_A))
493         {
494             PrintStat(&stat_before, &stat_after);
495 
496             OS_Printf("OK!\n\n");
497         }
498     }
499 }
500 
501 
502 //---------------------------------------------------------------------------
503 // VBlank interrupt function:
504 //---------------------------------------------------------------------------
VBlankIntr(void)505 void VBlankIntr(void)
506 {
507     frame_cnt++;
508     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // checking VBlank interrupt
509 }
510 
511 
512 //---------------------------------------------------------------------------
513 // VCount Equal interrupt function:
514 //---------------------------------------------------------------------------
VCountEqIntr(void)515 static void VCountEqIntr(void)
516 {
517     OS_SetIrqCheckFlag(OS_IE_V_COUNT); // checking VCount interrupt
518 }
519