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