/*---------------------------------------------------------------------------* Project: Revolution Demo Library File: DEMOInit.c Copyright 1998-2006 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. $Log: DEMOInit.c,v $ Revision 1.10 2009/05/19 00:57:29 urata Modified the limit of "xfbHeight" from 528 to 574 in DEMOInitGX. Revision 1.9 2008/07/29 09:24:47 nakano_yoshinobu Added DemoUseMEM_HEAP_OPT_THREAD_SAFE option. This option uses MEMCreateExpHeapEx(..., MEM_HEAP_OPT_THREAD_SAFE) in DEMOInit(). Revision 1.8 2008/05/19 01:19:30 nakano_yoshinobu Added GXFlush() for GXGetCPUFifo changing. Revision 1.7 2007/06/15 23:03:14 carlmu Allow XFB to be allocated from MEM2. Allow creation of extra large XFB's (eg, for panning). Revision 1.6 2007/02/07 23:54:57 johnc Removed static scope from functions and variables inside DEMOInit. Revision 1.5 2006/04/06 07:29:39 johnc Fixed bug in creation of heap for MEM2 when DemoUseMEMHeap is true. Revision 1.4 2006/03/11 06:56:02 hirose Integrated MEMAllocator, added switch to use heap defined in MEM library. Revision 1.3 2006/02/06 05:07:24 hirose Changes due to Fifo API updates. Revision 1.2 2006/01/07 06:47:39 hirose Reconstruction from simpler form. Revision 1.1.1.1 2005/05/12 02:15:48 yasuh-to $NoKeywords: $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* This DEMO library provides a common application framework that is used in all the GX demos distributed with the Revolution SDK. *---------------------------------------------------------------------------*/ #include /*---------------------------------------------------------------------------* Static variables *---------------------------------------------------------------------------*/ static GXBool DemoFirstFrame = GX_TRUE; #define DEFAULT_FIFO_SIZE (256 * 1024) void* DemoFifoBuffer; GXFifoObj* DemoFifoObj; static GXRenderModeObj *Rmode; static GXRenderModeObj Rmodeobj; static u32 allocatedFrameBufferSize = 0; /*---------------------------------------------------------------------------* Global variables *---------------------------------------------------------------------------*/ void* DemoFrameBuffer1; void* DemoFrameBuffer2; void* DemoCurrentBuffer; // Set to 1 before DEMOInit() if MEMHeap is prefered rather than OSHeap. u32 DemoUseMEMHeap = 0; // Set to TRUE before DEMOInit() if XFBs should be in MEM2 rather than MEM1. BOOL DemoUseMEM2XFB = FALSE; // Set to TRUE before DEMOInit() if MEMCreateExpHeapEx use MEM_HEAP_OPT_THREAD_SAFE. BOOL DemoUseMEM_HEAP_OPT_THREAD_SAFE = FALSE; MEMAllocator DemoAllocator1; MEMAllocator DemoAllocator2; /*---------------------------------------------------------------------------* Functions *---------------------------------------------------------------------------*/ /*===========================================================================* Initialization *===========================================================================*/ /*---------------------------------------------------------------------------* Name: DEMOInit Description: This function initializes the components of the operating system and its device drivers. The mode parameter allows the application to override the default render mode. It then allocates all of main memory except the area for external framebuffer into a heap than can be managed with OSAlloc. This function initializes the video controller to run at 640x480 interlaced display, with 60Hz refresh (actually, 640x448; see below). Arguments: mode : render mode Default render mode will be used when NULL is given as this argument. Returns: None *---------------------------------------------------------------------------*/ void (DEMOInit)( GXRenderModeObj *mode ); void (DEMOInit)( GXRenderModeObj *mode ) { DEMOInit_Real(mode); } /*---------------------------------------------------------------------------*/ void DEMOInit_Real( GXRenderModeObj *mode ) { // Initializes OS. // OSInit(); // called inside the startup routine. // Initializes disc drive interface. DVDInit(); // Initializes disc. // Initializes video interface. VIInit(); // Initializes game PADs (controllers) DEMOPadInit(); // PADInit() is called inside. // Set up rendering mode // (which reflects the GX/VI configurations and XFB size below) DEMOSetRenderMode(mode); // Memory configuration (framebuffers / GX Fifo / heap) DEMOConfigureMem(); // Initializes graphics DemoFifoObj = GXInit(DemoFifoBuffer, DEFAULT_FIFO_SIZE); DEMOInitGX(); // Starts VI DEMOStartVI(); } /*---------------------------------------------------------------------------* Name: DEMOSetRenderMode Description: This function sets up rendering mode which configures GX and VI. If mode == NULL, this function use a default rendering mode according to the TV format. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOSetRenderMode( GXRenderModeObj* mode ) { // If an application specific render mode is provided, // override the default render mode if (mode != NULL) { Rmodeobj = *mode; Rmode = &Rmodeobj; } else { switch (VIGetTvFormat()) { case VI_NTSC: Rmode = &GXNtsc480IntDf; break; case VI_PAL: Rmode = &GXPal528IntDf; break; case VI_EURGB60: Rmode = &GXEurgb60Hz480IntDf; break; case VI_MPAL: Rmode = &GXMpal480IntDf; break; default: OSHalt("DEMOInit: invalid TV format\n"); break; } // Trim off from top & bottom 16 scanlines (which will be overscanned). // So almost all demos actually render only 448 lines (in NTSC case.) // Since this setting is just for SDK demos, you can specify this // in order to match your application requirements. GXAdjustForOverscan(Rmode, &Rmodeobj, 0, 16); Rmode = &Rmodeobj; } } /*---------------------------------------------------------------------------* Name: DEMOConfigureMem Description: This function allocates external framebuffers and GX FIFO buffers from arena. This function also sets up an OS standard heap. Note that this memory configuration only uses MEM1 region. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOConfigureMem( void ) { void* arenaLo; void* arenaHi; u32 fbSize; /*----------------------------------------------------------------* * Allocate GX FIFO buffer in MEM1 * *----------------------------------------------------------------*/ arenaLo = OSGetMEM1ArenaLo(); DemoFifoBuffer = (void*)OSRoundUp32B((u32)arenaLo); arenaLo = (void*)OSRoundUp32B((u32)DemoFifoBuffer + DEFAULT_FIFO_SIZE); OSSetMEM1ArenaLo(arenaLo); /*----------------------------------------------------------------* * Allocate external framebuffers * *----------------------------------------------------------------*/ if (DemoUseMEM2XFB) { arenaLo = OSGetMEM2ArenaLo(); } else { arenaLo = OSGetMEM1ArenaLo(); } fbSize = VIPadFrameBufferWidth(Rmode->fbWidth) * Rmode->xfbHeight * (u32)VI_DISPLAY_PIX_SZ; allocatedFrameBufferSize = fbSize; DemoFrameBuffer1 = (void*)OSRoundUp32B((u32)arenaLo); DemoFrameBuffer2 = (void*)OSRoundUp32B((u32)DemoFrameBuffer1 + fbSize); arenaLo = (void*)OSRoundUp32B((u32)DemoFrameBuffer2 + fbSize); if (DemoUseMEM2XFB) { OSSetMEM2ArenaLo(arenaLo); } else { OSSetMEM1ArenaLo(arenaLo); } /*----------------------------------------------------------------* * Create a heap * *----------------------------------------------------------------*/ if ( DemoUseMEMHeap ) { // Memory allocation managed by MEM library. (recommended) MEMHeapHandle heapHandle; // Heap on MEM1 arenaLo = OSGetMEM1ArenaLo(); arenaHi = OSGetMEM1ArenaHi(); if (DemoUseMEM_HEAP_OPT_THREAD_SAFE) { heapHandle = MEMCreateExpHeapEx(arenaLo, (u32)arenaHi - (u32)arenaLo, MEM_HEAP_OPT_THREAD_SAFE); } else { heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo); } if ( heapHandle == MEM_HEAP_INVALID_HANDLE ) { OSHalt("MEM1 heap allocation error.\n"); } OSSetMEM1ArenaLo(arenaHi); MEMInitAllocatorForExpHeap(&DemoAllocator1, heapHandle, 32); // Heap on MEM2 arenaLo = OSGetMEM2ArenaLo(); arenaHi = OSGetMEM2ArenaHi(); if (DemoUseMEM_HEAP_OPT_THREAD_SAFE) { heapHandle = MEMCreateExpHeapEx(arenaLo, (u32)arenaHi - (u32)arenaLo, MEM_HEAP_OPT_THREAD_SAFE); } else { heapHandle = MEMCreateExpHeap(arenaLo, (u32)arenaHi - (u32)arenaLo); } if ( heapHandle == MEM_HEAP_INVALID_HANDLE ) { OSHalt("MEM2 heap allocation error.\n"); } OSSetMEM2ArenaLo(arenaHi); MEMInitAllocatorForExpHeap(&DemoAllocator2, heapHandle, 32); } else { // Memory allocation managed by conventional OSAlloc framework // for compatibilities. OSHeapHandle heapHandle; // OSInitAlloc should only ever be invoked once. arenaLo = OSGetMEM1ArenaLo(); arenaHi = OSGetMEM1ArenaHi(); arenaLo = OSInitAlloc(arenaLo, arenaHi, 1); // 1 heap OSSetMEM1ArenaLo(arenaLo); // Ensure boundaries are 32B aligned arenaLo = (void*)OSRoundUp32B(arenaLo); arenaHi = (void*)OSRoundDown32B(arenaHi); // The boundaries given to OSCreateHeap should be 32B aligned heapHandle = OSCreateHeap(arenaLo, arenaHi); if ( heapHandle == -1 ) { OSHalt("OS heap allocation error.\n"); } // From here on out, OSAlloc and OSFree behave like malloc and free // respectively OSSetMEM1ArenaLo(arenaLo=arenaHi); OSSetCurrentHeap(heapHandle); MEMInitAllocatorForOSHeap(&DemoAllocator1, heapHandle); MEMInitAllocatorForOSHeap(&DemoAllocator2, heapHandle); } } /*---------------------------------------------------------------------------* Name: DEMOInitGX Description: This function performs GX initialization and configuration by using current rendering mode Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOInitGX( void ) { u16 fbWidth; u16 xfbHeight; f32 yScale; /*----------------------------------------------------------------* * GX configuration by a render mode obj * *----------------------------------------------------------------*/ // These are necessary function calls to take a render mode // object and set up relevant GX configuration. // Check for unusual configuration fbWidth = Rmode->fbWidth; if (fbWidth > 640) { fbWidth = 640; } xfbHeight = Rmode->xfbHeight; if (xfbHeight > 574) { xfbHeight = 574; } GXSetViewport(0.0F, 0.0F, (f32)fbWidth, (f32)Rmode->efbHeight, 0.0F, 1.0F); GXSetScissor(0, 0, (u32)fbWidth, (u32)Rmode->efbHeight); yScale = GXGetYScaleFactor(Rmode->efbHeight, xfbHeight); xfbHeight = (u16)GXSetDispCopyYScale(yScale); GXSetDispCopySrc(0, 0, fbWidth, Rmode->efbHeight); // use adjusted width GXSetDispCopyDst(Rmode->fbWidth, Rmode->xfbHeight); // use original width GXSetCopyFilter(Rmode->aa, Rmode->sample_pattern, GX_TRUE, Rmode->vfilter); GXSetDispCopyGamma(GX_GM_1_0); if (Rmode->aa) GXSetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR); else GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); // Note that following is an appropriate setting for full-frame AA mode. // You should use "xfbHeight" instead of "efbHeight" to specify actual // view size. Since this library doesn't support such special case, please // call these in each application to override the normal setting. #if 0 GXSetViewport(0.0F, 0.0F, (f32)Rmode->fbWidth, (f32)Rmode->xfbHeight, 0.0F, 1.0F); GXSetDispCopyYScale(1.0F); #endif // Clear embedded framebuffer for the first frame GXCopyDisp(DemoFrameBuffer2, GX_TRUE); } /*---------------------------------------------------------------------------* Name: DEMOStartVI Description: This function performs VI start up settings that are necessary at the beginning of each demo Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOStartVI( void ) { // Configure VI with given render mode VIConfigure(Rmode); // Double-buffering initialization VISetNextFrameBuffer(DemoFrameBuffer1); DemoCurrentBuffer = DemoFrameBuffer2; // Tell VI device driver to write the current VI settings so far VIFlush(); // Wait for retrace to start first frame VIWaitForRetrace(); // Because of hardware restriction, we need to wait one more // field to make sure mode is safely changed when we change // INT->DS or DS->INT. (VIInit() sets INT mode as a default) if ( (u32)Rmode->viTVmode & 1 ) VIWaitForRetrace(); } /*===========================================================================* Basic demo framework control functions *===========================================================================*/ /*---------------------------------------------------------------------------* Name: DEMOBeforeRender Description: This function sets up the viewport to render the appropriate field if field rendering is enabled. Field rendering is a property of the render mode. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOBeforeRender( void ) { // Set up viewport (This is inappropriate for full-frame AA.) if (Rmode->field_rendering) { GXSetViewportJitter( 0.0F, 0.0F, (float)Rmode->fbWidth, (float)Rmode->efbHeight, 0.0F, 1.0F, VIGetNextField()); } else { GXSetViewport( 0.0F, 0.0F, (float)Rmode->fbWidth, (float)Rmode->efbHeight, 0.0F, 1.0F); } // Invalidate vertex cache in GP GXInvalidateVtxCache(); // Invalidate texture cache in GP GXInvalidateTexAll(); } /*---------------------------------------------------------------------------* Name: DEMODoneRender Description: This function copies the embedded frame buffer (EFB) to the external frame buffer (XFB) via GXCopyDisp, and then calls DEMOSwapBuffers. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMODoneRender( void ) { // Set Z/Color update to make sure eFB will be cleared at GXCopyDisp. // (If you want to control these modes by yourself in your application, // please comment out this part.) GXSetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); GXSetColorUpdate(GX_TRUE); // Issue display copy command GXCopyDisp(DemoCurrentBuffer, GX_TRUE); // Wait until everything is drawn and copied into XFB. GXDrawDone(); // Set the next frame buffer DEMOSwapBuffers(); } /*---------------------------------------------------------------------------* Name: DEMOSwapBuffers Description: This function finishes copying via GXDrawDone, sets the next video frame buffer, waits for vertical retrace, and swaps internal rendering buffers. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOSwapBuffers( void ) { // Display the buffer which was just filled by GXCopyDisplay VISetNextFrameBuffer(DemoCurrentBuffer); // If this is the first frame, turn off VIBlack if(DemoFirstFrame) { VISetBlack(FALSE); DemoFirstFrame = GX_FALSE; } // Tell VI device driver to write the current VI settings so far VIFlush(); // Wait for vertical retrace. VIWaitForRetrace(); // Swap buffers if(DemoCurrentBuffer == DemoFrameBuffer1) DemoCurrentBuffer = DemoFrameBuffer2; else DemoCurrentBuffer = DemoFrameBuffer1; } /*---------------------------------------------------------------------------* Name: DEMOGetRenderModeObj Description: This function returns the current rendering mode. It is most useful to inquire what the default rendering mode is. Arguments: None Returns: None *---------------------------------------------------------------------------*/ GXRenderModeObj* DEMOGetRenderModeObj( void ) { return Rmode; } /*---------------------------------------------------------------------------* Name: DEMOGetCurrentBuffer Description: This function returns the pointer to external framebuffer currently active. Since this library swiches double buffer DemoFrameBuffer1/DemoFrameBuffer2, the returned pointer will be one of them. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void* DEMOGetCurrentBuffer( void ) { return DemoCurrentBuffer; } /*---------------------------------------------------------------------------* Name: DEMOReInit Description: Re-initializes the graphics pipe. Makes no assumptions about the Fifo (allowing you to change it in your program if needed). Arguments: mode render mode object Returns: None *---------------------------------------------------------------------------*/ void DEMOReInit( GXRenderModeObj *mode ) { u32 fbSize; GXFifoObj realFifoObj; void* realFifoBase; u32 realFifoSize; // Get data on current Fifo. GXFlush(); GXGetCPUFifo(&realFifoObj); realFifoBase = GXGetFifoBase(&realFifoObj); realFifoSize = GXGetFifoSize(&realFifoObj); // Abort the GP GXAbortFrame(); /*----------------------------------------------------------------* * Initialize Graphics again *----------------------------------------------------------------*/ DEMOSetRenderMode(mode); // Verify that the previously allocated frame buffer can hold // the new render mode size (Rmode is the global variable). fbSize = VIPadFrameBufferWidth(Rmode->fbWidth) * Rmode->xfbHeight * (u32)VI_DISPLAY_PIX_SZ; ASSERTMSG( fbSize <= allocatedFrameBufferSize, "DEMOReInit - Previously " "allocated frame buffer is too small for the new render mode." ); // This will re-initialize the pointers for the original FIFO. DemoFifoObj = GXInit(realFifoBase, realFifoSize); DEMOInitGX(); // NOTE: the VI settings do not necessarily have to be reset, but // just to be safe, we do so anyway DEMOStartVI(); } /*===========================================================================*/