]> Chaos Git - corbenik/ctrulib.git/commitdiff
Revise/enhance GSPGPU/GFX code, see below:
authorfincs <fincs.alt1@gmail.com>
Mon, 4 Jan 2016 23:25:40 +0000 (00:25 +0100)
committerfincs <fincs.alt1@gmail.com>
Mon, 4 Jan 2016 23:25:40 +0000 (00:25 +0100)
- 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

libctru/include/3ds/gfx.h
libctru/include/3ds/services/gspgpu.h
libctru/source/gfx.c
libctru/source/services/gspgpu.c

index 8e254e1b8148abbe58af6e9ea903286208494f8c..c52d5b5d3eec86f7bdfca31e50d061a5de1f9d6d 100644 (file)
@@ -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
  *
index 93e302e7aebd5cc6ad62ab16263396d9a0eac683..8c359a61773f808d4a1869e5d44e3f1f6ef2139d 100644 (file)
@@ -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)
 
index feb63682e42e9cb24fdc9327b549c6a542be847e..f16ce27d20a2f4d7900e5a3d116a5b8ce057e316 100644 (file)
@@ -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);
 }
index 01ac1caee33912f94bd07d21b3bfe27a8c8373c4..a4b3c0dac83345ba9434a915cf476fd6c660ec57 100644 (file)
@@ -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]++;
                        }