3DS: Allow for multiple screens, increasing async ability

This commit is contained in:
Jeffrey Pfau 2015-09-19 19:42:34 -07:00
parent 8ffcb116f2
commit 465dc2b400
3 changed files with 91 additions and 31 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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) {