diff --git a/CHANGES b/CHANGES index 8d336824e..9f6722e56 100644 --- a/CHANGES +++ b/CHANGES @@ -73,6 +73,9 @@ Bugfixes: - 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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b6f3d35f..16da73e58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.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 @@ if(NOT QUIET) 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}") diff --git a/README.md b/README.md index d91a4fa6f..651a612b9 100644 --- a/README.md +++ b/README.md @@ -154,11 +154,11 @@ To build on Windows for development, using MSYS2 is recommended. Follow the inst 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: diff --git a/README_DE.md b/README_DE.md index f5b7affe3..b366af757 100644 --- a/README_DE.md +++ b/README_DE.md @@ -136,11 +136,11 @@ Um mGBA auf Windows zu kompilieren, wird MSYS2 empfohlen. Befolge die Installati 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: diff --git a/include/mgba/internal/gb/video.h b/include/mgba/internal/gb/video.h index 90cfd7bbb..7fd731be6 100644 --- a/include/mgba/internal/gb/video.h +++ b/include/mgba/internal/gb/video.h @@ -26,7 +26,6 @@ enum { GB_VIDEO_HORIZONTAL_LENGTH = 456, - GB_VIDEO_MODE_1_LENGTH = 65664, GB_VIDEO_TOTAL_LENGTH = 70224, GB_BASE_MAP = 0x1800, diff --git a/src/gb/memory.c b/src/gb/memory.c index 1dae0b988..089558011 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -16,31 +16,33 @@ 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) { diff --git a/src/gb/renderers/software.c b/src/gb/renderers/software.c index 5214b3d7f..93c67b871 100644 --- a/src/gb/renderers/software.c +++ b/src/gb/renderers/software.c @@ -75,25 +75,25 @@ static void _regenerateSGBBorder(struct GBVideoSoftwareRenderer* renderer) { 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]; + } + } } } } diff --git a/src/gba/timer.c b/src/gba/timer.c index c8b5e77b9..8e8f4aaa2 100644 --- a/src/gba/timer.c +++ b/src/gba/timer.c @@ -50,7 +50,7 @@ void GBATimerUpdate(struct mTiming* timing, struct GBATimer* timer, uint16_t* io 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 @@ void GBATimerUpdateRegisterInternal(struct GBATimer* timer, struct mTiming* timi 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); } } diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 046e64180..182644431 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -63,6 +63,27 @@ static void _reloadSettings(void) { }; 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 @@ void retro_set_environment(retro_environment_t env) { 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 @@ void retro_run(void) { 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 @@ bool retro_load_game(const struct retro_game_info* game) { 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,22 +458,53 @@ bool retro_load_game(const struct retro_game_info* game) { 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); diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 0dda9e538..8b6223c18 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -173,7 +173,7 @@ if(Qt5Multimedia_FOUND) 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 @@ if(BUILD_GL OR BUILD_GLES2) 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) diff --git a/src/platform/wii/main.c b/src/platform/wii/main.c index 5d8d11300..6a359a637 100644 --- a/src/platform/wii/main.c +++ b/src/platform/wii/main.c @@ -194,18 +194,20 @@ static void reconfigureScreen(struct mGUIRunner* runner) { free(framebuffer[0]); free(framebuffer[1]); - framebuffer[0] = SYS_AllocateFramebuffer(vmode); - framebuffer[1] = SYS_AllocateFramebuffer(vmode); - 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_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 @@ static void reconfigureScreen(struct mGUIRunner* runner) { 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 @@ int main(int argc, char* argv[]) { 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 @@ int main(int argc, char* argv[]) { } else { mGUIRunloop(&runner); } + VIDEO_SetBlack(true); + VIDEO_Flush(); + VIDEO_WaitVSync(); mGUIDeinit(&runner); #ifdef FIXED_ROM_BUFFER @@ -546,6 +558,8 @@ static void _audioDMA(void) { } static void _drawStart(void) { + VIDEO_SetBlack(false); + u32 level = 0; _CPU_ISR_Disable(level); if (referenceRetraceCount > retraceCount) { @@ -563,12 +577,11 @@ static void _drawStart(void) { } 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) {