all repos — mgba @ 39ad11d4711374cfd11a843f544e4c4b5dfff489

mGBA Game Boy Advance Emulator

Merge branch 'master' (early part) into medusa
Vicki Pfau vi@endrift.com
Fri, 28 Jun 2019 15:50:12 -0700
commit

39ad11d4711374cfd11a843f544e4c4b5dfff489

parent

a6ce525da1ed0f7e14e8db927871d2127681fc95

M CHANGESCHANGES

@@ -73,6 +73,9 @@ - GB Audio: Clock frame events on DIV

- GBA: Fix SharkPort saves for EEPROM games - Qt: Fix opening in fullscreen (fixes mgba.io/i/993) - Python: Fix package directory + - GB Memory: Fix OAM DMA blocking regions (fixes mgba.io/i/1013) + - Wii: Fix various setup and teardown drawing issues (fixes mgba.io/i/988) + - GBA Timer: Fix timers sometimes being late (fixes mgba.io/i/1012) Misc: - GBA Timer: Use global cycles for timers - GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
M CMakeLists.txtCMakeLists.txt

@@ -11,7 +11,9 @@ else()

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS /wd4003 /wd4244 /wd4146") endif() set(USE_DEBUGGERS ON CACHE BOOL "Whether or not to enable the debugging infrastructure") -set(USE_EDITLINE ON CACHE BOOL "Whether or not to enable the CLI-mode debugger") +if (NOT WIN32) + set(USE_EDITLINE ON CACHE BOOL "Whether or not to enable the CLI-mode debugger") +endif() set(USE_GDB_STUB ON CACHE BOOL "Whether or not to enable the GDB stub ARM debugger") set(USE_FFMPEG ON CACHE BOOL "Whether or not to enable FFmpeg support") set(USE_ZLIB ON CACHE BOOL "Whether or not to enable zlib support")

@@ -1023,7 +1025,9 @@ message(STATUS " Game Boy: ${M_CORE_GB}")

message(STATUS " DS: ${M_CORE_DS}") message(STATUS "Features:") message(STATUS " Debuggers: ${USE_DEBUGGERS}") - message(STATUS " CLI debugger: ${USE_EDITLINE}") + if(NOT WIN32) + message(STATUS " CLI debugger: ${USE_EDITLINE}") + endif() message(STATUS " GDB stub: ${USE_GDB_STUB}") message(STATUS " Video recording: ${USE_FFMPEG}") message(STATUS " GIF recording: ${USE_MAGICK}")
M README.mdREADME.md

@@ -154,11 +154,11 @@ To build on Windows for development, using MSYS2 is recommended. Follow the installation steps found on their [website](https://msys2.github.io). Make sure you're running the 32-bit version ("MSYS2 MinGW 32-bit") (or the 64-bit version "MSYS2 MinGW 64-bit" if you want to build for x86_64) and run this additional command (including the braces) to install the needed dependencies (please note that this involves downloading over 1100MiB of packages, so it will take a long time):

For x86 (32 bit) builds: - pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} + pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libelf,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} For x86_64 (64 bit) builds: - pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} + pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libelf,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} Check out the source code by running this command:
M README_DE.mdREADME_DE.md

@@ -136,11 +136,11 @@ Um mGBA auf Windows zu kompilieren, wird MSYS2 empfohlen. Befolge die Installationsschritte auf der [MSYS2-Website](https://msys2.github.io). Stelle sicher, dass Du die 32-Bit-Version ("MSYS2 MinGW 32-bit") (oder die 64-Bit-Version "MSYS2 MinGW 64-bit", wenn Du mGBA für x86_64 kompilieren willst) verwendest und führe folgendes Kommando (einschließlich der Klammern) aus, um alle benötigten Abhängigkeiten zu installieren. Bitte beachte, dass dafür über 1100MiB an Paketen heruntergeladen werden, was eine Weile dauern kann:

Für x86 (32 Bit): - pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} + pacman -Sy mingw-w64-i686-{cmake,ffmpeg,gcc,gdb,imagemagick,libelf,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} Für x86_64 (64 Bit): - pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} + pacman -Sy mingw-w64-x86_64-{cmake,ffmpeg,gcc,gdb,imagemagick,libelf,libepoxy,libzip,pkg-config,qt5,SDL2,ntldd-git} Lade den aktuellen mGBA-Quellcode mithilfe des folgenden Kommandos herunter:
M include/mgba/internal/gb/video.hinclude/mgba/internal/gb/video.h

@@ -26,7 +26,6 @@ GB_VIDEO_MODE_0_LENGTH_BASE = 204,

GB_VIDEO_HORIZONTAL_LENGTH = 456, - GB_VIDEO_MODE_1_LENGTH = 65664, GB_VIDEO_TOTAL_LENGTH = 70224, GB_BASE_MAP = 0x1800,
M src/gb/memory.csrc/gb/memory.c

@@ -16,31 +16,33 @@ #include <mgba-util/memory.h>

mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory", "gb.memory"); -struct OAMBlock { - uint16_t low; - uint16_t high; +enum GBBus { + GB_BUS_CPU, + GB_BUS_MAIN, + GB_BUS_VRAM, + GB_BUS_RAM }; -static const struct OAMBlock _oamBlockDMG[] = { - { 0xA000, 0xFE00 }, - { 0xA000, 0xFE00 }, - { 0xA000, 0xFE00 }, - { 0xA000, 0xFE00 }, - { 0x8000, 0xA000 }, - { 0xA000, 0xFE00 }, - { 0xA000, 0xFE00 }, - { 0xA000, 0xFE00 }, +static const enum GBBus _oamBlockDMG[] = { + GB_BUS_MAIN, // 0x0000 + GB_BUS_MAIN, // 0x2000 + GB_BUS_MAIN, // 0x4000 + GB_BUS_MAIN, // 0x6000 + GB_BUS_VRAM, // 0x8000 + GB_BUS_MAIN, // 0xA000 + GB_BUS_MAIN, // 0xC000 + GB_BUS_CPU, // 0xE000 }; -static const struct OAMBlock _oamBlockCGB[] = { - { 0xA000, 0xC000 }, - { 0xA000, 0xC000 }, - { 0xA000, 0xC000 }, - { 0xA000, 0xC000 }, - { 0x8000, 0xA000 }, - { 0xA000, 0xC000 }, - { 0xC000, 0xFE00 }, - { 0xA000, 0xC000 }, +static const enum GBBus _oamBlockCGB[] = { + GB_BUS_MAIN, // 0x0000 + GB_BUS_MAIN, // 0x2000 + GB_BUS_MAIN, // 0x4000 + GB_BUS_MAIN, // 0x6000 + GB_BUS_VRAM, // 0x8000 + GB_BUS_MAIN, // 0xA000 + GB_BUS_RAM, // 0xC000 + GB_BUS_CPU // 0xE000 }; static void _pristineCow(struct GB* gba);

@@ -192,9 +194,10 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {

struct GB* gb = (struct GB*) cpu->master; struct GBMemory* memory = &gb->memory; if (gb->memory.dmaRemaining) { - const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; - block = &block[memory->dmaSource >> 13]; - if (address >= block->low && address < block->high) { + const enum GBBus* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; + enum GBBus dmaBus = block[memory->dmaSource >> 13]; + enum GBBus accessBus = block[address >> 13]; + if (dmaBus != GB_BUS_CPU && dmaBus == accessBus) { return 0xFF; } if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {

@@ -264,9 +267,10 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {

struct GB* gb = (struct GB*) cpu->master; struct GBMemory* memory = &gb->memory; if (gb->memory.dmaRemaining) { - const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; - block = &block[memory->dmaSource >> 13]; - if (address >= block->low && address < block->high) { + const enum GBBus* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB; + enum GBBus dmaBus = block[memory->dmaSource >> 13]; + enum GBBus accessBus = block[address >> 13]; + if (dmaBus != GB_BUS_CPU && dmaBus == accessBus) { return; } if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
M src/gb/renderers/software.csrc/gb/renderers/software.c

@@ -75,25 +75,25 @@ tileData[2] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x10];

tileData[3] = renderer->d.sgbCharRam[(SGBBgAttributesGetTile(mapData) * 16 + localY) * 2 + 0x11]; size_t base = y * renderer->outputBufferStride + x; - int p = SGBBgAttributesGetPalette(mapData) * 0x10; + int paletteBase = SGBBgAttributesGetPalette(mapData) * 0x10; + int colorSelector; + if (SGBBgAttributesIsXFlip(mapData)) { - renderer->outputBuffer[base + 0] = renderer->palette[p | ((tileData[0] >> 0) & 0x1) | ((tileData[1] << 1) & 0x2) | ((tileData[2] << 2) & 0x4) | ((tileData[3] << 3) & 0x8)]; - renderer->outputBuffer[base + 1] = renderer->palette[p | ((tileData[0] >> 1) & 0x1) | ((tileData[1] >> 0) & 0x2) | ((tileData[2] << 1) & 0x4) | ((tileData[3] << 2) & 0x8)]; - renderer->outputBuffer[base + 2] = renderer->palette[p | ((tileData[0] >> 2) & 0x1) | ((tileData[1] >> 1) & 0x2) | ((tileData[2] >> 0) & 0x4) | ((tileData[3] << 1) & 0x8)]; - renderer->outputBuffer[base + 3] = renderer->palette[p | ((tileData[0] >> 3) & 0x1) | ((tileData[1] >> 2) & 0x2) | ((tileData[2] >> 1) & 0x4) | ((tileData[3] >> 0) & 0x8)]; - renderer->outputBuffer[base + 4] = renderer->palette[p | ((tileData[0] >> 4) & 0x1) | ((tileData[1] >> 3) & 0x2) | ((tileData[2] >> 2) & 0x4) | ((tileData[3] >> 1) & 0x8)]; - renderer->outputBuffer[base + 5] = renderer->palette[p | ((tileData[0] >> 5) & 0x1) | ((tileData[1] >> 4) & 0x2) | ((tileData[2] >> 3) & 0x4) | ((tileData[3] >> 2) & 0x8)]; - renderer->outputBuffer[base + 6] = renderer->palette[p | ((tileData[0] >> 6) & 0x1) | ((tileData[1] >> 5) & 0x2) | ((tileData[2] >> 4) & 0x4) | ((tileData[3] >> 3) & 0x8)]; - renderer->outputBuffer[base + 7] = renderer->palette[p | ((tileData[0] >> 7) & 0x1) | ((tileData[1] >> 6) & 0x2) | ((tileData[2] >> 5) & 0x4) | ((tileData[3] >> 4) & 0x8)]; + for (i = 0; i < 8; ++i) { + colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; + // The first color of every palette is transparent + if (colorSelector) { + renderer->outputBuffer[base + i] = renderer->palette[paletteBase | colorSelector]; + } + } } else { - renderer->outputBuffer[base + 0] = renderer->palette[p | ((tileData[0] >> 7) & 0x1) | ((tileData[1] >> 6) & 0x2) | ((tileData[2] >> 5) & 0x4) | ((tileData[3] >> 4) & 0x8)]; - renderer->outputBuffer[base + 1] = renderer->palette[p | ((tileData[0] >> 6) & 0x1) | ((tileData[1] >> 5) & 0x2) | ((tileData[2] >> 4) & 0x4) | ((tileData[3] >> 3) & 0x8)]; - renderer->outputBuffer[base + 2] = renderer->palette[p | ((tileData[0] >> 5) & 0x1) | ((tileData[1] >> 4) & 0x2) | ((tileData[2] >> 3) & 0x4) | ((tileData[3] >> 2) & 0x8)]; - renderer->outputBuffer[base + 3] = renderer->palette[p | ((tileData[0] >> 4) & 0x1) | ((tileData[1] >> 3) & 0x2) | ((tileData[2] >> 2) & 0x4) | ((tileData[3] >> 1) & 0x8)]; - renderer->outputBuffer[base + 4] = renderer->palette[p | ((tileData[0] >> 3) & 0x1) | ((tileData[1] >> 2) & 0x2) | ((tileData[2] >> 1) & 0x4) | ((tileData[3] >> 0) & 0x8)]; - renderer->outputBuffer[base + 5] = renderer->palette[p | ((tileData[0] >> 2) & 0x1) | ((tileData[1] >> 1) & 0x2) | ((tileData[2] >> 0) & 0x4) | ((tileData[3] << 1) & 0x8)]; - renderer->outputBuffer[base + 6] = renderer->palette[p | ((tileData[0] >> 1) & 0x1) | ((tileData[1] >> 0) & 0x2) | ((tileData[2] << 1) & 0x4) | ((tileData[3] << 2) & 0x8)]; - renderer->outputBuffer[base + 7] = renderer->palette[p | ((tileData[0] >> 0) & 0x1) | ((tileData[1] << 1) & 0x2) | ((tileData[2] << 2) & 0x4) | ((tileData[3] << 3) & 0x8)]; + for (i = 7; i >= 0; --i) { + colorSelector = (tileData[0] >> i & 0x1) << 0 | (tileData[1] >> i & 0x1) << 1 | (tileData[2] >> i & 0x1) << 2 | (tileData[3] >> i & 0x1) << 3; + + if (colorSelector) { + renderer->outputBuffer[base + 7 - i] = renderer->palette[paletteBase | colorSelector]; + } + } } } }
M src/gba/timer.csrc/gba/timer.c

@@ -50,7 +50,7 @@ int32_t currentTime = mTimingCurrentTime(timing) - cyclesLate;

int32_t tickMask = (1 << GBATimerFlagsGetPrescaleBits(timer->flags)) - 1; currentTime &= ~tickMask; timer->lastEvent = currentTime; - GBATimerUpdateRegisterInternal(timer, timing, io, 0); + GBATimerUpdateRegisterInternal(timer, timing, io, TIMER_RELOAD_DELAY + cyclesLate); if (GBATimerFlagsIsDoIrq(timer->flags)) { timer->flags = GBATimerFlagsFillIrqPending(timer->flags);

@@ -171,7 +171,7 @@ *io = tickIncrement;

if (!mTimingIsScheduled(timing, &timer->event)) { tickIncrement = (0x10000 - tickIncrement) << prescaleBits; currentTime -= mTimingCurrentTime(timing) - skew; - mTimingSchedule(timing, &timer->event, TIMER_RELOAD_DELAY + tickIncrement + currentTime); + mTimingSchedule(timing, &timer->event, tickIncrement + currentTime); } }
M src/platform/libretro/libretro.csrc/platform/libretro/libretro.c

@@ -63,6 +63,27 @@ .volume = 0x100,

}; struct retro_variable var; + enum GBModel model; + const char* modelName; + + var.key = "mgba_model"; + var.value = 0; + if (environCallback(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) { + if (strcmp(var.value, "Game Boy") == 0) { + model = GB_MODEL_DMG; + } else if (strcmp(var.value, "Super Game Boy") == 0) { + model = GB_MODEL_SGB; + } else if (strcmp(var.value, "Game Boy Color") == 0) { + model = GB_MODEL_CGB; + } else { + model = GB_MODEL_AUTODETECT; + } + + modelName = GBModelToName(model); + mCoreConfigSetDefaultValue(&core->config, "gb.model", modelName); + mCoreConfigSetDefaultValue(&core->config, "sgb.model", modelName); + mCoreConfigSetDefaultValue(&core->config, "cgb.model", modelName); + } var.key = "mgba_use_bios"; var.value = 0;

@@ -119,6 +140,7 @@

struct retro_variable vars[] = { { "mgba_solar_sensor_level", "Solar sensor level; 0|1|2|3|4|5|6|7|8|9|10" }, { "mgba_allow_opposing_directions", "Allow opposing directional input; OFF|ON" }, + { "mgba_model", "Game Boy model (requires restart); Autodetect|Game Boy|Super Game Boy|Game Boy Color" }, { "mgba_use_bios", "Use BIOS file if found (requires restart); ON|OFF" }, { "mgba_skip_bios", "Skip BIOS intro (requires restart); OFF|ON" }, { "mgba_sgb_borders", "Use Super Game Boy borders (requires restart); ON|OFF" },

@@ -299,7 +321,7 @@ core->desiredVideoDimensions(core, &width, &height);

videoCallback(outputBuffer, width, height, BYTES_PER_PIXEL * 256); } -void static _setupMaps(struct mCore* core) { +static void _setupMaps(struct mCore* core) { #ifdef M_CORE_GBA if (core->platform(core) == PLATFORM_GBA) { struct GBA* gba = core->board;

@@ -417,7 +439,9 @@ mCoreInitConfig(core, NULL);

core->init(core); core->setAVStream(core, &stream); - outputBuffer = malloc(256 * 224 * BYTES_PER_PIXEL); + size_t size = 256 * 224 * BYTES_PER_PIXEL; + outputBuffer = malloc(size); + memset(outputBuffer, 0xFF, size); core->setVideoBuffer(core, outputBuffer, 256); core->setAudioBufferSize(core, SAMPLES);

@@ -434,21 +458,52 @@ _reloadSettings();

core->loadROM(core, rom); core->loadSave(core, save); + const char* sysDir = 0; + const char* biosName = 0; + char biosPath[PATH_MAX]; + environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir); + #ifdef M_CORE_GBA if (core->platform(core) == PLATFORM_GBA) { core->setPeripheral(core, mPERIPH_GBA_LUMINANCE, &lux); + biosName = "gba_bios.bin"; - const char* sysDir = 0; - if (core->opts.useBios && environCallback(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &sysDir)) { - char biosPath[PATH_MAX]; - snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, "gba_bios.bin"); - struct VFile* bios = VFileOpen(biosPath, O_RDONLY); - if (bios) { - core->loadBIOS(core, bios, 0); - } + } +#endif + +#ifdef M_CORE_GB + if (core->platform(core) == PLATFORM_GB) { + const char* modelName = mCoreConfigGetValue(&core->config, "gb.model"); + struct GB* gb = core->board; + + if (modelName) { + gb->model = GBNameToModel(modelName); + } else { + GBDetectModel(gb); } + + switch (gb->model) { + case GB_MODEL_CGB: + biosName = "gbc_bios.bin"; + break; + case GB_MODEL_SGB: + biosName = "sgb_bios.bin"; + break; + case GB_MODEL_DMG: + default: + biosName = "gb_bios.bin"; + break; + }; } #endif + + if (core->opts.useBios && sysDir && biosName) { + snprintf(biosPath, sizeof(biosPath), "%s%s%s", sysDir, PATH_SEP, biosName); + struct VFile* bios = VFileOpen(biosPath, O_RDONLY); + if (bios) { + core->loadBIOS(core, bios, 0); + } + } core->reset(core); _setupMaps(core);
M src/platform/qt/CMakeLists.txtsrc/platform/qt/CMakeLists.txt

@@ -173,7 +173,7 @@ list(APPEND SOURCE_FILES

VideoDumper.cpp) if (WIN32 AND QT_STATIC) list(APPEND QT_LIBRARIES Qt5::QWindowsAudioPlugin Qt5::DSServicePlugin - strmiids winmm mfuuid mfplat mf ksguid dxva2 evr d3d9) + strmiids mfuuid mfplat mf ksguid dxva2 evr d3d9) endif() list(APPEND QT_LIBRARIES Qt5::Multimedia) list(APPEND QT_DEFINES BUILD_QT_MULTIMEDIA)

@@ -275,7 +275,7 @@ list(APPEND QT_LIBRARIES Qt5::OpenGL ${OPENGL_LIBRARY} ${OPENGLES2_LIBRARY})

endif() if(WIN32 AND QT_STATIC) list(APPEND QT_LIBRARIES qwindows dwmapi imm32 uxtheme Qt5EventDispatcherSupport Qt5FontDatabaseSupport Qt5ThemeSupport) - set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "qtpcre2;version;ws2_32") + set_target_properties(Qt5::Core PROPERTIES INTERFACE_LINK_LIBRARIES "qtpcre2;version;winmm;ws2_32") endif() target_link_libraries(${BINARY_NAME}-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES}) set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_DEBIAN_PACKAGE_DEPENDS}" PARENT_SCOPE)
M src/platform/wii/main.csrc/platform/wii/main.c

@@ -194,18 +194,20 @@

free(framebuffer[0]); free(framebuffer[1]); + VIDEO_SetBlack(true); + VIDEO_Configure(vmode); + framebuffer[0] = SYS_AllocateFramebuffer(vmode); framebuffer[1] = SYS_AllocateFramebuffer(vmode); + VIDEO_ClearFrameBuffer(vmode, framebuffer[0], COLOR_BLACK); + VIDEO_ClearFrameBuffer(vmode, framebuffer[1], COLOR_BLACK); - VIDEO_SetBlack(true); - VIDEO_Configure(vmode); VIDEO_SetNextFramebuffer(framebuffer[whichFb]); VIDEO_Flush(); VIDEO_WaitVSync(); if (vmode->viTVMode & VI_NON_INTERLACE) { VIDEO_WaitVSync(); } - VIDEO_SetBlack(false); GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); f32 yscale = GX_GetYScaleFactor(vmode->efbHeight, vmode->xfbHeight);

@@ -238,6 +240,9 @@ }

int main(int argc, char* argv[]) { VIDEO_Init(); + VIDEO_SetBlack(true); + VIDEO_Flush(); + VIDEO_WaitVSync(); PAD_Init(); WPAD_Init(); WPAD_SetDataFormat(0, WPAD_FMT_BTNS_ACC_IR);

@@ -481,6 +486,10 @@ };

mGUIInit(&runner, "wii"); reconfigureScreen(&runner); + // Make sure screen is properly initialized by drawing a blank frame + _drawStart(); + _drawEnd(); + _mapKey(&runner.params.keyMap, GCN1_INPUT, PAD_BUTTON_A, GUI_INPUT_SELECT); _mapKey(&runner.params.keyMap, GCN1_INPUT, PAD_BUTTON_B, GUI_INPUT_BACK); _mapKey(&runner.params.keyMap, GCN1_INPUT, PAD_TRIGGER_Z, GUI_INPUT_CANCEL);

@@ -516,6 +525,9 @@ mGUIRun(&runner, argv[1]);

} else { mGUIRunloop(&runner); } + VIDEO_SetBlack(true); + VIDEO_Flush(); + VIDEO_WaitVSync(); mGUIDeinit(&runner); #ifdef FIXED_ROM_BUFFER

@@ -546,6 +558,8 @@ audioBufferSize = 0;

} static void _drawStart(void) { + VIDEO_SetBlack(false); + u32 level = 0; _CPU_ISR_Disable(level); if (referenceRetraceCount > retraceCount) {

@@ -563,12 +577,11 @@ GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);

} static void _drawEnd(void) { - whichFb = !whichFb; - GX_CopyDisp(framebuffer[whichFb], GX_TRUE); GX_DrawDone(); VIDEO_SetNextFramebuffer(framebuffer[whichFb]); VIDEO_Flush(); + whichFb = !whichFb; u32 level = 0; _CPU_ISR_Disable(level);

@@ -713,6 +726,9 @@ void _gameUnloaded(struct mGUIRunner* runner) {

UNUSED(runner); AUDIO_StopDMA(); frameLimiter = true; + VIDEO_SetBlack(true); + VIDEO_Flush(); + VIDEO_WaitVSync(); } void _gameLoaded(struct mGUIRunner* runner) {