/*---------------------------------------------------------------------------* Copyright 2010-2012 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. *---------------------------------------------------------------------------*/ ////=========================================================================== /// DEMODRC.c /// /// This is DRC 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); } #define _DEMO_NUM_DRC 2 GX2ColorBuffer DEMODRCColorBuffer; GX2DepthBuffer DEMODRCDepthBuffer; void *DEMODRCScanBufferPtr; // DEMO Gfx Context State GX2ContextState *DEMODRCContextState; static BOOL gDemoDRCRunningFlag = FALSE; static BOOL gDemoDRCOutputEnabled = FALSE; extern BOOL gDemoGfxInForeground; // State set at init time that needs to be used to reacquire foreground. static GX2DRCMode gDemoDRCRenderMode; static GX2SurfaceFormat gDemoDRCScanOutCBFormat; static u32 gDemoDRCScanSize; // Other preserved items static u32 gDemoDRCRenderWidth; static u32 gDemoDRCRenderHeight; // Instance static DEMODRCInstance* gDemoDRCCurInstance = NULL; static u32 DEMODRCCallbackAcquiredForeground(void* unused) { DEMODRCAcquiredForeground(); // No issues return 0; } static u32 DEMODRCCallbackReleaseForeground(void* unused) { DEMODRCReleaseForeground(); // No issues return 0; } DEMODRCInstance* DEMODRCInit(int argc, char *argv[]) { void *ptr; u32 scanSize; GX2Boolean scaleNeeded; u32 i; char *p; u32 renderWidth = 854; u32 renderHeight = 480; // 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; GX2DRCMode renderMode = GX2_DRC_SINGLE; #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_DRC_WIDTH"); if (p != 0){ renderWidth = (u32)atoi(p+14+SKIP_NON_DIGIT(p[14])); } p = strstr(argv[i], "DEMO_DRC_HEIGHT"); if (p != 0){ renderHeight = (u32)atoi(p+15+SKIP_NON_DIGIT(p[15])); } p = strstr(argv[i], "DEMO_DRC_CB_FORMAT"); if (p != 0){ p = p+18+SKIP_NON_DIGIT(p[18]); 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 { DEMOPrintf("Unrecognized CB format: %s\n",p); } } p = strstr(argv[i], "DEMO_DRC_SCAN_FORMAT"); if (p != 0){ p = p+20+SKIP_NON_DIGIT(p[20]); 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_DRC_DB_FORMAT"); if (p != 0){ p = p+18+SKIP_NON_DIGIT(p[18]); 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_DRC_AA_MODE"); if (p != 0){ renderAAMode = (GX2AAMode)atoi(p+16+SKIP_NON_DIGIT(p[16])); GX2_CHECK_ENUM_RANGE(renderAAMode, GX2_AA_MODE) } p = strstr(argv[i], "DEMO_DRC_MODE"); if (p != 0){ renderMode = (GX2DRCMode)atoi(p+13); GX2_CHECK_ENUM_RANGE(renderMode, GX2_DRC) } } char *aaStr[4]={ "1X", "2X", "4X", "8X" }; char *modeStr[4]={ "none", "Single", "Double", "Single 30Hz"}; DEMOPrintf("DEMO: Rendering DRC:%dx%d CB:%s DB:%s ScanCB:%s AA:%s Mode:%s\n", renderWidth, renderHeight, &DEMOGfxGetSurfaceFormatName(renderCBFormat)[19], &DEMOGfxGetSurfaceFormatName(renderDBFormat)[19], &DEMOGfxGetSurfaceFormatName(scanOutCBFormat)[19], aaStr[renderAAMode], modeStr[renderMode]); // Setup Scan Buffers GX2CalcDRCSize(renderMode, scanOutCBFormat, GX2_BUFFERING_DOUBLE, &scanSize, &scaleNeeded); // For Cafe, should put scan buffers in the foreground bucket DEMODRCScanBufferPtr = DEMOGfxAllocBucket(scanSize, GX2_SCAN_BUFFER_ALIGNMENT); DEMOCheck(DEMODRCScanBufferPtr!=NULL, "DRC Scan buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, DEMODRCScanBufferPtr, scanSize); GX2SetDRCBuffer(DEMODRCScanBufferPtr, scanSize, renderMode, scanOutCBFormat, GX2_BUFFERING_DOUBLE); // Setup render buffer GX2InitColorBuffer(&DEMODRCColorBuffer, renderWidth, renderHeight, renderCBFormat, renderAAMode); ptr = DEMOGfxAllocMEM1(DEMODRCColorBuffer.surface.imageSize, DEMODRCColorBuffer.surface.alignment); DEMOCheck(ptr!=NULL, "DRC Color buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCColorBuffer.surface.imageSize); GX2InitColorBufferPtr(&DEMODRCColorBuffer, ptr); // Setup aux buffer if (DEMODRCColorBuffer.surface.aa != GX2_AA_MODE_1X) { u32 size, align; GX2CalcColorBufferAuxInfo(&DEMODRCColorBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); DEMOCheck(ptr!=NULL, "DRC Color aux buffer alloc failed"); GX2InitColorBufferAuxPtr(&DEMODRCColorBuffer, ptr); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); // Aux buffer must be cleared manually to this value once: GX2UTSetupColorAuxBuffer(&DEMODRCColorBuffer); } // Setup Depth Buffer GX2InitDepthBuffer(&DEMODRCDepthBuffer, renderWidth, renderHeight, renderDBFormat, renderAAMode); ptr = DEMOGfxAllocMEM1(DEMODRCDepthBuffer.surface.imageSize, DEMODRCDepthBuffer.surface.alignment); DEMOCheck(ptr!=NULL, "DRC Depth buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCDepthBuffer.surface.imageSize); GX2InitDepthBufferPtr(&DEMODRCDepthBuffer, ptr); // Setup Hi-Z buffer if (1) { // Allow testing with & without Hi-Z u32 size, align; GX2CalcDepthBufferHiZInfo(&DEMODRCDepthBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); DEMOCheck(ptr!=NULL, "DRC Depth Hi-Z buffer alloc failed"); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); GX2InitDepthBufferHiZPtr(&DEMODRCDepthBuffer, ptr); } // Register a callback upon foreground acquire and release ProcUIRegisterCallback(PROCUI_MESSAGE_ACQUIRE, DEMODRCCallbackAcquiredForeground, NULL, 200); ProcUIRegisterCallback(PROCUI_MESSAGE_RELEASE, DEMODRCCallbackReleaseForeground, NULL, 200); // Save state for DEMODRCAcquireForeground gDemoDRCRenderMode = renderMode; gDemoDRCScanOutCBFormat = scanOutCBFormat; gDemoDRCScanSize = scanSize; // Save state for instancing gDemoDRCRenderWidth = renderWidth; gDemoDRCRenderHeight = renderHeight; // Create a new instance (including the context state) gDemoDRCCurInstance = NULL; DEMODRCAddInstance(); // Indicate that graphics has been started gDemoDRCRunningFlag = TRUE; return gDemoDRCCurInstance; } void DEMODRCShutdown() { // Delete the instances DEMODRCDeleteInstance(gDemoDRCCurInstance); gDemoDRCOutputEnabled = FALSE; // Disable video outputs if this process is in the foreground. if (gDemoGfxInForeground && OS_SHUTDOWN_RESTART != OSGetShutdownReason()) { GX2SetDRCEnable(GX2_FALSE); } // Free allocated buffers DEMOGfxFreeBucket(DEMODRCScanBufferPtr); if (DEMODRCDepthBuffer.hiZPtr) { DEMOGfxFreeMEM1(DEMODRCDepthBuffer.hiZPtr); DEMODRCDepthBuffer.hiZPtr = NULL; } DEMOGfxFreeMEM1(DEMODRCDepthBuffer.surface.imagePtr); if (DEMODRCColorBuffer.auxPtr) { DEMOGfxFreeMEM1(DEMODRCColorBuffer.auxPtr); DEMODRCColorBuffer.auxPtr = NULL; } DEMOGfxFreeMEM1(DEMODRCColorBuffer.surface.imagePtr); gDemoDRCRunningFlag = FALSE; } void DEMODRCReleaseForeground() { if (DEMODRCDepthBuffer.hiZPtr) { DEMOGfxFreeMEM1(DEMODRCDepthBuffer.hiZPtr); DEMODRCDepthBuffer.hiZPtr = NULL; } DEMOGfxFreeMEM1(DEMODRCDepthBuffer.surface.imagePtr); if (DEMODRCColorBuffer.auxPtr) { DEMOGfxFreeMEM1(DEMODRCColorBuffer.auxPtr); DEMODRCColorBuffer.auxPtr = NULL; } DEMOGfxFreeMEM1(DEMODRCColorBuffer.surface.imagePtr); DEMOGfxFreeBucket(DEMODRCScanBufferPtr); gDemoDRCOutputEnabled = FALSE; } void DEMODRCAcquiredForeground() { void * ptr; // For Cafe, should put scan buffers in the foreground bucket DEMODRCScanBufferPtr = DEMOGfxAllocBucket(gDemoDRCScanSize, GX2_SCAN_BUFFER_ALIGNMENT); GX2Invalidate(GX2_INVALIDATE_CPU, DEMODRCScanBufferPtr, gDemoDRCScanSize); GX2SetDRCBuffer(DEMODRCScanBufferPtr, gDemoDRCScanSize, gDemoDRCRenderMode, gDemoDRCScanOutCBFormat, GX2_BUFFERING_DOUBLE); // Re-allocate color buffer ptr = DEMOGfxAllocMEM1(DEMODRCColorBuffer.surface.imageSize, DEMODRCColorBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCColorBuffer.surface.imageSize); GX2InitColorBufferPtr(&DEMODRCColorBuffer, ptr); // Setup aux buffer if (DEMODRCColorBuffer.surface.aa != GX2_AA_MODE_1X) { u32 size, align; GX2CalcColorBufferAuxInfo(&DEMODRCColorBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); GX2InitColorBufferAuxPtr(&DEMODRCColorBuffer, ptr); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); // Aux buffer must be cleared manually to this value once: GX2UTSetupColorAuxBuffer(&DEMODRCColorBuffer); } // Re-allocate depth buffer ptr = DEMOGfxAllocMEM1(DEMODRCDepthBuffer.surface.imageSize, DEMODRCDepthBuffer.surface.alignment); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, DEMODRCDepthBuffer.surface.imageSize); GX2InitDepthBufferPtr(&DEMODRCDepthBuffer, ptr); // Setup Hi-Z buffer if (1) { // Allow testing with & without Hi-Z u32 size, align; GX2CalcDepthBufferHiZInfo(&DEMODRCDepthBuffer, &size, &align); ptr = DEMOGfxAllocMEM1(size, align); GX2Invalidate(GX2_INVALIDATE_CPU, ptr, size); GX2InitDepthBufferHiZPtr(&DEMODRCDepthBuffer, ptr); } GX2SetContextState(DEMODRCContextState); // Force the next call to DEMODRCDoneRender to enable DRC output. gDemoDRCOutputEnabled = FALSE; } BOOL DEMODRCIsRunning() { return gDemoDRCRunningFlag; } GX2DRCMode DEMODRCGetStatus() { return GX2GetSystemDRCMode(); } void DEMODRCSetContextState(void) { GX2SetContextState(DEMODRCContextState); } void DEMODRCBeforeRender(void) { // Set DRC Context GX2SetContextState(DEMODRCContextState); } void DEMODRCDoneRender(void) { // Copy Color Buffer to DRC SCAN Buffer GX2CopyColorBufferToScanBuffer(&DEMODRCColorBuffer, GX2_SCAN_TARGET_DRC_FIRST); // Restore Demo context state after copy DEMOGfxSetContextState(); // Enable video output after first frame rendered if (gDemoDRCOutputEnabled == FALSE) { GX2SetDRCEnable(GX2_TRUE); gDemoDRCOutputEnabled = TRUE; } } DEMODRCInstance* DEMODRCAddInstance(void) { // Setup Context State buffer DEMODRCContextState = DEMOGfxAllocMEM2(sizeof(GX2ContextState), GX2_CONTEXT_STATE_ALIGNMENT); DEMOCheck(DEMODRCContextState != NULL, "DRC Context state buffer alloc failed"); // GX2SetupContextState will invalidate CPU cache for us GX2SetupContextState(DEMODRCContextState); // Setup render/depth buffers to be used now GX2SetColorBuffer(&DEMODRCColorBuffer, GX2_RENDER_TARGET_0); GX2SetDepthBuffer(&DEMODRCDepthBuffer); // Misc graphics setup GX2SetViewport(0, 0, (f32)gDemoDRCRenderWidth, (f32)gDemoDRCRenderHeight, 0.0f, 1.0f); GX2SetScissor(0, 0, gDemoDRCRenderWidth, gDemoDRCRenderHeight); GX2SetDRCScale(gDemoDRCRenderWidth, gDemoDRCRenderHeight); ///////////////////////////////////////////////////////////////////////////// // Create the new instance gDemoDRCCurInstance = DEMOAlloc(sizeof(DEMODRCInstance)); gDemoDRCCurInstance->contextState = DEMODRCContextState; return gDemoDRCCurInstance; } void DEMODRCDeleteInstance(DEMODRCInstance *instance) { DEMOGfxFreeMEM2(instance->contextState); DEMOFree(instance); // Edge case: delete current if (gDemoDRCCurInstance == instance) { gDemoDRCCurInstance = NULL; DEMODRCContextState = NULL; } } void DEMODRCSetInstance(DEMODRCInstance *instance) { gDemoDRCCurInstance = instance; DEMODRCContextState = instance->contextState; GX2SetContextState(DEMODRCContextState); } DEMODRCInstance* DEMODRCGetInstance(void) { return gDemoDRCCurInstance; }