mirror of https://github.com/mgba-emu/mgba.git
3DS: Allow for multiple screens, increasing async ability
This commit is contained in:
parent
8ffcb116f2
commit
465dc2b400
|
@ -31,13 +31,15 @@ static struct ctrUIVertex* ctrVertexBuffer = NULL;
|
|||
static u16* ctrIndexBuffer = NULL;
|
||||
static u16 ctrNumQuads = 0;
|
||||
|
||||
static void* gpuColorBuffer = NULL;
|
||||
static void* gpuColorBuffer[2] = { NULL, NULL };
|
||||
static u32* gpuCommandList = NULL;
|
||||
static void* screenTexture = NULL;
|
||||
|
||||
static shaderProgram_s gpuShader;
|
||||
static DVLB_s* passthroughShader = NULL;
|
||||
|
||||
static int pendingEvents = 0;
|
||||
|
||||
static const struct ctrTexture* activeTexture = NULL;
|
||||
|
||||
static u32 _f24FromFloat(float f) {
|
||||
|
@ -85,6 +87,17 @@ static u32 _f31FromFloat(float f) {
|
|||
return sign << 30 | exponent << 23 | mantissa;
|
||||
}
|
||||
|
||||
void ctrClearPending(int events) {
|
||||
int toClear = events & pendingEvents;
|
||||
if (toClear & (1 << GSPEVENT_PSC0)) {
|
||||
gspWaitForPSC0();
|
||||
}
|
||||
if (toClear & (1 << GSPEVENT_PPF)) {
|
||||
gspWaitForPPF();
|
||||
}
|
||||
pendingEvents ^= toClear;
|
||||
}
|
||||
|
||||
// Replacements for the limiting GPU_SetViewport function in ctrulib
|
||||
static void _GPU_SetFramebuffer(intptr_t colorBuffer, intptr_t depthBuffer, u16 w, u16 h) {
|
||||
u32 buf[4];
|
||||
|
@ -145,10 +158,11 @@ Result ctrInitGpu() {
|
|||
Result res = -1;
|
||||
|
||||
// Allocate buffers
|
||||
gpuColorBuffer = vramAlloc(400 * 240 * 4);
|
||||
gpuColorBuffer[0] = vramAlloc(400 * 240 * 4);
|
||||
gpuColorBuffer[1] = vramAlloc(320 * 240 * 4);
|
||||
gpuCommandList = linearAlloc(COMMAND_LIST_LENGTH * sizeof(u32));
|
||||
ctrVertexBuffer = linearAlloc(VERTEX_INDEX_BUFFER_SIZE);
|
||||
if (gpuColorBuffer == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) {
|
||||
if (gpuColorBuffer[0] == NULL || gpuColorBuffer[1] == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) {
|
||||
res = -1;
|
||||
goto error_allocs;
|
||||
}
|
||||
|
@ -197,9 +211,14 @@ error_allocs:
|
|||
gpuCommandList = NULL;
|
||||
}
|
||||
|
||||
if (gpuColorBuffer != NULL) {
|
||||
vramFree(gpuColorBuffer);
|
||||
gpuColorBuffer = NULL;
|
||||
if (gpuColorBuffer[0] != NULL) {
|
||||
vramFree(gpuColorBuffer[0]);
|
||||
gpuColorBuffer[0] = NULL;
|
||||
}
|
||||
|
||||
if (gpuColorBuffer[1] != NULL) {
|
||||
vramFree(gpuColorBuffer[1]);
|
||||
gpuColorBuffer[1] = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -221,22 +240,31 @@ void ctrDeinitGpu() {
|
|||
linearFree(gpuCommandList);
|
||||
gpuCommandList = NULL;
|
||||
|
||||
vramFree(gpuColorBuffer);
|
||||
gpuColorBuffer = NULL;
|
||||
vramFree(gpuColorBuffer[0]);
|
||||
gpuColorBuffer[0] = NULL;
|
||||
|
||||
vramFree(gpuColorBuffer[1]);
|
||||
gpuColorBuffer[1] = NULL;
|
||||
}
|
||||
|
||||
void ctrGpuBeginFrame(void) {
|
||||
void ctrGpuBeginFrame(int screen) {
|
||||
if (screen > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fw;
|
||||
if (screen == 0) {
|
||||
fw = 400;
|
||||
} else {
|
||||
fw = 320;
|
||||
}
|
||||
|
||||
_GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer[screen]), 0, 240, fw);
|
||||
}
|
||||
|
||||
void ctrGpuBeginDrawing(void) {
|
||||
shaderProgramUse(&gpuShader);
|
||||
|
||||
void* gpuColorBufferEnd = (char*)gpuColorBuffer + 240 * 400 * 4;
|
||||
|
||||
GX_SetMemoryFill(NULL,
|
||||
gpuColorBuffer, 0x00000000, gpuColorBufferEnd, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER,
|
||||
NULL, 0, NULL, 0);
|
||||
gspWaitForPSC0();
|
||||
|
||||
_GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer), 0, 240, 400);
|
||||
|
||||
// Disable depth and stencil testing
|
||||
GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR);
|
||||
GPU_SetStencilTest(false, GPU_ALWAYS, 0, 0xFF, 0);
|
||||
|
@ -286,20 +314,47 @@ void ctrGpuBeginFrame(void) {
|
|||
bufferOffsets, arrayTargetAttributes, numAttributesInArray);
|
||||
}
|
||||
|
||||
void ctrGpuEndFrame(void* outputFramebuffer, int w, int h) {
|
||||
void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h) {
|
||||
if (screen > 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fw;
|
||||
if (screen == 0) {
|
||||
fw = 400;
|
||||
} else {
|
||||
fw = 320;
|
||||
}
|
||||
|
||||
ctrFlushBatch();
|
||||
|
||||
void* colorBuffer = (u8*)gpuColorBuffer + ((400 - w) * 240 * 4);
|
||||
void* colorBuffer = (u8*)gpuColorBuffer[screen] + ((fw - w) * 240 * 4);
|
||||
|
||||
const u32 GX_CROP_INPUT_LINES = (1 << 2);
|
||||
|
||||
ctrClearPending(1 << GSPEVENT_PSC0);
|
||||
ctrClearPending(1 << GSPEVENT_PPF);
|
||||
|
||||
GX_SetDisplayTransfer(NULL,
|
||||
colorBuffer, GX_BUFFER_DIM(240, 400),
|
||||
colorBuffer, GX_BUFFER_DIM(240, fw),
|
||||
outputFramebuffer, GX_BUFFER_DIM(h, w),
|
||||
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) |
|
||||
GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) |
|
||||
GX_CROP_INPUT_LINES);
|
||||
gspWaitForPPF();
|
||||
pendingEvents |= (1 << GSPEVENT_PPF);
|
||||
}
|
||||
|
||||
void ctrGpuEndDrawing(void) {
|
||||
ctrClearPending(1 << GSPEVENT_PPF);
|
||||
gfxSwapBuffersGpu();
|
||||
gspWaitForEvent(GSPEVENT_VBlank0, false);
|
||||
|
||||
void* gpuColorBuffer0End = (char*)gpuColorBuffer[0] + 240 * 400 * 4;
|
||||
void* gpuColorBuffer1End = (char*)gpuColorBuffer[1] + 240 * 320 * 4;
|
||||
GX_SetMemoryFill(NULL,
|
||||
gpuColorBuffer[0], 0x00000000, gpuColorBuffer0End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER,
|
||||
gpuColorBuffer[1], 0x00000000, gpuColorBuffer1End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER);
|
||||
pendingEvents |= 1 << GSPEVENT_PSC0;
|
||||
}
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h) {
|
||||
|
@ -389,6 +444,8 @@ void ctrFlushBatch(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
ctrClearPending((1 << GSPEVENT_PSC0));
|
||||
|
||||
GSPGPU_FlushDataCache(NULL, (u8*)ctrVertexBuffer, VERTEX_INDEX_BUFFER_SIZE);
|
||||
GPU_DrawElements(GPU_UNKPRIM, (u32*)(osConvertVirtToPhys((u32)ctrIndexBuffer) - VRAM_BASE), ctrNumQuads * 6);
|
||||
|
||||
|
|
|
@ -28,8 +28,10 @@ inline void ctrTexture_Init(struct ctrTexture* tex) {
|
|||
Result ctrInitGpu(void);
|
||||
void ctrDeinitGpu(void);
|
||||
|
||||
void ctrGpuBeginFrame(void);
|
||||
void ctrGpuEndFrame(void* outputFramebuffer, int w, int h);
|
||||
void ctrGpuBeginDrawing(void);
|
||||
void ctrGpuBeginFrame(int screen);
|
||||
void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h);
|
||||
void ctrGpuEndDrawing(void);
|
||||
|
||||
void ctrSetViewportSize(s16 w, s16 h);
|
||||
|
||||
|
|
|
@ -60,10 +60,12 @@ extern bool allocateRomBuffer(void);
|
|||
static void _postAudioBuffer(struct GBAAVStream* stream, struct GBAAudio* audio);
|
||||
|
||||
static void _drawStart(void) {
|
||||
ctrGpuBeginFrame();
|
||||
ctrGpuBeginDrawing();
|
||||
if (screenMode < SM_PA_TOP || (guiDrawn & GUI_ACTIVE)) {
|
||||
ctrGpuBeginFrame(GFX_BOTTOM);
|
||||
ctrSetViewportSize(320, 240);
|
||||
} else {
|
||||
ctrGpuBeginFrame(GFX_TOP);
|
||||
ctrSetViewportSize(400, 240);
|
||||
}
|
||||
guiDrawn &= ~GUI_THIS_FRAME;
|
||||
|
@ -78,11 +80,10 @@ static void _drawEnd(void) {
|
|||
|
||||
if (!(guiDrawn & GUI_THIS_FRAME) || screen == GFX_BOTTOM) {
|
||||
void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(outputFramebuffer, width, height);
|
||||
ctrGpuEndFrame(screen, outputFramebuffer, width, height);
|
||||
}
|
||||
|
||||
gfxSwapBuffersGpu();
|
||||
gspWaitForEvent(GSPEVENT_VBlank0, false);
|
||||
ctrGpuEndDrawing();
|
||||
}
|
||||
|
||||
static int _batteryState(void) {
|
||||
|
@ -110,9 +111,9 @@ static void _guiPrepare(void) {
|
|||
u16 width = 0, height = 0;
|
||||
|
||||
void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(outputFramebuffer, width, height);
|
||||
ctrGpuEndFrame(screen, outputFramebuffer, width, height);
|
||||
|
||||
ctrGpuBeginFrame();
|
||||
ctrGpuBeginFrame(GFX_BOTTOM);
|
||||
ctrSetViewportSize(320, 240);
|
||||
}
|
||||
|
||||
|
@ -125,7 +126,7 @@ static void _guiFinish(void) {
|
|||
|
||||
u16 width = 0, height = 0;
|
||||
void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width);
|
||||
ctrGpuEndFrame(outputFramebuffer, width, height);
|
||||
ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height);
|
||||
}
|
||||
|
||||
static void _setup(struct GBAGUIRunner* runner) {
|
||||
|
|
Loading…
Reference in New Issue