3DS: Improve graphics pipeline, framelimiting

This commit is contained in:
Vicki Pfau 2017-09-02 15:05:14 -07:00
parent 41f27bf617
commit 10b14f90d1
3 changed files with 64 additions and 46 deletions

View File

@ -26,23 +26,21 @@ struct ctrUIVertex {
float rotate[2]; float rotate[2];
}; };
#define MAX_NUM_QUADS 256 #define MAX_NUM_QUADS 4096
#define BUFFER_PARTITIONS 4 #define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex)
#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 const C3D_Tex* activeTexture = NULL;
static shaderProgram_s uiProgram; static shaderProgram_s uiProgram;
static DVLB_s* uiShader = NULL; static DVLB_s* uiShader = NULL;
static int GSH_FVEC_projectionMtx; static int GSH_FVEC_projectionMtx;
static int GSH_FVEC_textureMtx; static int GSH_FVEC_textureMtx;
bool ctrInitGpu() { bool ctrInitGpu(void) {
// Load vertex shader binary // Load vertex shader binary
uiShader = DVLB_ParseFile((u32*) uishader, uishader_size); uiShader = DVLB_ParseFile((u32*) uishader, uishader_size);
if (uiShader == NULL) { if (uiShader == NULL) {
@ -85,7 +83,7 @@ bool ctrInitGpu() {
return true; return true;
} }
void ctrDeinitGpu() { void ctrDeinitGpu(void) {
if (ctrVertexBuffer) { if (ctrVertexBuffer) {
linearFree(ctrVertexBuffer); linearFree(ctrVertexBuffer);
ctrVertexBuffer = NULL; ctrVertexBuffer = NULL;
@ -110,10 +108,23 @@ void ctrSetViewportSize(s16 w, s16 h, bool tilt) {
C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx); C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx);
} }
void ctrActivateTexture(C3D_Tex* texture) { void ctrFlushBatch(void) {
int thisBatch = ctrNumVerts - ctrVertStart;
if (!thisBatch) {
return;
}
if (thisBatch < 0) {
svcBreak(USERBREAK_PANIC);
}
C3D_DrawArrays(GPU_GEOMETRY_PRIM, ctrVertStart, thisBatch);
ctrVertStart = ctrNumVerts;
}
void ctrActivateTexture(const C3D_Tex* texture) {
if (texture == activeTexture) { if (texture == activeTexture) {
return; return;
} }
if (activeTexture) { if (activeTexture) {
ctrFlushBatch(); ctrFlushBatch();
} }
@ -174,16 +185,11 @@ void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s
return; return;
} }
if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) { if (ctrNumVerts == MAX_NUM_QUADS) {
ctrFlushBatch(); abort();
++ctrVertPartition;
if (ctrVertPartition == BUFFER_PARTITIONS) {
svcBreak(USERBREAK_PANIC);
}
ctrVertStart = ctrVertPartition * MAX_NUM_QUADS;
} }
struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts]; struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrNumVerts];
vtx->x = x; vtx->x = x;
vtx->y = y; vtx->y = y;
vtx->w = w; vtx->w = w;
@ -203,24 +209,17 @@ void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) {
ctrAddRectEx(color, x, y, w, h, u, v, w, h, 0); ctrAddRectEx(color, x, y, w, h, u, v, w, h, 0);
} }
void ctrFlushBatch(void) { void ctrStartFrame(void) {
if (ctrNumVerts == 0) { ctrNumVerts = 0;
return; ctrVertStart = 0;
} activeTexture = NULL;
C3D_BufInfo* bufInfo = C3D_GetBufInfo(); C3D_BufInfo* bufInfo = C3D_GetBufInfo();
BufInfo_Init(bufInfo); BufInfo_Init(bufInfo);
BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 4, 0x3210); BufInfo_Add(bufInfo, ctrVertexBuffer, sizeof(struct ctrUIVertex), 4, 0x3210);
GSPGPU_FlushDataCache(&ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex) * ctrNumVerts);
C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumVerts);
ctrVertStart += ctrNumVerts;
ctrNumVerts = 0;
} }
void ctrFinalize(void) { void ctrEndFrame(void) {
ctrFlushBatch(); ctrFlushBatch();
ctrVertStart = 0; GSPGPU_FlushDataCache(ctrVertexBuffer, sizeof(struct ctrUIVertex) * ctrNumVerts);
ctrVertPartition = 0;
} }

View File

@ -16,12 +16,13 @@ void ctrDeinitGpu(void);
void ctrSetViewportSize(s16 w, s16 h, bool tilt); void ctrSetViewportSize(s16 w, s16 h, bool tilt);
void ctrActivateTexture(C3D_Tex* texture); void ctrActivateTexture(const C3D_Tex* texture);
void ctrTextureMultiply(void); void ctrTextureMultiply(void);
void ctrTextureBias(u32 color); void ctrTextureBias(u32 color);
void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate); void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate);
void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h); void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h);
void ctrFlushBatch(void); void ctrFlushBatch(void);
void ctrFinalize(void); void ctrStartFrame(void);
void ctrEndFrame(void);
#endif #endif

View File

@ -92,11 +92,12 @@ 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 u64 tickCounter;
static C3D_RenderTarget* topScreen[2]; static C3D_RenderTarget* topScreen[2];
static C3D_RenderTarget* bottomScreen[2]; static C3D_RenderTarget* bottomScreen[2];
static int doubleBuffer = 0; static int doubleBuffer = 0;
static bool frameStarted = false;
static C3D_RenderTarget* upscaleBuffer; static C3D_RenderTarget* upscaleBuffer;
static C3D_Tex upscaleBufferTex; static C3D_Tex upscaleBufferTex;
@ -226,22 +227,38 @@ 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_FrameBegin(frameLimiter ? 0 : C3D_FRAME_NONBLOCK); }
static void _frameStart(void) {
if (frameStarted) {
return;
}
frameStarted = true;
u8 flags = 0;
if (!frameLimiter) {
if (tickCounter + 4481000 > svcGetSystemTick()) {
flags = C3D_FRAME_NONBLOCK;
} else {
tickCounter = svcGetSystemTick();
}
}
C3D_FrameBegin(flags);
// Mark both buffers used to make sure they get cleared // Mark both buffers used to make sure they get cleared
C3D_FrameDrawOn(topScreen[doubleBuffer]); C3D_FrameDrawOn(topScreen[doubleBuffer]);
C3D_FrameDrawOn(bottomScreen[doubleBuffer]); C3D_FrameDrawOn(bottomScreen[doubleBuffer]);
ctrStartFrame();
} }
static void _drawEnd(void) { static void _drawEnd(void) {
ctrFinalize(); if (!frameStarted) {
return;
}
ctrEndFrame();
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_RenderTargetSetOutput(topScreen[doubleBuffer], GFX_TOP, GFX_LEFT, 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)); C3D_RenderTargetSetOutput(bottomScreen[doubleBuffer], GFX_BOTTOM, GFX_LEFT, GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8));
C3D_FrameEnd(GX_CMDLIST_FLUSH); C3D_FrameEnd(GX_CMDLIST_FLUSH);
if (frameLimiter) { frameStarted = false;
while (frameCounter == C3D_FrameCounter(0)) {
gspWaitForAnyEvent();
}
}
doubleBuffer ^= 1; doubleBuffer ^= 1;
C3D_FrameBufClear(&bottomScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0); C3D_FrameBufClear(&bottomScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
C3D_FrameBufClear(&topScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0); C3D_FrameBufClear(&topScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);
@ -263,6 +280,7 @@ static int _batteryState(void) {
} }
static void _guiPrepare(void) { static void _guiPrepare(void) {
_frameStart();
C3D_FrameDrawOn(bottomScreen[doubleBuffer]); C3D_FrameDrawOn(bottomScreen[doubleBuffer]);
ctrSetViewportSize(320, 240, true); ctrSetViewportSize(320, 240, true);
} }
@ -442,12 +460,8 @@ static void _gameUnloaded(struct mGUIRunner* runner) {
} }
} }
static void _storeCounter(struct mGUIRunner* runner) {
UNUSED(runner);
frameCounter = C3D_FrameCounter(0);
}
static void _drawTex(struct mCore* core, bool faded) { static void _drawTex(struct mCore* core, bool faded) {
_frameStart();
unsigned screen_w, screen_h; unsigned screen_w, screen_h;
switch (screenMode) { switch (screenMode) {
case SM_PA_BOTTOM: case SM_PA_BOTTOM:
@ -657,7 +671,11 @@ static void _incrementScreenMode(struct mGUIRunner* runner) {
static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) { static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) {
UNUSED(runner); UNUSED(runner);
if (frameLimiter == limit) {
return;
}
frameLimiter = limit; frameLimiter = limit;
tickCounter = svcGetSystemTick();
} }
static uint32_t _pollInput(const struct mInputMap* map) { static uint32_t _pollInput(const struct mInputMap* map) {
@ -995,7 +1013,7 @@ int main() {
.teardown = 0, .teardown = 0,
.gameLoaded = _gameLoaded, .gameLoaded = _gameLoaded,
.gameUnloaded = _gameUnloaded, .gameUnloaded = _gameUnloaded,
.prepareForFrame = _storeCounter, .prepareForFrame = 0,
.drawFrame = _drawFrame, .drawFrame = _drawFrame,
.drawScreenshot = _drawScreenshot, .drawScreenshot = _drawScreenshot,
.paused = _gameUnloaded, .paused = _gameUnloaded,