/*---------------------------------------------------------------------------* Copyright (C) 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. *---------------------------------------------------------------------------*/ ////=========================================================================== /// DEMOGfx.c /// /// This is graphics system code for the DEMO library. /// ////=========================================================================== #include #include #include #include // A bit like asserts, but even for NDEBUG=TRUE: #define DEMOCheck(x,y) if (!(x)) { OSReport("%s\n", y); while(1) OSSleepSeconds(1); } GX2ColorBuffer DEMOColorBuffer; GX2DepthBuffer DEMODepthBuffer; void *DEMOScanBufferPtr; // DEMO Gfx Context State GX2ContextState *DEMOContextState; u32 *DEMOCommandBufferBasePtr; #define DEMO_GFX_COMMAND_BUFFER_POOL_SIZE 1024*1024*sizeof(u32) static BOOL gDemoGfxRunningFlag=FALSE; static BOOL gDemoGfxTVEnabled=FALSE; static BOOL gDemoGfxForceMEM2=FALSE; BOOL gDemoGfxInForeground=TRUE; static MEMHeapHandle gDEMOMem1Heap = MEM_HEAP_INVALID_HANDLE; static MEMHeapHandle gDEMOBucketHeap = MEM_HEAP_INVALID_HANDLE; static char gDemoAssetsDir[MAX_ASSET_DIR_LEN] = "assets/"; // State from init that needs to be preserved when reacquiring foreground. static GX2TVRenderMode gDemoGfxRenderMode; static GX2SurfaceFormat gDemoGfxScanOutCBFormat; static u32 gDemoGfxScanSize; // Other preserved items static u32 gDemoGfxRenderWidth; static u32 gDemoGfxRenderHeight; static u32 gDemoGfxSwapInterval; // Instance static DEMOGfxInstance* gDemoGfxCurInstance = NULL; //GPU Job Control DEMOGfxGPUTask *pgDemoGfxGPUTaskList = NULL; u32 gDemoGfxGPUFence = 1; // Start with fence unlocked u64 *gpDemoGfxGPUTs = NULL; u64 gDemoGfxTimeVal = 0; static void* DEMOGX2RAlloc(GX2RResourceFlags resourceFlags, u32 byteCount, u32 alignment) { if (GX2TestBitFlagsAny(resourceFlags, GX2R_BIND_COLOR_BUFFER | GX2R_BIND_DEPTH_BUFFER | GX2R_BIND_SCAN_BUFFER | GX2R_BIND_GS_RING | GX2R_USAGE_FORCE_MEM1) && !GX2TestBitFlagsAny(resourceFlags, GX2R_USAGE_FORCE_MEM2)) { return DEMOGfxAllocMEM1(byteCount, alignment); } else { return DEMOGfxAllocMEM2(byteCount, alignment); } } static void DEMOGX2RFree(GX2RResourceFlags resourceFlags, void* pMem) { if (GX2TestBitFlagsAny(resourceFlags, GX2R_BIND_COLOR_BUFFER | GX2R_BIND_DEPTH_BUFFER | GX2R_BIND_SCAN_BUFFER | GX2R_BIND_GS_RING | GX2R_USAGE_FORCE_MEM1) && !GX2TestBitFlagsAny(resourceFlags, GX2R_USAGE_FORCE_MEM2)) { DEMOGfxFreeMEM1(pMem); } else { DEMOGfxFreeMEM2(pMem); } } void *DEMOGfxAllocMEM1(u32 size, u32 align) { void *ptr; if (align < 4) { align = 4; } // DEMOGfxMem1HeapInit() must be called first to init the heap. DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE); // Use the expanded heap for demos. ptr = MEMAllocFromExpHeapEx(gDEMOMem1Heap, size, align); GX2NotifyMemAlloc(ptr, size, align); DEMOAssert(ptr&&"Failed MEM1 alloc"); return ptr; } void DEMOGfxFreeMEM1(void * ptr) { if (gDemoGfxInForeground) MEMFreeToExpHeap(gDEMOMem1Heap, ptr); GX2NotifyMemFree(ptr); } void *DEMOGfxAllocBucket(u32 size, u32 align) { DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE); void * ptr = MEMAllocFromExpHeapEx(gDEMOBucketHeap, size, align); GX2NotifyMemAlloc(ptr, size, align); DEMOAssert(ptr); return ptr; } void DEMOGfxFreeBucket(void * ptr) { if (gDemoGfxInForeground) MEMFreeToExpHeap(gDEMOBucketHeap, ptr); GX2NotifyMemFree(ptr); } void *DEMOGfxAllocMEM2(u32 size, u32 align) { void *ptr; if (align < 4) { align = 4; } // FINAL MEMORY MANAGEMENT MODEL ptr = DEMOAllocEx(size, align); GX2NotifyMemAlloc(ptr, size, align); DEMOAssert(ptr&&"Failed MEM2 alloc"); return ptr; } void DEMOGfxFreeMEM2(void * ptr) { // FINAL MEMORY MANAGEMENT MODEL DEMOFree(ptr); GX2NotifyMemFree(ptr); } static u32 DEMOGfxCallbackAcquiredForeground(void* unused) { DEMOGfxAcquiredForeground(); // No issues return 0; } static u32 DEMOGfxCallbackReleaseForeground(void* unused) { DEMOGfxReleaseForeground(); // No issues return 0; } DEMOGfxInstance* DEMOGfxInit(int argc, char *argv[]) { void *ptr; u32 scanSize; GX2Boolean scaleNeeded; u32 i; char *p; u32 renderWidth = 1280; u32 renderHeight = 720; // Default to SRGB for gamma GX2SurfaceFormat renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB; GX2SurfaceFormat scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB; GX2SurfaceFormat renderDBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT; GX2AAMode renderAAMode = GX2_AA_MODE_1X; GX2Boolean renderHiZ = GX2_TRUE; static const u32 tvRenderModeTable[] = { 640, 480, GX2_TV_RENDER_480_NARROW, // 4:3 ratio (640x480) 854, 480, GX2_TV_RENDER_480_WIDE, // 16:9 ratio (854x480) 1280, 720, GX2_TV_RENDER_720, // 16:9 for all the rest... 1920, 1080, GX2_TV_RENDER_1080, }; #define RM_TABLE_SZ 4 GX2TVRenderMode renderMode; // Init flags gDemoGfxRunningFlag=FALSE; gDemoGfxTVEnabled=FALSE; gDemoGfxForceMEM2=FALSE; // Asset Directory strcpy(gDemoAssetsDir, "assets/"); // Alloc Gfx command buffer pool DEMOCommandBufferBasePtr = (u32 *) DEMOAllocEx( DEMO_GFX_COMMAND_BUFFER_POOL_SIZE, GX2_DEFAULT_BUFFER_ALIGNMENT); DEMOCheck(DEMOCommandBufferBasePtr, "Failed to allocate command buffer pool"); // Passing user allocated cb buffer and command-line arguments to gx2Init u32 gx2InitAttribs[] = { GX2_INIT_ATTRIB_CB_BASE, (u32)DEMOCommandBufferBasePtr, // cb buffer GX2_INIT_ATTRIB_CB_SIZE, (u32)DEMO_GFX_COMMAND_BUFFER_POOL_SIZE, // cb size GX2_INIT_ATTRIB_ARGC, (u32)argc, // number of args GX2_INIT_ATTRIB_ARGV, (u32)argv, // command-line args GX2_INIT_ATTRIB_NULL // terminates the list }; // Initialize GX2 library GX2Init(gx2InitAttribs); s32 gx2DebugMode=-1; s32 gx2rDebugOptions=-1; u32 swapInterval = 1; #define SKIP_NON_DIGIT(c) ((c)!=0&&((c)<'0'||(c)>'9')) // Analyze arguments // Note that all arguments might be in a single string! for (i = 0; i < argc; ++i) { p = strstr(argv[i], "DEMO_WIDTH"); if (p != 0){ renderWidth = (u32)atoi(p+10+SKIP_NON_DIGIT(p[10])); } p = strstr(argv[i], "DEMO_HEIGHT"); if (p != 0){ renderHeight = (u32)atoi(p+11+SKIP_NON_DIGIT(p[11])); } p = strstr(argv[i], "DEMO_CB_FORMAT"); if (p != 0){ p = p+14+SKIP_NON_DIGIT(p[14]); if(strncmp(p, "10_10_10_2", 10) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM; } else if(strncmp(p, "2_10_10_10", 10) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM; } else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB; } else if(strncmp(p, "8_8_8_8", 7) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM; } else if(strncmp(p, "16_16_16_16F", 12) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT; } else if(strncmp(p, "32_32_32_32F", 12) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT; } else if(strncmp(p, "16", 2) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCD_R16_UNORM; } else if(strncmp(p, "32F", 3) == 0){ renderCBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT; } else { DEMOPrintf("Unrecognized CB format: %s\n",p); } } p = strstr(argv[i], "DEMO_SCAN_FORMAT"); if (p != 0){ p = p+16+SKIP_NON_DIGIT(p[16]); if(strncmp(p, "10_10_10_2", 10) == 0){ scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM; }else if(strncmp(p, "2_10_10_10", 10) == 0){ scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM; }else if(strncmp(p, "8_8_8_8_SRGB", 12) == 0){ scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB; }else if(strncmp(p, "8_8_8_8", 7) == 0){ scanOutCBFormat = GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM; } else { DEMOPrintf("Unrecognized SCAN format: %s\n",p); } } p = strstr(argv[i], "DEMO_DB_FORMAT"); if (p != 0){ p = p+14+SKIP_NON_DIGIT(p[14]); if(strncmp(p, "16", 2) == 0){ renderDBFormat = GX2_SURFACE_FORMAT_TCD_R16_UNORM; }else if(strncmp(p, "8_24F", 5) == 0){ renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_FLOAT; }else if(strncmp(p, "8_24", 4) == 0){ renderDBFormat = GX2_SURFACE_FORMAT_D_D24_S8_UNORM; }else if(strncmp(p, "X24_8_32F", 9) == 0){ renderDBFormat = GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24; }else if(strncmp(p, "32F", 3) == 0){ renderDBFormat = GX2_SURFACE_FORMAT_TCD_R32_FLOAT; } else { DEMOPrintf("Unrecognized DB format: %s\n",p); } } p = strstr(argv[i], "DEMO_AA_MODE"); if (p != 0){ renderAAMode = (GX2AAMode)atoi(p+12+SKIP_NON_DIGIT(p[12])); GX2_CHECK_ENUM_RANGE(renderAAMode, GX2_AA_MODE) } p = strstr(argv[i], "DEMO_FONT_DISABLE"); if (p != 0){ DEMOFontDrawEnable(FALSE); DEMOPrintf("DEMO: DISABLE_FONT\n"); } p = strstr(argv[i], "DEMO_HIZ_DISABLE"); if (p != 0){ DEMOPrintf("DEMO: DISABLE_HIZ\n"); renderHiZ = GX2_FALSE; } p = strstr(argv[i], "DEMO_GX2_DEBUG_MODE"); if (p != 0) { sscanf(p+strlen("DEMO_GX2_DEBUG_MODE="), "%i", &gx2DebugMode); // allows hex notation } p = strstr(argv[i], "DEMO_GX2R_DEBUG_OPTIONS"); if (p != 0) { sscanf(p+strlen("DEMO_GX2R_DEBUG_OPTIONS="), "%i", &gx2rDebugOptions); // allows hex notation } p = strstr(argv[i], "DEMO_SWAP_INTERVAL"); if (p != 0) { u32 offset=strlen("DEMO_SWAP_INTERVAL"); swapInterval = atoi(p+offset+SKIP_NON_DIGIT(p[offset])); OSReport("DEMO: swap interval=%d\n", swapInterval); } p = strstr(argv[i], "DEMO_FORCE_MEM2"); if (p != 0){ gDemoGfxForceMEM2 = TRUE; DEMOPrintf("DEMO: FORCE_MEM2\n"); DEMOPrintf("DEMO: Performance will be signifcantly worse!\n"); } // Modify the assets directory if DEMO_ASSETS_DIR is passed in p = strstr(argv[i], "DEMO_ASSETS_DIR="); if (p != 0){ char tempBuffer[MAX_ASSET_DIR_LEN]; tempBuffer[MAX_ASSET_DIR_LEN - 2] = 0; strncpy(tempBuffer, p+strlen("DEMO_ASSETS_DIR="), MAX_ASSET_DIR_LEN - 2); // replace EOL or ',' with terminating 0 char* p2 = tempBuffer; for( ; *p2 != '\n' && *p2 != '\r' && *p2 != ',' && *p2 != 0; p2++ ) {} *p2 = 0; // Make sure the asset directory ends with a forward slash if (*(p2 - 1) != '/') { *p2 = '/'; *(p2 + 1) = 0; } strcpy(gDemoAssetsDir, tempBuffer); } } //Use a different MEM1 allocator for DEMO lib. DEMOGfxMem1HeapInit(); DEMOGfxBucketHeapInit(); if (gx2DebugMode!=-1) { DEMOPrintf("DEMO: GX2 debug mode=%#04x\n", gx2DebugMode); GX2SetDebugMode((GX2DebugMode)gx2DebugMode); } #ifdef _DEBUG // If no GX2R debug options specified, default some of them in debug builds if (gx2rDebugOptions==-1) { gx2rDebugOptions = GX2R_DEBUG_GUARD_BANDS_ENABLED | GX2R_DEBUG_LEAK_CHECK | GX2R_DEBUG_CHECK_GPU_CONTENTION; } #endif if (gx2rDebugOptions!=-1) { DEMOPrintf("DEMO: GX2R debug options=%#04x\n", gx2rDebugOptions); GX2RSetDebugOptions((GX2RDebugOptions)gx2rDebugOptions); } // Hook in the demo allocators for GX2R GX2RSetAllocator(DEMOGX2RAlloc, DEMOGX2RFree); char *aaStr[4]={ "1X", "2X", "4X", "8X" }; DEMOPrintf("DEMO: Rendering TV:%dx%d CB:%s DB:%s ScanCB:%s AA:%s\n", renderWidth, renderHeight, &DEMOGfxGetSurfaceFormatName(renderCBFormat)[19], &DEMOGfxGetSurfaceFormatName(renderDBFormat)[19], &DEMOGfxGetSurfaceFormatName(scanOutCBFormat)[19], aaStr[renderAAMode]); // Choose an appropriate TV render mode based on desired dimensions for (i = 0; i < RM_TABLE_SZ; i++) { if (((tvRenderModeTable[i*3] >= renderWidth) && (tvRenderModeTable[i*3+1] >= renderHeight)) || i==(RM_TABLE_SZ-1)) { renderMode = (GX2TVRenderMode) tvRenderModeTable[i*3+2]; break; } } // Setup Scan Buffers; this must be done before setting up TV render targets! GX2CalcTVSize(renderMode, scanOutCBFormat, GX2_BUFFERING_DOUBLE, &scanSize, &scaleNeeded); // For Cafe, should put scan buffers in the foreground bucket DEMOScanBufferPtr = DEMOGfxAllocBucket(scanSize, GX2_SCAN_BUFFER_ALIGNMENT); DEMOCheck(DEMOScanBufferPtr!=NULL, "Scan buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, DEMOScanBufferPtr, scanSize); GX2SetTVBuffer(DEMOScanBufferPtr, scanSize, renderMode, scanOutCBFormat, GX2_BUFFERING_DOUBLE); // First, we do all the memory allocations to see what fits into MEM1. // Setup render buffer; designate it as "final" TV render target. GX2InitColorBufferFTV(&DEMOColorBuffer, renderWidth, renderHeight, renderCBFormat, renderAAMode); // AA mode may have changed due to display-related issues. // Please refer to the GX2 display documentation. renderAAMode = DEMOColorBuffer.surface.aa; ptr = DEMOGfxAllocMEM1(DEMOColorBuffer.surface.imageSize, DEMOColorBuffer.surface.alignment); DEMOCheck(ptr!=NULL, "Color buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMOColorBuffer.surface.imageSize); GX2InitColorBufferPtr(&DEMOColorBuffer, ptr); // Setup aux buffer if (DEMOColorBuffer.surface.aa != GX2_AA_MODE_1X) { u32 size, align; GX2CalcColorBufferAuxInfo(&DEMOColorBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); DEMOCheck(ptr!=NULL, "Color aux buffer alloc failed"); GX2InitColorBufferAuxPtr(&DEMOColorBuffer, ptr); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); // Aux buffer must be cleared manually to this value once: GX2UTSetupColorAuxBuffer(&DEMOColorBuffer); } // Setup Depth Buffer GX2InitDepthBuffer(&DEMODepthBuffer, renderWidth, renderHeight, renderDBFormat, renderAAMode); ptr = DEMOGfxAllocMEM1(DEMODepthBuffer.surface.imageSize, DEMODepthBuffer.surface.alignment); DEMOCheck(ptr!=NULL, "Depth buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODepthBuffer.surface.imageSize); GX2InitDepthBufferPtr(&DEMODepthBuffer, ptr); // Setup Hi-Z buffer if (renderHiZ) { u32 size, align; GX2CalcDepthBufferHiZInfo(&DEMODepthBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); DEMOCheck(ptr!=NULL, "Depth Hi-Z buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); GX2InitDepthBufferHiZPtr(&DEMODepthBuffer, ptr); } // Register a callback upon foreground acquire and release ProcUIRegisterCallback(PROCUI_MESSAGE_ACQUIRE, DEMOGfxCallbackAcquiredForeground, NULL, 100); ProcUIRegisterCallback(PROCUI_MESSAGE_RELEASE, DEMOGfxCallbackReleaseForeground, NULL, 100); // Save state for DEMOGfxAcquiredForeground gDemoGfxRenderMode = renderMode; gDemoGfxScanOutCBFormat = scanOutCBFormat; gDemoGfxScanSize = scanSize; // Save state for instancing gDemoGfxRenderWidth = renderWidth; gDemoGfxRenderHeight = renderHeight; gDemoGfxSwapInterval = swapInterval; // Create a new instance (including the context state) gDemoGfxCurInstance = NULL; DEMOGfxAddInstance(); // The main core is the one with GFX DEMOSetMainCore(OSGetCoreId()); // Indicate that graphics has been started gDemoGfxRunningFlag = TRUE; // Align on a cache-line boundary gpDemoGfxGPUTs = (u64*)DEMOGfxAllocMEM2(sizeof(u64), 32); *gpDemoGfxGPUTs = GX2_INVALID_COUNTER_VALUE_U64; GX2Invalidate(GX2_INVALIDATE_CPU, gpDemoGfxGPUTs, 32); return gDemoGfxCurInstance; } void DEMOGfxShutdown() { // Delete the instances DEMOGfxDeleteInstance(gDemoGfxCurInstance); // It is possible to exit from the background, but some API calls // can only happen from the foreground. Check a flag to see if this // processes is exiting from the foreground before calling APIs // that deal with foreground-only resources. // Disable video outputs if (gDemoGfxInForeground && OS_SHUTDOWN_RESTART != OSGetShutdownReason()) { GX2SetTVEnable(GX2_FALSE); } gDemoGfxTVEnabled = FALSE; // Free allocated buffers DEMOGfxFreeBucket(DEMOScanBufferPtr); if (DEMODepthBuffer.hiZPtr) { DEMOGfxFreeMEM1(DEMODepthBuffer.hiZPtr); DEMODepthBuffer.hiZPtr = NULL; } DEMOGfxFreeMEM1(DEMODepthBuffer.surface.imagePtr); if (DEMOColorBuffer.auxPtr) { DEMOGfxFreeMEM1(DEMOColorBuffer.auxPtr); DEMOColorBuffer.auxPtr = NULL; } DEMOGfxFreeMEM1(DEMOColorBuffer.surface.imagePtr); if (gDemoGfxInForeground) DEMOFree(DEMOCommandBufferBasePtr); // Free GPU Task Control System DEMOGfxFreeMEM2(gpDemoGfxGPUTs); if (pgDemoGfxGPUTaskList) { DEMOGfxFreeGPUTasks(); } // Shutdown GX2 (which is safe to call from the background); GX2Shutdown(); // Dump any leaked resources if enabled if (GX2RGetDebugOptions() & GX2R_DEBUG_LEAK_CHECK) { if (GX2TempGetResourceCount()>0) { OSReport("***DEMO: resources were not destroyed on shutdown\n"); GX2TempDumpResources(); ASSERT(FALSE && "Resources were not destroyed on shutdown"); } } // Unhook the GX2R allocator functions. GX2RSetAllocator(NULL, NULL); // Only destroy these heaps if this process is in the foreground. if (gDemoGfxInForeground) { DEMOGfxMem1HeapDestroy(); DEMOGfxBucketHeapDestroy(); } gDemoGfxRunningFlag = FALSE; } void DEMOGfxReleaseForeground() { // First wait for all pending draws to complete. GX2DrawDone(); // Release resources in MEM1 if (DEMODepthBuffer.hiZPtr) { DEMOGfxFreeMEM1(DEMODepthBuffer.hiZPtr); DEMODepthBuffer.hiZPtr = NULL; } DEMOGfxFreeMEM1(DEMODepthBuffer.surface.imagePtr); if (DEMOColorBuffer.auxPtr) { DEMOGfxFreeMEM1(DEMOColorBuffer.auxPtr); DEMOColorBuffer.auxPtr = NULL; } DEMOGfxFreeMEM1(DEMOColorBuffer.surface.imagePtr); // Free resources from the foreground bucket DEMOGfxFreeBucket(DEMOScanBufferPtr); // Destroy heaps that will not be available. DEMOGfxMem1HeapDestroy(); DEMOGfxBucketHeapDestroy(); // Mark the TV as disabled. gDemoGfxTVEnabled=FALSE; // Set a flag to indicate that this process is in the background. gDemoGfxInForeground=FALSE; OSMemoryBarrier(); } void DEMOGfxAcquiredForeground() { void *ptr; // Set a flag to indicate that this process is in the foreground. gDemoGfxInForeground=TRUE; OSMemoryBarrier(); // Recreate heaps that were lost. DEMOGfxMem1HeapInit(); DEMOGfxBucketHeapInit(); // For Cafe, should put scan buffers in the foreground bucket DEMOScanBufferPtr = DEMOGfxAllocBucket(gDemoGfxScanSize, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_CPU, DEMOScanBufferPtr, gDemoGfxScanSize); GX2SetTVBuffer(DEMOScanBufferPtr, gDemoGfxScanSize, gDemoGfxRenderMode, gDemoGfxScanOutCBFormat, GX2_BUFFERING_DOUBLE); // Re-allocate color buffer ptr = DEMOGfxAllocMEM1(DEMOColorBuffer.surface.imageSize, DEMOColorBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMOColorBuffer.surface.imageSize); GX2InitColorBufferPtr(&DEMOColorBuffer, ptr); // Setup aux buffer if (DEMOColorBuffer.surface.aa != GX2_AA_MODE_1X) { u32 size, align; GX2CalcColorBufferAuxInfo(&DEMOColorBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); GX2InitColorBufferAuxPtr(&DEMOColorBuffer, ptr); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); // Aux buffer must be cleared manually to this value once: GX2UTSetupColorAuxBuffer(&DEMOColorBuffer); } // Re-allocate depth buffer ptr = DEMOGfxAllocMEM1(DEMODepthBuffer.surface.imageSize, DEMODepthBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODepthBuffer.surface.imageSize); GX2InitDepthBufferPtr(&DEMODepthBuffer, ptr); // Setup Hi-Z buffer if (1) { // Allow testing with & without Hi-Z u32 size, align; GX2CalcDepthBufferHiZInfo(&DEMODepthBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); GX2InitDepthBufferHiZPtr(&DEMODepthBuffer, ptr); } GX2SetContextState(DEMOContextState); // Indicate that graphics has been started gDemoGfxRunningFlag = TRUE; } BOOL DEMOGfxIsRunning() { return gDemoGfxRunningFlag; } void DEMOGfxSetContextState(void) { GX2UTDebugTagIndent("DEMOGfxSetContextState()"); GX2SetContextState(DEMOContextState); GX2UTDebugTagUndent(); } void DEMOGfxBeforeRender(void) { GX2UTDebugTagIndent("DEMOGfxBeforeRender()"); // Allow CPU to run 1 frame ahead of GPU and display //DEMOGfxWaitForSwap(1, 0); //TEMP TODO: most of the demos rely on the CPU not being ahead of the GPU, until that's (maybe) going to get fixed // we need to leave the swap queue depth at 0. DEMOGfxWaitForSwap(0, 0); // Enabled when Demo Perf condition is met DEMOTestCheckPerfBegin(); GX2UTDebugTagUndent(); } void DEMOGfxDoneRender(void) { GX2UTDebugTagIndent("DEMOGfxDoneRender()"); // Enabled when Demo Perf condition is met DEMOTestCheckPerfEnd(); // This extra flush avoids a potential race condition that can occur with // the GX2R Resource Tracker: the swap buffer command might finish before // the time stamp of its CB is updated. The race condition would make the // resource appear still in use at the start of the next frame. This extra // flush makes sure that no GX2R resources share the same time stamp as // the swap buffer CB, thus avoiding the problem. GX2Flush(); GX2SwapBuffers(&DEMOColorBuffer); // Restore the context state after copy GX2SetContextState(DEMOContextState); // Do this before the flush so it's in the same CB as everything else GX2UTDebugTagUndent(); // Flush after swap, since swap goes into the FIFO GX2Flush(); // Enable video output after first frame rendered if (gDemoGfxTVEnabled == FALSE) { GX2SetTVEnable(GX2_TRUE); gDemoGfxTVEnabled = TRUE; } } void DEMOGfxDrawDone(void) { // Only if running and in the foreground if (APP_IN_FOREGROUND && DEMOGfxIsRunning()) GX2DrawDone(); } void DEMOGfxWaitForSwap(u32 depth, u32 percent) { GX2UTDebugTagIndent("DEMOGfxWaitForSwap()"); u32 swapCount, flipCount, waitCount=0; OSTime tLastFlip, tLastVsync; OSTime tNow; const OSTime t60 = (OSTime)OSSecondsToTicks(1.0f/59.94f); OSTime period; u32 swapInt = GX2GetSwapInterval(); if (swapInt != 0) { // Note: must be careful about unsigned wrap-around! // Wait for "depth" frames ago to post while (1) { GX2GetSwapStatus(&swapCount, &flipCount, &tLastFlip, &tLastVsync); if (flipCount+depth >= swapCount) break; // If we've waited over 10 seconds for a flip, consider the GPU hung // and stop running. if (waitCount++ > 60*GX2GetGPUTimeout()/1000) { OSReport("DEMOGfxWaitForSwap timed out. Potential GPU hang detected?\n"); GX2SetMiscParam(GX2_MISC_HANG_STATE, GX2_HANG_STATE_ETC); if (GX2GetMiscParam(GX2_MISC_HANG_RESPONSE) == GX2_HANG_RESPONSE_DEBUG) { GX2PrintGPUStatus(); OSDebugStrIfConnected(0); DEMOStopRunning(); } break; } // Call WaitForVsync instead of WaitForFlip due to possible // race condition of flip happening right after above test. // (There will always be more vsyncs, but not always more flips.) GX2WaitForVsync(); } // Wait for (percent * Swap Period) milliseconds since last flip period = (percent * swapInt * t60 / 100); tNow = OSGetSystemTime(); if (period > (tNow - tLastFlip)) { OSSleepTicks(period - (tNow - tLastFlip)); } } GX2UTDebugTagUndent(); } void DEMOGfxMem1HeapInit(void) { //A real game should use the frame heap directly to save memory, //but using an expanded heap makes the demos simpler. //For more information on MEM1 usage, go to // Operating System->Cafe Core OS (COS) Overview->Basic Memory Allocation->MEM1 //in the MAN pages. MEMHeapHandle hMEM1 = MEMGetBaseHeapHandle(MEM_ARENA_1); u32 uMEM1Size = MEMGetAllocatableSizeForFrmHeapEx(hMEM1,4); if (!gDemoGfxForceMEM2) { void* pStartOfMem1 = MEMAllocFromFrmHeapEx(hMEM1, uMEM1Size, 4); gDEMOMem1Heap = MEMCreateExpHeap(pStartOfMem1, uMEM1Size); } else { void* pStartOfMem1 = MEMAllocFromDefaultHeapEx(uMEM1Size, 4); gDEMOMem1Heap = MEMCreateExpHeap(pStartOfMem1, uMEM1Size); } DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE); } void DEMOGfxMem1HeapDestroy(void) { DEMOAssert(gDEMOMem1Heap != MEM_HEAP_INVALID_HANDLE); //Destroy the expanded heap and reset the frame heap to restore the allocation. MEMDestroyExpHeap(gDEMOMem1Heap); if (!gDemoGfxForceMEM2) { MEMHeapHandle hMEM1 = MEMGetBaseHeapHandle(MEM_ARENA_1); MEMFreeToFrmHeap(hMEM1, MEM_FRMHEAP_FREE_ALL); } else { MEMFreeToDefaultHeap(gDEMOMem1Heap); } gDEMOMem1Heap = MEM_HEAP_INVALID_HANDLE; } void DEMOGfxBucketHeapInit(void) { //A real game should use the frame heap directly to save memory, //but using an expanded heap makes the demos simpler. //For more information on Foreground Bucket usage, go to // Operating System->Cafe Core OS (COS) Overview->Basic Memory Allocation->Foreground Bucket //in the MAN pages. MEMHeapHandle hMEMFg = MEMGetBaseHeapHandle(MEM_ARENA_FG); u32 uMEMFgSize = MEMGetAllocatableSizeForFrmHeapEx(hMEMFg,4); void* pStartOfMemFg = MEMAllocFromFrmHeapEx(hMEMFg, uMEMFgSize, 4); gDEMOBucketHeap = MEMCreateExpHeap(pStartOfMemFg, uMEMFgSize); DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE); } void DEMOGfxBucketHeapDestroy(void) { DEMOAssert(gDEMOBucketHeap != MEM_HEAP_INVALID_HANDLE); //Destroy the expanded heap and reset the frame heap to restore the allocation. MEMDestroyExpHeap(gDEMOBucketHeap); gDEMOBucketHeap = MEM_HEAP_INVALID_HANDLE; MEMHeapHandle hMEMFg = MEMGetBaseHeapHandle(MEM_ARENA_FG); MEMFreeToFrmHeap(hMEMFg, MEM_FRMHEAP_FREE_ALL); } DEMOGfxInstance* DEMOGfxAddInstance(void) { // Setup Context State buffer DEMOContextState = (GX2ContextState *)DEMOGfxAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); DEMOCheck(DEMOContextState != NULL, "Context state buffer alloc failed"); // GX2SetupContextState will invalidate CPU cache for us GX2SetupContextState(DEMOContextState); // Setup render/depth buffers to be used now GX2SetColorBuffer(&DEMOColorBuffer, GX2_RENDER_TARGET_0); GX2SetDepthBuffer(&DEMODepthBuffer); // Misc graphics setup GX2SetViewport(0, 0, (f32)gDemoGfxRenderWidth, (f32)gDemoGfxRenderHeight, 0.0f, 1.0f); GX2SetScissor(0, 0, gDemoGfxRenderWidth, gDemoGfxRenderHeight); // Indicate that swaps can happen as fast as every vertical interval (1/60 sec) GX2SetSwapInterval(gDemoGfxSwapInterval); ///////////////////////////////////////////////////////////////////////////// // Create the new instance gDemoGfxCurInstance = (DEMOGfxInstance *)DEMOAlloc(sizeof(DEMOGfxInstance)); gDemoGfxCurInstance->contextState = DEMOContextState; return gDemoGfxCurInstance; } void DEMOGfxDeleteInstance(DEMOGfxInstance *instance) { DEMOGfxFreeMEM2(instance->contextState); DEMOFree(instance); // Edge case: delete current if (gDemoGfxCurInstance == instance) { gDemoGfxCurInstance = NULL; DEMOContextState = NULL; } } void DEMOGfxSetInstance(DEMOGfxInstance *instance) { gDemoGfxCurInstance = instance; DEMOContextState = instance->contextState; GX2SetContextState(DEMOContextState); } DEMOGfxInstance* DEMOGfxGetInstance(void) { return gDemoGfxCurInstance; } s32 DEMOGfxOpenAssetFile(const char* path, DEMOFSFileInfo* info) { char filename[MAX_ASSET_DIR_FULL_LEN]; strcpy(filename, gDemoAssetsDir); strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN); return DEMOFSOpenFile(filename, info); } s32 DEMOGfxGetAssetFileLength(const DEMOFSFileInfo* fileInfo, u32* length) { return DEMOFSGetLength(fileInfo, length); } s32 DEMOGfxReadAssetFile(DEMOFSFileInfo* fileInfo, void* addr, s32 length, s32 offset) { return DEMOFSRead(fileInfo, addr, length, offset); } s32 DEMOGfxCloseAssetFile(DEMOFSFileInfo* fileInfo) { return DEMOFSCloseFile(fileInfo); } void* DEMOGfxLoadAssetFile(const char* path, u32* len) { char filename[MAX_ASSET_DIR_FULL_LEN]; strcpy(filename, gDemoAssetsDir); strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN); return DEMOFSSimpleRead(filename, len); } void* DEMOGfxLoadAssetFileAlign(const char* path, u32* len, u32 alignSize) { char filename[MAX_ASSET_DIR_FULL_LEN]; strcpy(filename, gDemoAssetsDir); strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN); return DEMOFSSimpleReadAlign(filename, len, alignSize); } s32 DEMOGfxScanAssetDir(const char *path, u32 *pFileCount, u32 maxFiles, char** ppFileNames) { char filename[MAX_ASSET_DIR_FULL_LEN]; strcpy(filename, gDemoAssetsDir); strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN); return DEMOFSScanDir(filename, path, pFileCount, maxFiles, ppFileNames); } BOOL DEMOGfxFileExists(const char* path) { char filename[MAX_ASSET_DIR_FULL_LEN]; strcpy(filename, gDemoAssetsDir); strncat(filename, path, MAX_ASSET_DIR_FULL_LEN - MAX_ASSET_DIR_LEN); return DEMOFSFileExists(path); } const char *DEMOGfxGetAttribFormatName(GX2AttribFormat format) { switch(format) { case GX2_ATTRIB_FORMAT_8_UNORM: return "GX2_ATTRIB_FORMAT_8_UNORM"; // 0x0000 case GX2_ATTRIB_FORMAT_8_UINT: return "GX2_ATTRIB_FORMAT_8_UINT"; // 0x0100 case GX2_ATTRIB_FORMAT_8_SNORM: return "GX2_ATTRIB_FORMAT_8_SNORM"; // 0x0200 case GX2_ATTRIB_FORMAT_8_SINT: return "GX2_ATTRIB_FORMAT_8_SINT"; // 0x0300 case GX2_ATTRIB_FORMAT_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_UINT_TO_FLOAT"; // 0x0800 case GX2_ATTRIB_FORMAT_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_SINT_TO_FLOAT"; // 0x0a00 case GX2_ATTRIB_FORMAT_4_4_UNORM: return "GX2_ATTRIB_FORMAT_4_4_UNORM"; // 0x0001 case GX2_ATTRIB_FORMAT_16_UNORM: return "GX2_ATTRIB_FORMAT_16_UNORM"; // 0x0002 case GX2_ATTRIB_FORMAT_16_UINT: return "GX2_ATTRIB_FORMAT_16_UINT"; // 0x0102 case GX2_ATTRIB_FORMAT_16_SNORM: return "GX2_ATTRIB_FORMAT_16_SNORM"; // 0x0202 case GX2_ATTRIB_FORMAT_16_SINT: return "GX2_ATTRIB_FORMAT_16_SINT"; // 0x0302 case GX2_ATTRIB_FORMAT_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_FLOAT"; // 0x0803 case GX2_ATTRIB_FORMAT_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_UINT_TO_FLOAT"; // 0x0802 case GX2_ATTRIB_FORMAT_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_SINT_TO_FLOAT"; // 0x0a02 case GX2_ATTRIB_FORMAT_8_8_UNORM: return "GX2_ATTRIB_FORMAT_8_8_UNORM"; // 0x0004 case GX2_ATTRIB_FORMAT_8_8_UINT: return "GX2_ATTRIB_FORMAT_8_8_UINT"; // 0x0104 case GX2_ATTRIB_FORMAT_8_8_SNORM: return "GX2_ATTRIB_FORMAT_8_8_SNORM"; // 0x0204 case GX2_ATTRIB_FORMAT_8_8_SINT: return "GX2_ATTRIB_FORMAT_8_8_SINT"; // 0x0304 case GX2_ATTRIB_FORMAT_8_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_UINT_TO_FLOAT"; // 0x0804 case GX2_ATTRIB_FORMAT_8_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_SINT_TO_FLOAT"; // 0x0a04 case GX2_ATTRIB_FORMAT_32_UINT: return "GX2_ATTRIB_FORMAT_32_UINT"; // 0x0105 case GX2_ATTRIB_FORMAT_32_SINT: return "GX2_ATTRIB_FORMAT_32_SINT"; // 0x0305 case GX2_ATTRIB_FORMAT_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_FLOAT"; // 0x0806 case GX2_ATTRIB_FORMAT_16_16_UNORM: return "GX2_ATTRIB_FORMAT_16_16_UNORM"; // 0x0007 case GX2_ATTRIB_FORMAT_16_16_UINT: return "GX2_ATTRIB_FORMAT_16_16_UINT"; // 0x0107 case GX2_ATTRIB_FORMAT_16_16_SNORM: return "GX2_ATTRIB_FORMAT_16_16_SNORM"; // 0x0207 case GX2_ATTRIB_FORMAT_16_16_SINT: return "GX2_ATTRIB_FORMAT_16_16_SINT"; // 0x0307 case GX2_ATTRIB_FORMAT_16_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_FLOAT"; // 0x0808 case GX2_ATTRIB_FORMAT_16_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_UINT_TO_FLOAT"; // 0x0807 case GX2_ATTRIB_FORMAT_16_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_SINT_TO_FLOAT"; // 0x0a07 case GX2_ATTRIB_FORMAT_10_11_11_FLOAT: return "GX2_ATTRIB_FORMAT_10_11_11_FLOAT"; // 0x0809 case GX2_ATTRIB_FORMAT_8_8_8_8_UNORM: return "GX2_ATTRIB_FORMAT_8_8_8_8_UNORM"; // 0x000a case GX2_ATTRIB_FORMAT_8_8_8_8_UINT: return "GX2_ATTRIB_FORMAT_8_8_8_8_UINT"; // 0x010a case GX2_ATTRIB_FORMAT_8_8_8_8_SNORM: return "GX2_ATTRIB_FORMAT_8_8_8_8_SNORM"; // 0x020a case GX2_ATTRIB_FORMAT_8_8_8_8_SINT: return "GX2_ATTRIB_FORMAT_8_8_8_8_SINT"; // 0x030a case GX2_ATTRIB_FORMAT_8_8_8_8_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_8_8_UINT_TO_FLOAT"; // 0x080a case GX2_ATTRIB_FORMAT_8_8_8_8_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_8_8_8_8_SINT_TO_FLOAT"; // 0x0a0a case GX2_ATTRIB_FORMAT_10_10_10_2_UNORM: return "GX2_ATTRIB_FORMAT_10_10_10_2_UNORM"; // 0x000b case GX2_ATTRIB_FORMAT_10_10_10_2_UINT: return "GX2_ATTRIB_FORMAT_10_10_10_2_UINT"; // 0x010b case GX2_ATTRIB_FORMAT_10_10_10_2_SNORM: return "GX2_ATTRIB_FORMAT_10_10_10_2_SNORM"; // 0x020b case GX2_ATTRIB_FORMAT_10_10_10_2_SINT: return "GX2_ATTRIB_FORMAT_10_10_10_2_SINT"; // 0x030b case GX2_ATTRIB_FORMAT_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_UINT"; // 0x010c case GX2_ATTRIB_FORMAT_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_SINT"; // 0x030c case GX2_ATTRIB_FORMAT_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_FLOAT"; // 0x080d case GX2_ATTRIB_FORMAT_16_16_16_16_UNORM: return "GX2_ATTRIB_FORMAT_16_16_16_16_UNORM"; // 0x000e case GX2_ATTRIB_FORMAT_16_16_16_16_UINT: return "GX2_ATTRIB_FORMAT_16_16_16_16_UINT"; // 0x010e case GX2_ATTRIB_FORMAT_16_16_16_16_SNORM: return "GX2_ATTRIB_FORMAT_16_16_16_16_SNORM"; // 0x020e case GX2_ATTRIB_FORMAT_16_16_16_16_SINT: return "GX2_ATTRIB_FORMAT_16_16_16_16_SINT"; // 0x030e case GX2_ATTRIB_FORMAT_16_16_16_16_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_FLOAT"; // 0x080f case GX2_ATTRIB_FORMAT_16_16_16_16_UINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_UINT_TO_FLOAT"; // 0x080e case GX2_ATTRIB_FORMAT_16_16_16_16_SINT_TO_FLOAT: return "GX2_ATTRIB_FORMAT_16_16_16_16_SINT_TO_FLOAT"; // 0x0a0e case GX2_ATTRIB_FORMAT_32_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_32_UINT"; // 0x0110 case GX2_ATTRIB_FORMAT_32_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_32_SINT"; // 0x0310 case GX2_ATTRIB_FORMAT_32_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_32_FLOAT"; // 0x0811 case GX2_ATTRIB_FORMAT_32_32_32_32_UINT: return "GX2_ATTRIB_FORMAT_32_32_32_32_UINT"; // 0x0112 case GX2_ATTRIB_FORMAT_32_32_32_32_SINT: return "GX2_ATTRIB_FORMAT_32_32_32_32_SINT"; // 0x0312 case GX2_ATTRIB_FORMAT_32_32_32_32_FLOAT: return "GX2_ATTRIB_FORMAT_32_32_32_32_FLOAT"; // 0x0813 default: return "invalid format"; } } const char *DEMOGfxGetSurfaceFormatName(GX2SurfaceFormat format) { switch(format) { case GX2_SURFACE_FORMAT_INVALID: return "GX2_SURFACE_FORMAT_INVALID"; // 0x0000 case GX2_SURFACE_FORMAT_TC_R8_UNORM: return "GX2_SURFACE_FORMAT_TC_R8_UNORM"; // 0x0001 case GX2_SURFACE_FORMAT_TC_R8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_UINT"; // 0x0101 case GX2_SURFACE_FORMAT_TC_R8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_SNORM"; // 0x0201 case GX2_SURFACE_FORMAT_TC_R8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_SINT"; // 0x0301 case GX2_SURFACE_FORMAT_T_R4_G4_UNORM: return "GX2_SURFACE_FORMAT_T_R4_G4_UNORM"; // 0x0002 case GX2_SURFACE_FORMAT_TCD_R16_UNORM: return "GX2_SURFACE_FORMAT_TCD_R16_UNORM"; // 0x0005 case GX2_SURFACE_FORMAT_TC_R16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_UINT"; // 0x0105 case GX2_SURFACE_FORMAT_TC_R16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_SNORM"; // 0x0205 case GX2_SURFACE_FORMAT_TC_R16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_SINT"; // 0x0305 case GX2_SURFACE_FORMAT_TC_R16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_FLOAT"; // 0x0806 case GX2_SURFACE_FORMAT_TC_R8_G8_UNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_UNORM"; // 0x0007 case GX2_SURFACE_FORMAT_TC_R8_G8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_UINT"; // 0x0107 case GX2_SURFACE_FORMAT_TC_R8_G8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_SNORM"; // 0x0207 case GX2_SURFACE_FORMAT_TC_R8_G8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_SINT"; // 0x0307 case GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM: return "GX2_SURFACE_FORMAT_TCS_R5_G6_B5_UNORM"; // 0x0008 case GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM: return "GX2_SURFACE_FORMAT_TC_R5_G5_B5_A1_UNORM"; // 0x000a case GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM: return "GX2_SURFACE_FORMAT_TC_R4_G4_B4_A4_UNORM"; // 0x000b case GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM: return "GX2_SURFACE_FORMAT_TC_A1_B5_G5_R5_UNORM"; // 0x000c case GX2_SURFACE_FORMAT_TC_R32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_UINT"; // 0x010d case GX2_SURFACE_FORMAT_TC_R32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_SINT"; // 0x030d case GX2_SURFACE_FORMAT_TCD_R32_FLOAT: return "GX2_SURFACE_FORMAT_TCD_R32_FLOAT"; // 0x080e case GX2_SURFACE_FORMAT_TC_R16_G16_UNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_UNORM"; // 0x000f case GX2_SURFACE_FORMAT_TC_R16_G16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_UINT"; // 0x010f case GX2_SURFACE_FORMAT_TC_R16_G16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_SNORM"; // 0x020f case GX2_SURFACE_FORMAT_TC_R16_G16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_SINT"; // 0x030f case GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_G16_FLOAT"; // 0x0810 case GX2_SURFACE_FORMAT_D_D24_S8_UNORM: return "GX2_SURFACE_FORMAT_D_D24_S8_UNORM"; // 0x0011 // case GX2_SURFACE_FORMAT_T_R24_UNORM_X8: return "GX2_SURFACE_FORMAT_T_R24_UNORM_X8"; // 0x0011 case GX2_SURFACE_FORMAT_T_X24_G8_UINT: return "GX2_SURFACE_FORMAT_T_X24_G8_UINT"; // 0x0111 case GX2_SURFACE_FORMAT_D_D24_S8_FLOAT: return "GX2_SURFACE_FORMAT_D_D24_S8_FLOAT"; // 0x0811 case GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT: return "GX2_SURFACE_FORMAT_TC_R11_G11_B10_FLOAT"; // 0x0816 case GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM: return "GX2_SURFACE_FORMAT_TCS_R10_G10_B10_A2_UNORM"; // 0x0019 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_UINT"; // 0x0119 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SNORM: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SNORM"; // 0x0219 case GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SINT: return "GX2_SURFACE_FORMAT_TC_R10_G10_B10_A2_SINT"; // 0x0319 case GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM: return "GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_UNORM"; // 0x001a case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_UINT"; // 0x011a case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SNORM"; // 0x021a case GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT: return "GX2_SURFACE_FORMAT_TC_R8_G8_B8_A8_SINT"; // 0x031a case GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB: return "GX2_SURFACE_FORMAT_TCS_R8_G8_B8_A8_SRGB"; // 0x041a case GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM: return "GX2_SURFACE_FORMAT_TCS_A2_B10_G10_R10_UNORM"; // 0x001b case GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT: return "GX2_SURFACE_FORMAT_TC_A2_B10_G10_R10_UINT"; // 0x011b case GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24: return "GX2_SURFACE_FORMAT_D_D32_FLOAT_S8_UINT_X24"; // 0x081c // case GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24: return "GX2_SURFACE_FORMAT_T_R32_FLOAT_X8_X24"; // 0x081c case GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24: return "GX2_SURFACE_FORMAT_T_X32_G8_UINT_X24"; // 0x011c case GX2_SURFACE_FORMAT_TC_R32_G32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_UINT"; // 0x011d case GX2_SURFACE_FORMAT_TC_R32_G32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_SINT"; // 0x031d case GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT: return "GX2_SURFACE_FORMAT_TC_R32_G32_FLOAT"; // 0x081e case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UNORM"; // 0x001f case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_UINT"; // 0x011f case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SNORM"; // 0x021f case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_SINT"; // 0x031f case GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT: return "GX2_SURFACE_FORMAT_TC_R16_G16_B16_A16_FLOAT"; // 0x0820 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_UINT"; // 0x0122 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_SINT"; // 0x0322 case GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT: return "GX2_SURFACE_FORMAT_TC_R32_G32_B32_A32_FLOAT"; // 0x0823 case GX2_SURFACE_FORMAT_T_BC1_UNORM: return "GX2_SURFACE_FORMAT_T_BC1_UNORM"; // 0x0031 case GX2_SURFACE_FORMAT_T_BC1_SRGB: return "GX2_SURFACE_FORMAT_T_BC1_SRGB"; // 0x0431 case GX2_SURFACE_FORMAT_T_BC2_UNORM: return "GX2_SURFACE_FORMAT_T_BC2_UNORM"; // 0x0032 case GX2_SURFACE_FORMAT_T_BC2_SRGB: return "GX2_SURFACE_FORMAT_T_BC2_SRGB"; // 0x0432 case GX2_SURFACE_FORMAT_T_BC3_UNORM: return "GX2_SURFACE_FORMAT_T_BC3_UNORM"; // 0x0033 case GX2_SURFACE_FORMAT_T_BC3_SRGB: return "GX2_SURFACE_FORMAT_T_BC3_SRGB"; // 0x0433 case GX2_SURFACE_FORMAT_T_BC4_UNORM: return "GX2_SURFACE_FORMAT_T_BC4_UNORM"; // 0x0034 case GX2_SURFACE_FORMAT_T_BC4_SNORM: return "GX2_SURFACE_FORMAT_T_BC4_SNORM"; // 0x0234 case GX2_SURFACE_FORMAT_T_BC5_UNORM: return "GX2_SURFACE_FORMAT_T_BC5_UNORM"; // 0x0035 case GX2_SURFACE_FORMAT_T_BC5_SNORM: return "GX2_SURFACE_FORMAT_T_BC5_SNORM"; // 0x0235 case GX2_SURFACE_FORMAT_T_NV12_UNORM: return "GX2_SURFACE_FORMAT_T_NV12_UNORM"; // 0x0081 default: return "invalid format"; } } DEMOGfxGPUTask* DEMOGfxBeginGPUTask() { // Create a new time value, meaning a new key in the list u64 timeVal = gDemoGfxTimeVal; DEMOGfxGPUTask *pTask = (DEMOGfxGPUTask *)DEMOAlloc(sizeof(DEMOGfxGPUTask)); ASSERT(pTask && "Failed to allocate pTask!"); pTask->pDLPatchLoc = GX2BeginGPUTask(); pTask->timeVal = timeVal; pTask->next = pgDemoGfxGPUTaskList; pgDemoGfxGPUTaskList = pTask; GX2SubmitUserTimeStamp(gpDemoGfxGPUTs, timeVal, GX2_PIPE_EVENT_TOP, GX2_FALSE); return pTask; } void DEMOGfxEndGPUTask() { u64 timeVal = gDemoGfxTimeVal | DEMO_GPU_TASK_END_TS; GX2SubmitUserTimeStamp(gpDemoGfxGPUTs, timeVal, GX2_PIPE_EVENT_TOP, GX2_FALSE); GX2EndGPUTask(&gDemoGfxGPUFence); // Move to next timeval gDemoGfxTimeVal++; } void DEMOGfxInsertGPUTask(void *pDisplayList, u32 byteSize) { DEMOGfxGPUTask *pTask; u64 timeVal; // Set the fence gDemoGfxGPUFence = 0; GX2Invalidate(GX2_INVALIDATE_CPU, &gDemoGfxGPUFence, sizeof(u32)); timeVal = GX2ReadUserTimeStamp(gpDemoGfxGPUTs); // If it is a begin Ts if ((timeVal & DEMO_GPU_TASK_END_TS) == 0) { // Look for the patch entry for the next job timeVal++; } else { // Try looking up the patch entry after the next one timeVal = (timeVal & (~DEMO_GPU_TASK_END_TS)) + 2ull; } for (pTask = pgDemoGfxGPUTaskList; pTask != NULL; pTask = pTask->next) { if (pTask->timeVal == timeVal) break; } if (pTask) { // Read pTask->pDLPatchLoc, pass it to GX2SubmitUserGpuTask GX2InsertGPUTask((u32*)pTask->pDLPatchLoc, (u32*)pDisplayList, byteSize); } else { // the gpu is already idle, just call the new task directly GX2DirectCallDisplayList(pDisplayList, byteSize); } // Release the fence gDemoGfxGPUFence = 1; GX2Invalidate(GX2_INVALIDATE_CPU, &gDemoGfxGPUFence, sizeof(u32)); } void DEMOGfxFreeGPUTask(DEMOGfxGPUTask *pTask) { DEMOGfxGPUTask *pList; ASSERT(pgDemoGfxGPUTaskList && "Can't free a GPU Task from an empty list!"); for (pList = pgDemoGfxGPUTaskList; pList != NULL; pList = pList->next) { if (pList == pTask) { pList = pTask->next; break; } } DEMOFree(pTask); } void DEMOGfxFreeGPUTasks(void) { DEMOGfxGPUTask *pList, *pNext; ASSERT(pgDemoGfxGPUTaskList && "Can't free GPU Tasks from an empty list!"); for (pList = pgDemoGfxGPUTaskList; pList != NULL; pList = pNext) { pNext = pList->next; DEMOFree(pList); } }