From: fincs Date: Mon, 4 Jan 2016 23:25:40 +0000 (+0100) Subject: Revise/enhance GSPGPU/GFX code, see below: X-Git-Tag: v1.1.0~2 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=9f98cefa3ee19f22ffba317a6d05ba8b8b2822a7;p=corbenik%2Fctrulib.git Revise/enhance GSPGPU/GFX code, see below: - Screens can be buffer-swapped independently (gfxConfigScreen) - Added gspSetEventCallback for running event code directly on the GSP thread - Added gspWaitForAnyEvent for waiting for any GSP event - Added gfxIs3D for retrieving 3D-enable status --- diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index 8e254e1..c52d5b5 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -81,6 +81,12 @@ void gfxExit(void); */ void gfxSet3D(bool enable); +/** + * @brief Retrieves the status of the 3D stereoscopic effect. + * @return true if 3D enabled, false otherwise. + */ +bool gfxIs3D(void); + /** * @brief Changes the color format of a screen * @param screen The screen of which format should be changed @@ -117,6 +123,13 @@ void gfxSetDoubleBuffering(gfxScreen_t screen, bool doubleBuffering); */ void gfxFlushBuffers(void); +/** + * @brief Updates the configuration of the specified screen (swapping the buffers if double-buffering is enabled). + * @param scr Screen to configure. + * @param immediate Whether to apply the updated configuration immediately or let GSPGPU apply it after the next GX transfer completes. + */ +void gfxConfigScreen(gfxScreen_t scr, bool immediate); + /** * @brief Swaps the buffers and sets the gsp state * diff --git a/libctru/include/3ds/services/gspgpu.h b/libctru/include/3ds/services/gspgpu.h index 93e302e..8c359a6 100644 --- a/libctru/include/3ds/services/gspgpu.h +++ b/libctru/include/3ds/services/gspgpu.h @@ -63,6 +63,15 @@ Result gspInit(void); /// Exits GSPGPU. void gspExit(void); +/** + * @brief Configures a callback to run when a GSPGPU event occurs. + * @param id ID of the event. + * @param cb Callback to run. + * @param data Data to be passed to the callback. + * @param oneShot When true, the callback is only executed once. When false, the callback is executed every time the event occurs. + */ +void gspSetEventCallback(GSPGPU_Event id, ThreadFunc cb, void* data, bool oneShot); + /** * @brief Initializes the GSPGPU event handler. * @param gspEvent Event handle to use. @@ -77,10 +86,18 @@ void gspExitEventHandler(void); /** * @brief Waits for a GSPGPU event to occur. * @param id ID of the event. - * @param Whether to discard the current event and wait for the next event. + * @param nextEvent Whether to discard the current event and wait for the next event. */ void gspWaitForEvent(GSPGPU_Event id, bool nextEvent); +/** + * @brief Waits for any GSPGPU event to occur. + * @return The ID of the event that occurred. + * + * The function returns immediately if there are unprocessed events at the time of call. + */ +GSPGPU_Event gspWaitForAnyEvent(void); + /// Waits for PSC0 #define gspWaitForPSC0() gspWaitForEvent(GSPGPU_EVENT_PSC0, false) diff --git a/libctru/source/gfx.c b/libctru/source/gfx.c index feb6368..f16ce27 100644 --- a/libctru/source/gfx.c +++ b/libctru/source/gfx.c @@ -26,11 +26,18 @@ Handle gspEvent, gspSharedMemHandle; static GSPGPU_FramebufferFormats topFormat = GSP_BGR8_OES; static GSPGPU_FramebufferFormats botFormat = GSP_BGR8_OES; +static GSPGPU_FramebufferInfo* const framebufferInfoSt[] = { &topFramebufferInfo, &bottomFramebufferInfo }; + void gfxSet3D(bool enable) { enable3d=enable; } +bool gfxIs3D(void) +{ + return enable3d; +} + void gfxSetScreenFormat(gfxScreen_t screen, GSPGPU_FramebufferFormats format) { if(screen==GFX_TOP) topFormat = format; @@ -94,7 +101,7 @@ void gfxWriteFramebufferInfo(gfxScreen_t screen) if(screen==GFX_BOTTOM)framebufferInfoHeader+=0x40; GSPGPU_FramebufferInfo* framebufferInfo=(GSPGPU_FramebufferInfo*)&framebufferInfoHeader[0x4]; framebufferInfoHeader[0x0]^=doubleBuf[screen]; - framebufferInfo[framebufferInfoHeader[0x0]]=(screen==GFX_TOP)?(topFramebufferInfo):(bottomFramebufferInfo); + framebufferInfo[framebufferInfoHeader[0x0]]=*framebufferInfoSt[screen]; framebufferInfoHeader[0x1]=1; } @@ -231,22 +238,24 @@ void gfxFlushBuffers(void) GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), bottomSize); } +void gfxConfigScreen(gfxScreen_t scr, bool immediate) +{ + currentBuffer[scr]^=doubleBuf[scr]; + gfxSetFramebufferInfo(scr, currentBuffer[scr]); + if (immediate) + GSPGPU_SetBufferSwap(scr, framebufferInfoSt[scr]); + else + gfxWriteFramebufferInfo(scr); +} + void gfxSwapBuffers(void) { - currentBuffer[0]^=doubleBuf[0]; - currentBuffer[1]^=doubleBuf[1]; - gfxSetFramebufferInfo(GFX_TOP, currentBuffer[0]); - gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer[1]); - GSPGPU_SetBufferSwap(GFX_TOP, &topFramebufferInfo); - GSPGPU_SetBufferSwap(GFX_BOTTOM, &bottomFramebufferInfo); + gfxConfigScreen(GFX_TOP, true); + gfxConfigScreen(GFX_BOTTOM, true); } void gfxSwapBuffersGpu(void) { - currentBuffer[0]^=doubleBuf[0]; - currentBuffer[1]^=doubleBuf[1]; - gfxSetFramebufferInfo(GFX_TOP, currentBuffer[0]); - gfxSetFramebufferInfo(GFX_BOTTOM, currentBuffer[1]); - gfxWriteFramebufferInfo(GFX_TOP); - gfxWriteFramebufferInfo(GFX_BOTTOM); + gfxConfigScreen(GFX_TOP, false); + gfxConfigScreen(GFX_BOTTOM, false); } diff --git a/libctru/source/services/gspgpu.c b/libctru/source/services/gspgpu.c index 01ac1ca..a4b3c0d 100644 --- a/libctru/source/services/gspgpu.c +++ b/libctru/source/services/gspgpu.c @@ -16,6 +16,9 @@ static int gspRefCount; Handle gspEvents[GSPGPU_EVENT_MAX]; vu32 gspEventCounts[GSPGPU_EVENT_MAX]; +ThreadFunc gspEventCb[GSPGPU_EVENT_MAX]; +void* gspEventCbData[GSPGPU_EVENT_MAX]; +bool gspEventCbOneShot[GSPGPU_EVENT_MAX]; volatile bool gspRunEvents; Thread gspEventThread; @@ -39,6 +42,15 @@ void gspExit(void) svcCloseHandle(gspGpuHandle); } +void gspSetEventCallback(GSPGPU_Event id, ThreadFunc cb, void* data, bool oneShot) +{ + if(id>= GSPGPU_EVENT_MAX)return; + + gspEventCb[id] = cb; + gspEventCbData[id] = data; + gspEventCbOneShot[id] = oneShot; +} + Result gspInitEventHandler(Handle _gspEvent, vu8* _gspSharedMem, u8 gspThreadId) { // Create events @@ -88,6 +100,15 @@ void gspWaitForEvent(GSPGPU_Event id, bool nextEvent) svcClearEvent(gspEvents[id]); } +GSPGPU_Event gspWaitForAnyEvent(void) +{ + s32 which = 0; + Result rc = svcWaitSynchronizationN(&which, gspEvents, GSPGPU_EVENT_MAX, false, U64_MAX); + if (R_FAILED(rc)) return -1; + svcClearEvent(gspEvents[which]); + return which; +} + static int popInterrupt() { int curEvt; @@ -138,7 +159,15 @@ void gspEventThreadMain(void *arg) if (curEvt == -1) break; - if (curEvt < GSPGPU_EVENT_MAX) { + if (curEvt < GSPGPU_EVENT_MAX) + { + if (gspEventCb[curEvt]) + { + ThreadFunc func = gspEventCb[curEvt]; + if (gspEventCbOneShot[curEvt]) + gspEventCb[curEvt] = NULL; + func(gspEventCbData[curEvt]); + } svcSignalEvent(gspEvents[curEvt]); gspEventCounts[curEvt]++; }