3DS: Transition to using RenderTarget

This commit is contained in:
Vicki Pfau 2017-08-27 23:39:16 -07:00
parent e2e0fe8f85
commit c0f0d54a52
2 changed files with 65 additions and 40 deletions

View File

@ -27,11 +27,13 @@ struct ctrUIVertex {
}; };
#define MAX_NUM_QUADS 256 #define MAX_NUM_QUADS 256
#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex) #define BUFFER_PARTITIONS 4
#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * BUFFER_PARTITIONS * sizeof(struct ctrUIVertex)
static struct ctrUIVertex* ctrVertexBuffer = NULL; static struct ctrUIVertex* ctrVertexBuffer = NULL;
static int ctrNumVerts = 0; static int ctrNumVerts = 0;
static int ctrVertStart = 0; static int ctrVertStart = 0;
static int ctrVertPartition = 0;
static C3D_Tex* activeTexture = NULL; static C3D_Tex* activeTexture = NULL;
@ -174,9 +176,11 @@ void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s
if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) { if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) {
ctrFlushBatch(); ctrFlushBatch();
C3D_Flush(); ++ctrVertPartition;
ctrNumVerts = 0; if (ctrVertPartition == BUFFER_PARTITIONS) {
ctrVertStart = 0; svcBreak(USERBREAK_PANIC);
}
ctrVertStart = ctrVertPartition * MAX_NUM_QUADS;
} }
struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts]; struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts];
@ -217,7 +221,6 @@ void ctrFlushBatch(void) {
void ctrFinalize(void) { void ctrFinalize(void) {
ctrFlushBatch(); ctrFlushBatch();
C3D_Flush();
ctrNumVerts = 0;
ctrVertStart = 0; ctrVertStart = 0;
ctrVertPartition = 0;
} }

View File

@ -80,10 +80,14 @@ static C3D_Tex outputTexture;
static ndspWaveBuf dspBuffer[DSP_BUFFERS]; static ndspWaveBuf dspBuffer[DSP_BUFFERS];
static int bufferId = 0; static int bufferId = 0;
static bool frameLimiter = true; static bool frameLimiter = true;
static unsigned frameCounter;
static C3D_RenderBuf bottomScreen; static C3D_RenderTarget* topScreen[2];
static C3D_RenderBuf topScreen; static C3D_RenderTarget* bottomScreen[2];
static C3D_RenderBuf upscaleBuffer; static int doubleBuffer = 0;
static C3D_RenderTarget* upscaleBuffer;
static C3D_Tex upscaleBufferTex;
static aptHookCookie cookie; static aptHookCookie cookie;
@ -94,10 +98,24 @@ static bool _initGpu(void) {
return false; return false;
} }
if (!C3D_RenderBufInit(&topScreen, 240, 400, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&bottomScreen, 240, 320, GPU_RB_RGB8, 0) || !C3D_RenderBufInit(&upscaleBuffer, 512, 512, GPU_RB_RGB8, 0)) { topScreen[0] = C3D_RenderTargetCreate(240, 400, GPU_RB_RGB8, 0);
topScreen[1] = C3D_RenderTargetCreate(240, 400, GPU_RB_RGB8, 0);
bottomScreen[0] = C3D_RenderTargetCreate(240, 320, GPU_RB_RGB8, 0);
bottomScreen[1] = C3D_RenderTargetCreate(240, 320, GPU_RB_RGB8, 0);
if (!topScreen[0] || !topScreen[1] || !bottomScreen[0] || !bottomScreen[1]) {
return false; return false;
} }
if (!C3D_TexInitVRAM(&upscaleBufferTex, 512, 512, GPU_RB_RGB8)) {
return false;
}
upscaleBuffer = C3D_RenderTargetCreateFromTex(&upscaleBufferTex, GPU_TEXFACE_2D, 0, 0);
if (!upscaleBuffer) {
return false;
}
C3D_RenderTargetSetClear(upscaleBuffer, C3D_CLEAR_COLOR, 0, 0);
return ctrInitGpu(); return ctrInitGpu();
} }
@ -108,9 +126,13 @@ static void _cleanup(void) {
linearFree(outputBuffer); linearFree(outputBuffer);
} }
C3D_RenderBufDelete(&topScreen); C3D_RenderTargetDelete(topScreen[0]);
C3D_RenderBufDelete(&bottomScreen); C3D_RenderTargetDelete(topScreen[1]);
C3D_RenderBufDelete(&upscaleBuffer); C3D_RenderTargetDelete(bottomScreen[0]);
C3D_RenderTargetDelete(bottomScreen[1]);
C3D_RenderTargetDelete(upscaleBuffer);
C3D_TexDelete(&upscaleBufferTex);
C3D_TexDelete(&outputTexture);
C3D_Fini(); C3D_Fini();
gfxExit(); gfxExit();
@ -191,18 +213,23 @@ static void _csndPlaySound(u32 flags, u32 sampleRate, float vol, void* left, voi
static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right); static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right);
static void _drawStart(void) { static void _drawStart(void) {
C3D_RenderBufClear(&bottomScreen); C3D_FrameBegin(frameLimiter ? 0 : C3D_FRAME_NONBLOCK);
C3D_RenderBufClear(&topScreen); frameCounter = C3D_FrameCounter(0);
} }
static void _drawEnd(void) { static void _drawEnd(void) {
ctrFinalize(); ctrFinalize();
C3D_RenderBufTransfer(&topScreen, (u32*) gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_RenderTargetSetOutput(topScreen[doubleBuffer], GFX_TOP, GFX_LEFT, GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
C3D_RenderBufTransfer(&bottomScreen, (u32*) gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_RenderTargetSetOutput(bottomScreen[doubleBuffer], GFX_BOTTOM, GFX_LEFT, GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
gfxSwapBuffersGpu(); C3D_FrameEnd(GX_CMDLIST_FLUSH);
if (frameLimiter) { if (frameLimiter) {
gspWaitForEvent(GSPGPU_EVENT_VBlank0, false); while (frameCounter == C3D_FrameCounter(0)) {
gspWaitForAnyEvent();
}
} }
doubleBuffer ^= 1;
C3D_FrameBufClear(&bottomScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
C3D_FrameBufClear(&topScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
} }
static int _batteryState(void) { static int _batteryState(void) {
@ -221,12 +248,7 @@ static int _batteryState(void) {
} }
static void _guiPrepare(void) { static void _guiPrepare(void) {
int screen = screenMode < SM_PA_TOP ? GFX_BOTTOM : GFX_TOP; C3D_FrameDrawOn(bottomScreen[doubleBuffer]);
if (screen == GFX_BOTTOM) {
return;
}
C3D_RenderBufBind(&bottomScreen);
ctrSetViewportSize(320, 240, true); ctrSetViewportSize(320, 240, true);
} }
@ -268,9 +290,9 @@ static void _setup(struct mGUIRunner* runner) {
if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) { if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) {
filterMode = mode; filterMode = mode;
if (filterMode == FM_NEAREST) { if (filterMode == FM_NEAREST) {
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_NEAREST, GPU_NEAREST); C3D_TexSetFilter(&upscaleBufferTex, GPU_NEAREST, GPU_NEAREST);
} else { } else {
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR); C3D_TexSetFilter(&upscaleBufferTex, GPU_LINEAR, GPU_LINEAR);
} }
} }
if (mCoreConfigGetUIntValue(&runner->config, "darkenMode", &mode) && mode < DM_MAX) { if (mCoreConfigGetUIntValue(&runner->config, "darkenMode", &mode) && mode < DM_MAX) {
@ -326,9 +348,9 @@ static void _gameLoaded(struct mGUIRunner* runner) {
if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) { if (mCoreConfigGetUIntValue(&runner->config, "filterMode", &mode) && mode < FM_MAX) {
filterMode = mode; filterMode = mode;
if (filterMode == FM_NEAREST) { if (filterMode == FM_NEAREST) {
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_NEAREST, GPU_NEAREST); C3D_TexSetFilter(&upscaleBufferTex, GPU_NEAREST, GPU_NEAREST);
} else { } else {
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR); C3D_TexSetFilter(&upscaleBufferTex, GPU_LINEAR, GPU_LINEAR);
} }
} }
if (mCoreConfigGetUIntValue(&runner->config, "darkenMode", &mode) && mode < DM_MAX) { if (mCoreConfigGetUIntValue(&runner->config, "darkenMode", &mode) && mode < DM_MAX) {
@ -372,19 +394,19 @@ static void _drawTex(struct mCore* core, bool faded) {
unsigned screen_w, screen_h; unsigned screen_w, screen_h;
switch (screenMode) { switch (screenMode) {
case SM_PA_BOTTOM: case SM_PA_BOTTOM:
C3D_RenderBufBind(&bottomScreen); C3D_FrameDrawOn(bottomScreen[doubleBuffer]);
screen_w = 320; screen_w = 320;
screen_h = 240; screen_h = 240;
break; break;
case SM_PA_TOP: case SM_PA_TOP:
C3D_RenderBufBind(&topScreen); C3D_FrameDrawOn(topScreen[doubleBuffer]);
screen_w = 400; screen_w = 400;
screen_h = 240; screen_h = 240;
break; break;
default: default:
C3D_RenderBufBind(&upscaleBuffer); C3D_FrameDrawOn(upscaleBuffer);
screen_w = upscaleBuffer.colorBuf.width; screen_w = 512;
screen_h = upscaleBuffer.colorBuf.height; screen_h = 512;
break; break;
} }
@ -473,10 +495,10 @@ static void _drawTex(struct mCore* core, bool faded) {
coreh = h; coreh = h;
screen_h = 240; screen_h = 240;
if (screenMode < SM_PA_TOP) { if (screenMode < SM_PA_TOP) {
C3D_RenderBufBind(&bottomScreen); C3D_FrameDrawOn(bottomScreen[doubleBuffer]);
screen_w = 320; screen_w = 320;
} else { } else {
C3D_RenderBufBind(&topScreen); C3D_FrameDrawOn(topScreen[doubleBuffer]);
screen_w = 400; screen_w = 400;
} }
ctrSetViewportSize(screen_w, screen_h, true); ctrSetViewportSize(screen_w, screen_h, true);
@ -505,7 +527,7 @@ static void _drawTex(struct mCore* core, bool faded) {
x = (screen_w - w) / 2; x = (screen_w - w) / 2;
y = (screen_h - h) / 2; y = (screen_h - h) / 2;
ctrActivateTexture(&upscaleBuffer.colorBuf); ctrActivateTexture(&upscaleBufferTex);
ctrAddRectEx(0xFFFFFFFF, x, y, w, h, 0, 0, corew, coreh, 0); ctrAddRectEx(0xFFFFFFFF, x, y, w, h, 0, 0, corew, coreh, 0);
ctrFlushBatch(); ctrFlushBatch();
} }
@ -572,8 +594,8 @@ static void _incrementScreenMode(struct mGUIRunner* runner) {
screenMode = (screenMode + 1) % SM_MAX; screenMode = (screenMode + 1) % SM_MAX;
mCoreConfigSetUIntValue(&runner->config, "screenMode", screenMode); mCoreConfigSetUIntValue(&runner->config, "screenMode", screenMode);
C3D_RenderBufClear(&bottomScreen); C3D_FrameBufClear(&bottomScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
C3D_RenderBufClear(&topScreen); C3D_FrameBufClear(&topScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
} }
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) { static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
@ -716,7 +738,7 @@ int main() {
} }
C3D_TexSetWrap(&outputTexture, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE); C3D_TexSetWrap(&outputTexture, GPU_CLAMP_TO_EDGE, GPU_CLAMP_TO_EDGE);
C3D_TexSetFilter(&outputTexture, GPU_NEAREST, GPU_NEAREST); C3D_TexSetFilter(&outputTexture, GPU_NEAREST, GPU_NEAREST);
C3D_TexSetFilter(&upscaleBuffer.colorBuf, GPU_LINEAR, GPU_LINEAR); C3D_TexSetFilter(&upscaleBufferTex, GPU_LINEAR, GPU_LINEAR);
void* outputTextureEnd = (u8*)outputTexture.data + 256 * 256 * 2; void* outputTextureEnd = (u8*)outputTexture.data + 256 * 256 * 2;
// Zero texture data to make sure no garbage around the border interferes with filtering // Zero texture data to make sure no garbage around the border interferes with filtering