mirror of https://github.com/mgba-emu/mgba.git
3DS: Improve graphics pipeline, framelimiting
This commit is contained in:
parent
41f27bf617
commit
10b14f90d1
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue