*/
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
*/
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
*
/// 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.
/**
* @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)
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;
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;
}
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);
}
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;
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
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;
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]++;
}