/*---------------------------------------------------------------------------* Project: TwlSDK - tips - SwapCrossOver File: main.c Copyright 2003-2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-09-17#$ $Rev: 8556 $ $Author: okubata_ryoma $ *---------------------------------------------------------------------------*/ //--------------------------------------------------------------------------- // A sample for detect SwapBuffer of geometry engine cross over vblank. // // If you send SwapBuffer command to geometry command FIFO just before the vblank, // you need detect the command will be executed before vblank or after vblank // to sync 2D and 3D graphics. // This sample detect SwapBuffer has been executed by the vblank. // // HOWTO: // 1. If it is possible that no polygon are drawn, you draw invisible polygon // by DrawDummyPolygon(). // 2. If SwapBuffer has been executed by the vblank, polygon list RAM and vertex // list RAM count become 0. you can check these counts after 8 cycle from vblank. // // Operation: // Left, Right : Move a cube. // A : Print parameters at the time called swapbuffer and after vblank. // B : Send SwapBuffer command just before vblank, and print parameters. // Select : Switch BG on/off. //--------------------------------------------------------------------------- #include #include "DEMO.h" #include "data.h" static void VCountEqIntr(); static vs32 frame_cnt = 0; typedef struct { s32 vcount; // VCount s32 fifo_cnt; // Geometry command fifo count. s32 frame_cnt; // frame count s32 polygon_num; // count of PolygonList RAM. s32 vertex_num; // count of VertexList RAM. } t_geometry_stat; s16 gCubeGeometry[3 * 8] = { FX16_ONE, FX16_ONE, FX16_ONE, FX16_ONE, FX16_ONE, -FX16_ONE, FX16_ONE, -FX16_ONE, FX16_ONE, FX16_ONE, -FX16_ONE, -FX16_ONE, -FX16_ONE, FX16_ONE, FX16_ONE, -FX16_ONE, FX16_ONE, -FX16_ONE, -FX16_ONE, -FX16_ONE, FX16_ONE, -FX16_ONE, -FX16_ONE, -FX16_ONE }; /*---------------------------------------------------------------------------* Name: DrawDummyPolygon Description: Set a unvisible polygon, to Polygon List RAM and Vertex RAM. Please call this function with any POSITION VECTOR matrix stack. Arguments: 0 if PROJECTION matrix stack is full. 1 if PROJECTION matrix stack has more area. Returns: none *---------------------------------------------------------------------------*/ static void DrawDummyPolygon(s32 pj_stacked) { MtxFx44 mtx_pj; // move current matrix, and load identity matrix. G3_MtxMode(GX_MTXMODE_POSITION_VECTOR); G3_PushMtx(); G3_Identity(); G3_MtxMode(GX_MTXMODE_PROJECTION); if (pj_stacked) { /* if stack is full, load current matrix */ while (G3X_GetClipMtx(&mtx_pj) != 0) { }; } else { /* if stack has more area push matrix. */ G3_PushMtx(); } G3_Identity(); // draw unvisible polygon. G3_PolygonAttr(GX_LIGHTMASK_NONE, // no lights GX_POLYGONMODE_MODULATE, // modulation mode GX_CULL_NONE, // cull back 0, // polygon ID(0 - 63) 0, // alpha(0 - 31) GX_POLYGON_ATTR_MISC_DISP_1DOT // OR of GXPolygonAttrMisc's value ); G3_Begin(GX_BEGIN_TRIANGLES); { G3_Vtx(0, 0, -FX32_ONE); G3_Vtx(0, 0, -FX32_ONE); G3_Vtx(0, 0, -FX32_ONE); } G3_End(); // restore current matrix. G3_MtxMode(GX_MTXMODE_PROJECTION); if (pj_stacked) { G3_LoadMtx44(&mtx_pj); } else { G3_PopMtx(1); } G3_MtxMode(GX_MTXMODE_POSITION_VECTOR); G3_PopMtx(1); } //--------------------------------------------------------------------------- // Translate many geometry command to make time lag. //--------------------------------------------------------------------------- static void PushHugeCommands() { s32 i; enum { COMMAND_NUM = 95 }; for (i = 0; i < COMMAND_NUM; i++) { G3_Direct3(G3OP_BOX_TEST, 0, 0, 0); } } //--------------------------------------------------------------------------- // Send vertex data from table. //--------------------------------------------------------------------------- static void vtx(int idx) { G3_Vtx(gCubeGeometry[idx * 3], gCubeGeometry[idx * 3 + 1], gCubeGeometry[idx * 3 + 2]); } //--------------------------------------------------------------------------- // Send quad polygon data. //--------------------------------------------------------------------------- static void quad(int idx0, int idx1, int idx2, int idx3) { vtx(idx0); vtx(idx1); vtx(idx2); vtx(idx3); } //--------------------------------------------------------------------------- // Draw cube function. //--------------------------------------------------------------------------- static void drawCube(int alpha, u16 Rotate) { { fx16 s = FX_SinIdx(Rotate); fx16 c = FX_CosIdx(Rotate); G3_RotX(s, c); G3_RotY(s, c); G3_RotZ(s, c); } G3_MaterialColorDiffAmb(GX_RGB(31, 31, 31), // diffuse GX_RGB(16, 16, 16), // ambient TRUE // use diffuse as vtx color if TRUE ); G3_MaterialColorSpecEmi(GX_RGB(16, 16, 16), // specular GX_RGB(0, 0, 0), // emission FALSE // use shininess table if TRUE ); G3_PolygonAttr(GX_LIGHTMASK_NONE, // no lights GX_POLYGONMODE_MODULATE, // modulation mode GX_CULL_BACK, // cull back 0, // polygon ID(0 - 63) alpha, // alpha(0 - 31) 0 // OR of GXPolygonAttrMisc's value ); G3_Begin(GX_BEGIN_QUADS); { quad(2, 0, 4, 6); quad(7, 5, 1, 3); quad(6, 4, 5, 7); quad(3, 1, 0, 2); quad(5, 4, 0, 1); quad(6, 7, 3, 2); } G3_End(); } //--------------------------------------------------------------------------- // Init display settings. //--------------------------------------------------------------------------- static void InitDisplay() { G3X_Init(); // initialize the 3D graphics states G3X_InitTable(); // initialize tables G3X_InitMtxStack(); // initialize the matrix stack GX_SetBankForTex(GX_VRAM_TEX_0_A); // VRAM-A for texture images GX_SetBankForBG(GX_VRAM_BG_128_D); // VRAM-D for BGs GX_SetBankForTexPltt(GX_VRAM_TEXPLTT_0123_E); // VRAM-E for texture palettes GX_SetBankForOBJ(GX_VRAM_OBJ_32_FG); // VRAM-FG for OBJ GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, // graphics mode GX_BGMODE_0, // BGMODE is 0 GX_BG0_AS_3D); // BG #0 is for 3D GX_SetVisiblePlane(GX_PLANEMASK_BG0 | // BG #0 for 3D GX_PLANEMASK_BG1 | // BG #1 for text GX_PLANEMASK_OBJ // OBJ ); G2_SetBG0Priority(0); G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, // 256pix x 256pix text GX_BG_COLORMODE_256, // use 16 colors mode GX_BG_SCRBASE_0x0000, // screen base offset + 0x3800 is the address for BG #1 screen GX_BG_CHARBASE_0x04000, // character base offset + 0x00000 is the address for BG #1 characters GX_BG_EXTPLTT_01 // use BGExtPltt slot #1 if BGExtPltt is enabled ); G2_SetBG1Priority(1); G2_BG1Mosaic(FALSE); G3X_SetShading(GX_SHADING_TOON); // shading mode is toon G3X_AntiAlias(TRUE); // enable antialias(without additional computing costs) G2_BlendNone(); // no 2D alpha blending or brightness change //--------------------------------------------------------------------------- // After you start the geometry engine and the rendering one // (by GX_SetPower etc.), G3_SwapBuffers must be called once before use //--------------------------------------------------------------------------- G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W); //--------------------------------------------------------------------------- // Set clear color, depth and polygon ID. //--------------------------------------------------------------------------- G3X_SetClearColor(GX_RGB(0, 0, 0), // clear color 0, // clear alpha 0x7fff, // clear depth 63, // clear polygon ID FALSE // fog ); G3_ViewPort(0, 0, 255, 191); // Viewport //--------------------------------------------------------------------------- // Set up the projection matrix //--------------------------------------------------------------------------- { fx32 right = FX32_ONE * 2; fx32 left = FX32_ONE; fx32 top = FX32_ONE * 3 / 4; fx32 bottom = 0; fx32 near = FX32_ONE; fx32 far = FX32_ONE * 400; //--------------------------------------------------------------------------- // Switch MTXMODE to GX_MTXMODE_PROJECTION, and // set a projection matrix onto the current projection matrix on the matrix stack //--------------------------------------------------------------------------- G3_Perspective(FX32_SIN30, FX32_COS30, // sine and cosine of FOVY FX32_ONE * 4 / 3, // aspect near, // near far, // far NULL // a pointer to a matrix if you use it ); G3_StoreMtx(0); } } //--------------------------------------------------------------------------- // Record current geometry state. //--------------------------------------------------------------------------- static void RecordCurrentStat(t_geometry_stat * stat) { stat->vcount = GX_GetVCount(); stat->fifo_cnt = G3X_GetCommandFifoCount(); stat->frame_cnt = frame_cnt; } //--------------------------------------------------------------------------- // Print geometry stat. //--------------------------------------------------------------------------- static void PrintStat(t_geometry_stat * stat1, t_geometry_stat * stat2) { #ifdef SDK_FINALROM #pragma unused( stat1, stat2 ) #endif OS_Printf("[Before VBlank]\n"); OS_Printf("PolygonListRAM = %d/2048\t", stat1->polygon_num); OS_Printf("VertexListRAM = %d/6144\n", stat1->vertex_num); OS_Printf("fr%x: VCOUNT=%d, FIFO_COUNT=%d\n", stat1->frame_cnt, stat1->vcount, stat1->fifo_cnt); OS_Printf("[After VBlank]\n"); OS_Printf("PolygonListRAM = %d/2048\t", stat2->polygon_num); OS_Printf("VertexListRAM = %d/6144\n", stat2->vertex_num); OS_Printf("fr%x: VCOUNT=%d, FIFO_COUNT=%d\n", stat2->frame_cnt, stat2->vcount, stat2->fifo_cnt); } //--------------------------------------------------------------------------- // Main Loop. //--------------------------------------------------------------------------- void NitroMain(void) { u16 Rotate = 0; // for rotating cubes(0-65535) u32 bg = 1; s32 vp_x1 = 0, vp_y1 = 0, vp_x2 = 255, vp_y2 = 191; fx32 cam_y = FX32_ONE, cam_z = FX32_ONE; t_geometry_stat stat_before, stat_after; //--------------------------------------------------------------------------- // Initialize: // They enable IRQ interrupts, initialize VRAM, and set BG #0 for 3D mode, // and BG #1 for 2D mode. //--------------------------------------------------------------------------- DEMOInitCommon(); DEMOInitVRAM(); InitDisplay(); OS_SetIrqFunction(OS_IE_V_COUNT, VCountEqIntr); GX_SetVCounterEqVal(191); (void)OS_EnableIrqMask(OS_IE_V_COUNT); (void)GX_VCounterEqIntr(TRUE); // Load 2D graphic data GX_LoadBG1Char(d_natsunoumi_schDT, 0, sizeof(d_natsunoumi_schDT)); GX_LoadBGPltt(d_natsunoumi_sclDT, 0, sizeof(d_natsunoumi_sclDT)); GX_LoadBG1Scr(d_natsunoumi_sscDT, 0, sizeof(d_natsunoumi_sscDT)); // not displayed if alpha is equal or less than 24 DEMOStartDisplay(); while (1) { G3_ViewPort(vp_x1, vp_y1, vp_x2, vp_y2); DEMOReadKey(); // switch BG ON/OFF. if (DEMO_IS_TRIG(PAD_BUTTON_SELECT)) { bg = !bg; } if (bg) { GX_SetVisiblePlane(GX_PLANEMASK_BG0 | // BG #0 for 3D GX_PLANEMASK_BG1 | // BG #1 for text GX_PLANEMASK_OBJ // OBJ ); } else { GX_SetVisiblePlane(GX_PLANEMASK_BG0 | // BG #0 for 3D GX_PLANEMASK_OBJ // OBJ ); } // move position of cube. if (DEMO_IS_PRESS(PAD_KEY_LEFT)) { cam_y += FX32_ONE; } else if (DEMO_IS_PRESS(PAD_KEY_RIGHT)) { cam_y -= FX32_ONE; } G3X_Reset(); // Draw invisible polygon to Polygon RAM. DrawDummyPolygon(FALSE); //--------------------------------------------------------------------------- // Set up the camera matrix //--------------------------------------------------------------------------- { VecFx32 Eye = { 0, 4 * FX32_ONE, FX32_ONE }; // camera position VecFx32 at = { 0, 0, -5 * FX32_ONE }; // Viewpoint VecFx32 vUp = { 0, FX32_ONE, 0 }; // Up at.x = cam_y / 16; at.x = cam_y / 16; G3_LookAt(&Eye, &vUp, &at, NULL); // set camera } G3_PushMtx(); G3_Translate(0, 0, -5 * FX32_ONE); //--------------------------------------------------------------------------- // Send Cube //--------------------------------------------------------------------------- Rotate += 256; G3_PushMtx(); G3_Translate(3 * (FX32_ONE >> 1), 0, 0); drawCube(31, Rotate); G3_PopMtx(1); G3_PopMtx(1); // If B button pushed, Wait vcount just before VBlank Inter. if (DEMO_IS_PRESS(PAD_BUTTON_B)) { OS_WaitInterrupt(1, OS_IE_V_COUNT); } PushHugeCommands(); stat_before.polygon_num = G3X_GetPolygonListRamCount(); stat_before.vertex_num = G3X_GetVtxListRamCount(); // swapping the polygon list RAM, the vertex RAM, etc. G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W); RecordCurrentStat(&stat_before); OS_WaitVBlankIntr(); // Waiting the end of VBlank interrupt RecordCurrentStat(&stat_after); // get PolygonListRAM count after more than 8 cycle from vblank. stat_after.polygon_num = G3X_GetPolygonListRamCount(); stat_after.vertex_num = G3X_GetVtxListRamCount(); // if vertex_num is not 0, SwapBuffers executed after VBlank. if (stat_after.vertex_num != 0) { PrintStat(&stat_before, &stat_after); OS_Printf(" SwapBuffer cross over a vblank!\n\n"); } else if (DEMO_IS_PRESS(PAD_BUTTON_A)) { PrintStat(&stat_before, &stat_after); OS_Printf("OK!\n\n"); } } } //--------------------------------------------------------------------------- // VBlank interrupt function: //--------------------------------------------------------------------------- void VBlankIntr(void) { frame_cnt++; OS_SetIrqCheckFlag(OS_IE_V_BLANK); // checking VBlank interrupt } //--------------------------------------------------------------------------- // VCount Equal interrupt function: //--------------------------------------------------------------------------- static void VCountEqIntr(void) { OS_SetIrqCheckFlag(OS_IE_V_COUNT); // checking VCount interrupt }