#include #include #include #include <3ds.h> GSP_FramebufferInfo topFramebufferInfo, bottomFramebufferInfo; u8 gfxThreadID; u8* gfxSharedMemory; u8* gfxTopLeftFramebuffers[2]; u8* gfxTopRightFramebuffers[2]; u8* gfxBottomFramebuffers[2]; u8 currentBuffer; bool enable3d; Handle gspEvent, gspSharedMemHandle; /** * Enable / disable 3D on upper screen. * @param enable (bool): true enables 3D, false disables it. */ void gfxSet3D(bool enable) { enable3d=enable; } /** * Set framebuffer information for a screen * @param screen: 0 (GFX_TOP) / 1 (GFX_BOTTOM) * @param id: id of the framebuffer to use (0 / 1) */ void gfxSetFramebufferInfo(gfxScreen_t screen, u8 id) { if(screen==GFX_TOP) { topFramebufferInfo.active_framebuf=id; topFramebufferInfo.framebuf0_vaddr=(u32*)gfxTopLeftFramebuffers[id]; if(enable3d)topFramebufferInfo.framebuf1_vaddr=(u32*)gfxTopRightFramebuffers[id]; else topFramebufferInfo.framebuf1_vaddr=topFramebufferInfo.framebuf0_vaddr; topFramebufferInfo.framebuf_widthbytesize=240*3; u8 bit5=(enable3d!=0); topFramebufferInfo.format=((1)<<8)|((1^bit5)<<6)|((bit5)<<5)|GSP_BGR8_OES; topFramebufferInfo.framebuf_dispselect=id; topFramebufferInfo.unk=0x00000000; }else{ bottomFramebufferInfo.active_framebuf=id; bottomFramebufferInfo.framebuf0_vaddr=(u32*)gfxBottomFramebuffers[id]; bottomFramebufferInfo.framebuf1_vaddr=0x00000000; bottomFramebufferInfo.framebuf_widthbytesize=240*3; bottomFramebufferInfo.format=GSP_BGR8_OES; bottomFramebufferInfo.framebuf_dispselect=id; bottomFramebufferInfo.unk=0x00000000; } } /** * Write a screen's framebuffer information * @param screen: 0 (GFX_TOP) / 1 (GFX_BOTTOM) * @param id: id of the framebuffer to use (0 / 1) */ void gfxWriteFramebufferInfo(gfxScreen_t screen) { u8* framebufferInfoHeader=gfxSharedMemory+0x200+gfxThreadID*0x80; if(screen==GFX_BOTTOM)framebufferInfoHeader+=0x40; GSP_FramebufferInfo* framebufferInfo=(GSP_FramebufferInfo*)&framebufferInfoHeader[0x4]; framebufferInfoHeader[0x0]^=1; framebufferInfo[framebufferInfoHeader[0x0]]=(screen==GFX_TOP)?(topFramebufferInfo):(bottomFramebufferInfo); framebufferInfoHeader[0x1]=1; } /** * Initialize the console's graphics system */ void gfxInit() { gspInit(); gfxSharedMemory=(u8*)0x10002000; GSPGPU_AcquireRight(NULL, 0x0); GSPGPU_SetLcdForceBlack(NULL, 0x0); //setup our gsp shared mem section svcCreateEvent(&gspEvent, 0x0); GSPGPU_RegisterInterruptRelayQueue(NULL, gspEvent, 0x1, &gspSharedMemHandle, &gfxThreadID); svcMapMemoryBlock(gspSharedMemHandle, (u32)gfxSharedMemory, 0x3, 0x10000000); // default gspHeap configuration : // topleft1 0x00000000-0x00046500 // topleft2 0x00046500-0x0008CA00 // bottom1 0x0008CA00-0x000C4E00 // bottom2 0x000C4E00-0x000FD200 // if 3d enabled : // topright1 0x000FD200-0x00143700 // topright2 0x00143700-0x00189C00 gfxTopLeftFramebuffers[0]=linearAlloc(0x46500); gfxTopLeftFramebuffers[1]=linearAlloc(0x46500); gfxBottomFramebuffers[0]=linearAlloc(0x38400); gfxBottomFramebuffers[1]=linearAlloc(0x38400); gfxTopRightFramebuffers[0]=linearAlloc(0x46500); gfxTopRightFramebuffers[1]=linearAlloc(0x46500); enable3d=false; //initialize framebuffer info structures gfxSetFramebufferInfo(GFX_TOP, 0); gfxSetFramebufferInfo(GFX_BOTTOM, 0); //GSP shared mem : 0x2779F000 gxCmdBuf=(u32*)(gfxSharedMemory+0x800+gfxThreadID*0x200); currentBuffer=0; // Initialize event handler and wait for VBlank gspInitEventHandler(gspEvent, (vu8*)gfxSharedMemory, gfxThreadID); gspWaitForVBlank(); } /** * Stop the console's graphics system */ void gfxExit() { // Exit event handler gspExitEventHandler(); // Free framebuffers (let's pretend linearFree is actually implemented...) linearFree(gfxTopRightFramebuffers[1]); linearFree(gfxTopRightFramebuffers[0]); linearFree(gfxBottomFramebuffers[1]); linearFree(gfxBottomFramebuffers[0]); linearFree(gfxTopLeftFramebuffers[1]); linearFree(gfxTopLeftFramebuffers[0]); //unmap GSP shared mem svcUnmapMemoryBlock(gspSharedMemHandle, 0x10002000); GSPGPU_UnregisterInterruptRelayQueue(NULL); svcCloseHandle(gspSharedMemHandle); svcCloseHandle(gspEvent); GSPGPU_ReleaseRight(NULL); gspExit(); } /** * Get a screen's framebuffer * @param screen: 0 (GFX_TOP) / 1 (GFX_BOTTOM) * @param side: 0 (GFX_LEFT) / 1 (GFX_RIGHT) * @param width: pointer to store screen's width * @param width: pointer to store screen's height * @return given screen's framebuffer */ u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* height) { if(width)*width=240; if(screen==GFX_TOP) { if(height)*height=400; return (side==GFX_LEFT || !enable3d)?(gfxTopLeftFramebuffers[currentBuffer^1]):(gfxTopRightFramebuffers[currentBuffer^1]); }else{ if(height)*height=320; return gfxBottomFramebuffers[currentBuffer^1]; } } /** * Flush (empty) current screen buffers */ void gfxFlushBuffers() { GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), 0x46500); if(enable3d)GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), 0x46500); GSPGPU_FlushDataCache(NULL, gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), 0x38400); } /** * Swap screen buffers (buffer 0 <=> buffer 1) */ void gfxSwapBuffers() { currentBuffer^=1; gfxSetFramebufferInfo(GFX_TOP, currentBuffer); gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); GSPGPU_SetBufferSwap(NULL, GFX_TOP, &topFramebufferInfo); GSPGPU_SetBufferSwap(NULL, GFX_BOTTOM, &bottomFramebufferInfo); } /** * Swap screen buffers (buffer 0 <=> buffer 1) using GPU */ void gfxSwapBuffersGpu() { currentBuffer^=1; gfxSetFramebufferInfo(GFX_TOP, currentBuffer); gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer); gfxWriteFramebufferInfo(GFX_TOP); gfxWriteFramebufferInfo(GFX_BOTTOM); }