diff --git a/libctru/include/3ds/GSP.h b/libctru/include/3ds/GSP.h index 5ac95ea..c592731 100644 --- a/libctru/include/3ds/GSP.h +++ b/libctru/include/3ds/GSP.h @@ -27,9 +27,33 @@ typedef struct GSP_CaptureInfoEntry screencapture[2]; } GSP_CaptureInfo; +typedef enum +{ + GSPEVENT_PSC0 = 0, + GSPEVENT_PSC1, + GSPEVENT_VBlank0, + GSPEVENT_VBlank1, + GSPEVENT_PPF, + GSPEVENT_P3D, + GSPEVENT_DMA, + GSPEVENT_count, // used to know how many events there are +} GSP_Event; + Result gspInit(); void gspExit(); +Result gspInitEventHandler(Handle gspEvent, vu8* gspSharedMem, u8 gspThreadId); +void gspExitEventHandler(); +void gspWaitForEvent(GSP_Event id); +#define gspWaitForPSC0() gspWaitForEvent(GSPEVENT_PSC0) +#define gspWaitForPSC1() gspWaitForEvent(GSPEVENT_PSC1) +#define gspWaitForVBlank() gspWaitForVBlank0() +#define gspWaitForVBlank0() gspWaitForEvent(GSPEVENT_VBlank0) +#define gspWaitForVBlank1() gspWaitForEvent(GSPEVENT_VBlank1) +#define gspWaitForPPF() gspWaitForEvent(GSPEVENT_PPF) +#define gspWaitForP3D() gspWaitForEvent(GSPEVENT_P3D) +#define gspWaitForDMA() gspWaitForEvent(GSPEVENT_DMA) + Result GSPGPU_AcquireRight(Handle *handle, u8 flags); Result GSPGPU_ReleaseRight(Handle *handle); Result GSPGPU_ImportDisplayCaptureInfo(Handle* handle, GSP_CaptureInfo *captureinfo); diff --git a/libctru/source/services/gsp.c b/libctru/source/services/gsp.c index 95e724d..a8e115a 100644 --- a/libctru/source/services/gsp.c +++ b/libctru/source/services/gsp.c @@ -5,7 +5,18 @@ #include <3ds/svc.h> #include <3ds/srv.h> +#define GSP_EVENT_STACK_SIZE 0x1000 + Handle gspGpuHandle=0; +Handle gspEvents[GSPEVENT_count]; +u64 gspEventStack[GSP_EVENT_STACK_SIZE/sizeof(u64)]; //u64 so that it's 8-byte aligned +volatile bool gspRunEvents; +Handle gspEventThread; + +static Handle gspEvent; +static vu8* gspEventData; + +static void gspEventThreadMain(u32 arg); Result gspInit() { @@ -17,6 +28,76 @@ void gspExit() if(gspGpuHandle)svcCloseHandle(gspGpuHandle); } +Result gspInitEventHandler(Handle _gspEvent, vu8* _gspSharedMem, u8 gspThreadId) +{ + // Create events + int i; + for (i = 0; i < GSPEVENT_count; i ++) + { + Result rc = svcCreateEvent(&gspEvents[i], 0); + if (rc != 0) + { + // Destroy already created events due to failure + int j; + for (j = 0; j < i; j ++) + svcCloseHandle(gspEvents[j]); + return rc; + } + } + + // Start event thread + gspEvent = _gspEvent; + gspEventData = _gspSharedMem + gspThreadId*0x40; + gspRunEvents = true; + return svcCreateThread(&gspEventThread, gspEventThreadMain, 0x0, (u32*)((char*)gspEventStack + sizeof(gspEventStack)), 0x31, 0xfffffffe); +} + +void gspExitEventHandler() +{ + // Stop event thread + gspRunEvents = false; + svcWaitSynchronization(gspEventThread, 1000000000); + + // Free events + int i; + for (i = 0; i < GSPEVENT_count; i ++) + svcCloseHandle(gspEvents[i]); +} + +void gspWaitForEvent(GSP_Event id) +{ + svcClearEvent(gspEvents[id]); + svcWaitSynchronization(gspEvents[id], U64_MAX); +} + +void gspEventThreadMain(u32 arg) +{ + while (gspRunEvents) + { + svcWaitSynchronization(gspEvent, U64_MAX); + svcClearEvent(gspEvent); + + int count = gspEventData[1]; + int last = gspEventData[0] + count; + while (last >= 0x34) last -= 0x34; + int cur = last; + int i; + for (i = 0; i < count; i ++) + { + int curEvt = gspEventData[0xC + cur]; + cur --; + if (cur < 0) cur += 0x34; + if (curEvt >= GSPEVENT_count) continue; + svcSignalEvent(gspEvents[curEvt]); + } + + gspEventData[0] = last; + gspEventData[1] -= count; + gspEventData[2] = 0; + } + svcExitThread(); +} + Result GSPGPU_AcquireRight(Handle* handle, u8 flags) { if(!handle)handle=&gspGpuHandle;