From f73fd7f3da3e36b6a11fe5e15cafaca8c0fd733f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 3 Apr 2017 14:31:40 -0700 Subject: [PATCH] GB: Fix flickering when screen is strobed quickly --- CHANGES | 1 + include/mgba/internal/gb/video.h | 1 + src/gb/renderers/software.c | 25 +++++++--------------- src/gb/video.c | 36 +++++++++++++++++++------------- 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/CHANGES b/CHANGES index a873c957d..cdb0889eb 100644 --- a/CHANGES +++ b/CHANGES @@ -33,6 +33,7 @@ Bugfixes: - Windows: Fix VDir.rewind - SDL: Fix game crash check - SDL: Fix race condition with audio thread when starting + - GB: Fix flickering when screen is strobed quickly Misc: - SDL: Remove scancode key input - GBA Video: Clean up unused timers diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h index 67bf96405..a7b143077 100644 --- a/include/mgba/internal/gb/video.h +++ b/include/mgba/internal/gb/video.h @@ -119,6 +119,7 @@ struct GBVideo { int ocpIndex; bool ocpIncrement; + uint16_t dmgPalette[4]; uint16_t palette[64]; int32_t frameCounter; diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index 61daa9f98..6c4740d76 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -24,26 +24,15 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int startX, int endX, int y); static void _clearScreen(struct GBVideoSoftwareRenderer* renderer) { - // TODO: Dynamic from dmgPalette -#ifdef COLOR_16_BIT -#ifdef COLOR_5_6_5 - color_t palette0 = 0xFFDF; -#else - color_t palette0 = 0x7FFF; -#endif -#else - color_t palette0 = 0xFFFFFF; -#endif - int y; for (y = 0; y < GB_VIDEO_VERTICAL_PIXELS; ++y) { color_t* row = &renderer->outputBuffer[renderer->outputBufferStride * y]; int x; for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; x += 4) { - row[x + 0] = palette0; - row[x + 1] = palette0; - row[x + 2] = palette0; - row[x + 3] = palette0; + row[x + 0] = renderer->palette[0]; + row[x + 1] = renderer->palette[0]; + row[x + 2] = renderer->palette[0]; + row[x + 3] = renderer->palette[0]; } } } @@ -85,9 +74,6 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; switch (address) { case REG_LCDC: - if (GBRegisterLCDCIsEnable(softwareRenderer->lcdc) && !GBRegisterLCDCIsEnable(value)) { - _clearScreen(softwareRenderer); - } softwareRenderer->lcdc = value; break; case REG_SCY: @@ -197,6 +183,9 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) mappedMemoryFree(softwareRenderer->temporaryBuffer, GB_VIDEO_HORIZONTAL_PIXELS * GB_VIDEO_VERTICAL_PIXELS * 4); softwareRenderer->temporaryBuffer = 0; } + if (!GBRegisterLCDCIsEnable(softwareRenderer->lcdc)) { + _clearScreen(softwareRenderer); + } softwareRenderer->currentWy = 0; } diff --git a/src/gb/video.c b/src/gb/video.c index 038729b20..e1650acd9 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -61,6 +61,11 @@ void GBVideoInit(struct GBVideo* video) { video->frameEvent.name = "GB Video Frame"; video->frameEvent.callback = _updateFrameCount; video->frameEvent.priority = 9; + + video->dmgPalette[0] = 0x7FFF; + video->dmgPalette[1] = 0x56B5; + video->dmgPalette[2] = 0x294A; + video->dmgPalette[3] = 0x0000; } void GBVideoReset(struct GBVideo* video) { @@ -157,7 +162,6 @@ void _endMode1(struct mTiming* timing, void* context, uint32_t cyclesLate) { video->p->memory.io[REG_IF] |= (1 << GB_IRQ_LCDSTAT); GBUpdateIRQs(video->p); } - video->renderer->finishFrame(video->renderer); if (video->p->memory.mbcType == GB_MBC7 && video->p->memory.rotation && video->p->memory.rotation->sample) { video->p->memory.rotation->sample(video->p->memory.rotation); } @@ -234,6 +238,7 @@ void _updateFrameCount(struct mTiming* timing, void* context, uint32_t cyclesLat GBFrameEnded(video->p); --video->frameskipCounter; if (video->frameskipCounter < 0) { + video->renderer->finishFrame(video->renderer); mCoreSyncPostFrame(video->p->sync); video->frameskipCounter = video->frameskip; } @@ -318,6 +323,8 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) { GBUpdateIRQs(video->p); } video->p->memory.io[REG_STAT] = video->stat; + video->renderer->writePalette(video->renderer, 0, video->palette[0]); + mTimingDeschedule(&video->p->timing, &video->frameEvent); } if (GBRegisterLCDCIsEnable(video->p->memory.io[REG_LCDC]) && !GBRegisterLCDCIsEnable(value)) { @@ -326,6 +333,8 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) { video->p->memory.io[REG_STAT] = video->stat; video->ly = 0; video->p->memory.io[REG_LY] = 0; + video->renderer->writePalette(video->renderer, 0, video->dmgPalette[0]); + mTimingDeschedule(&video->p->timing, &video->modeEvent); mTimingSchedule(&video->p->timing, &video->frameEvent, GB_VIDEO_TOTAL_LENGTH); } @@ -351,34 +360,33 @@ void GBVideoWriteLYC(struct GBVideo* video, uint8_t value) { } void GBVideoWritePalette(struct GBVideo* video, uint16_t address, uint8_t value) { - static const uint16_t dmgPalette[4] = { 0x7FFF, 0x56B5, 0x294A, 0x0000}; if (video->p->model < GB_MODEL_CGB) { switch (address) { case REG_BGP: - video->palette[0] = dmgPalette[value & 3]; - video->palette[1] = dmgPalette[(value >> 2) & 3]; - video->palette[2] = dmgPalette[(value >> 4) & 3]; - video->palette[3] = dmgPalette[(value >> 6) & 3]; + video->palette[0] = video->dmgPalette[value & 3]; + video->palette[1] = video->dmgPalette[(value >> 2) & 3]; + video->palette[2] = video->dmgPalette[(value >> 4) & 3]; + video->palette[3] = video->dmgPalette[(value >> 6) & 3]; video->renderer->writePalette(video->renderer, 0, video->palette[0]); video->renderer->writePalette(video->renderer, 1, video->palette[1]); video->renderer->writePalette(video->renderer, 2, video->palette[2]); video->renderer->writePalette(video->renderer, 3, video->palette[3]); break; case REG_OBP0: - video->palette[8 * 4 + 0] = dmgPalette[value & 3]; - video->palette[8 * 4 + 1] = dmgPalette[(value >> 2) & 3]; - video->palette[8 * 4 + 2] = dmgPalette[(value >> 4) & 3]; - video->palette[8 * 4 + 3] = dmgPalette[(value >> 6) & 3]; + video->palette[8 * 4 + 0] = video->dmgPalette[value & 3]; + video->palette[8 * 4 + 1] = video->dmgPalette[(value >> 2) & 3]; + video->palette[8 * 4 + 2] = video->dmgPalette[(value >> 4) & 3]; + video->palette[8 * 4 + 3] = video->dmgPalette[(value >> 6) & 3]; video->renderer->writePalette(video->renderer, 8 * 4 + 0, video->palette[8 * 4 + 0]); video->renderer->writePalette(video->renderer, 8 * 4 + 1, video->palette[8 * 4 + 1]); video->renderer->writePalette(video->renderer, 8 * 4 + 2, video->palette[8 * 4 + 2]); video->renderer->writePalette(video->renderer, 8 * 4 + 3, video->palette[8 * 4 + 3]); break; case REG_OBP1: - video->palette[9 * 4 + 0] = dmgPalette[value & 3]; - video->palette[9 * 4 + 1] = dmgPalette[(value >> 2) & 3]; - video->palette[9 * 4 + 2] = dmgPalette[(value >> 4) & 3]; - video->palette[9 * 4 + 3] = dmgPalette[(value >> 6) & 3]; + video->palette[9 * 4 + 0] = video->dmgPalette[value & 3]; + video->palette[9 * 4 + 1] = video->dmgPalette[(value >> 2) & 3]; + video->palette[9 * 4 + 2] = video->dmgPalette[(value >> 4) & 3]; + video->palette[9 * 4 + 3] = video->dmgPalette[(value >> 6) & 3]; video->renderer->writePalette(video->renderer, 9 * 4 + 0, video->palette[9 * 4 + 0]); video->renderer->writePalette(video->renderer, 9 * 4 + 1, video->palette[9 * 4 + 1]); video->renderer->writePalette(video->renderer, 9 * 4 + 2, video->palette[9 * 4 + 2]);