libctru/libctru/source/gpu/gxqueue.c
fincs 6ef91576ae
Overhaul gspgpu/gfx code, see details:
- GSPGPU changes:
  - gspInit now properly initializes the event queue, GSP shared memory
    and first-time initialization - previously this was done in gfxInit.
  - Removed gspInitEventHandler/gspExitEventHandler in line with above.
  - Added gspPresentBuffer for pushing a framebuffer to the internal
    GSP swap queue (previously this was an internal function in gfx.c).
  - Added defines for screen IDs and screen dimensions.
  - Removed sharedGspCmdBuf param from gspSubmitGxCommand (now uses
    the correct GSP shared memory address automatically).
  - Removed gxCmdBuf global variable (no longer needed as per above).
  - Removed GSPGPU_REBASE_REG (leftover from early 3DS homebrew).
- GFX changes:
  - Documentation overhaul and code cleanup.
  - Simplified implementation using the enhanced GSPGPU service wrapper.
  - Top left/right framebuffers now form a single allocation instead of
    being split into two separate allocations.
  - Fixed LCD configuration mode when framebuffers are on VRAM.
  - Removed the ability to forcefully swap the screens: gspPresentBuffer
    is now always used (i.e. GSP shared mem). The 'immediate' parameter
    of gfxConfigScreen now does nothing, and gfxSwapBuffers/Gpu now do
    the same thing.
  - Removed gfx{TopLeft,TopRight,Bottom}Framebuffers global variables
    (please use gfxGetFramebuffer instead as originally intended...)
2020-06-13 20:08:37 +02:00

120 lines
2.6 KiB
C

#include <stdlib.h>
#include <string.h>
#include <3ds/types.h>
#include <3ds/svc.h>
#include <3ds/synchronization.h>
#include <3ds/gpu/gx.h>
#include <3ds/services/gspgpu.h>
#define MAX_PARALLEL_CMDS 3
static gxCmdQueue_s* curQueue;
static bool isActive, isRunning, shouldStop;
static LightLock queueLock = 1;
static void gxCmdQueueDoCommands(void)
{
if (shouldStop)
return;
int batchSize = curQueue->lastEntry+MAX_PARALLEL_CMDS-curQueue->curEntry;
while (curQueue->curEntry < curQueue->numEntries && batchSize--)
{
gxCmdEntry_s* entry = &curQueue->entries[curQueue->curEntry++];
gspSubmitGxCommand(entry->data);
}
}
void gxCmdQueueInterrupt(GSPGPU_Event irq)
{
if (!isRunning || irq==GSPGPU_EVENT_PSC1 || irq==GSPGPU_EVENT_VBlank0 || irq==GSPGPU_EVENT_VBlank1)
return;
gxCmdQueue_s* runCb = NULL;
LightLock_Lock(&queueLock);
curQueue->lastEntry++;
if (shouldStop)
{
curQueue = NULL;
isActive = false;
isRunning = false;
shouldStop = false;
}
else if (curQueue->lastEntry < curQueue->numEntries)
gxCmdQueueDoCommands();
else
{
runCb = curQueue;
isRunning = false;
}
LightLock_Unlock(&queueLock);
if (runCb && runCb->callback)
runCb->callback(runCb);
}
void gxCmdQueueClear(gxCmdQueue_s* queue)
{
if (queue==curQueue && isRunning)
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
queue->numEntries = 0;
queue->curEntry = 0;
queue->lastEntry = 0;
}
void gxCmdQueueAdd(gxCmdQueue_s* queue, const gxCmdEntry_s* entry)
{
if (queue->numEntries == queue->maxEntries)
svcBreak(USERBREAK_PANIC); // Shouldn't happen.
memcpy(&queue->entries[queue->numEntries], entry, sizeof(gxCmdEntry_s));
LightLock_Lock(&queueLock);
queue->numEntries++;
if (queue==curQueue && isActive && !isRunning)
{
isRunning = true;
gxCmdQueueDoCommands();
}
LightLock_Unlock(&queueLock);
}
void gxCmdQueueRun(gxCmdQueue_s* queue)
{
if (isRunning)
return;
curQueue = queue;
isActive = true;
if (queue->lastEntry < queue->numEntries)
{
isRunning = true;
LightLock_Lock(&queueLock);
gxCmdQueueDoCommands();
LightLock_Unlock(&queueLock);
} else
isRunning = false;
}
void gxCmdQueueStop(gxCmdQueue_s* queue)
{
if (!curQueue)
return;
LightLock_Lock(&queueLock);
if (!isRunning)
{
curQueue = NULL;
isActive = false;
} else
shouldStop = true;
LightLock_Unlock(&queueLock);
}
bool gxCmdQueueWait(gxCmdQueue_s* queue, s64 timeout)
{
u64 deadline = U64_MAX;
if (timeout >= 0)
deadline = svcGetSystemTick() + timeout;
while (isRunning)
{
if (timeout >= 0 && (s64)(u64)(svcGetSystemTick()-deadline) >= 0)
return false;
gspWaitForAnyEvent();
}
return true;
}