diff --git a/.gitignore b/.gitignore index 20c19fc41..0e5d801be 100644 --- a/.gitignore +++ b/.gitignore @@ -10,10 +10,12 @@ *.a *.dylib *.dll +*.lib *.exe *.o *.so CMakeCache.txt CMakeFiles CMakeSettings.json +cmake_install.cmake version.c diff --git a/CHANGES b/CHANGES index 6d5d163c8..1a17ccea3 100644 --- a/CHANGES +++ b/CHANGES @@ -43,6 +43,13 @@ Misc: Features: - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 - Debugger: Add range watchpoints +Emulation fixes: + - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) +Misc: + - GB Serialize: Add missing savestate support for MBC6 and NT (newer) + - GBA: Improve detection of valid ELF ROMs + +0.10.1: (2023-01-10) Emulation fixes: - GB Audio: Fix channels 1/2 not playing when resetting volume (fixes mgba.io/i/2614) - GB Audio: Fix channel 3 volume being changed between samples (fixes mgba.io/i/1896) @@ -52,21 +59,20 @@ Emulation fixes: - GB Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694) - GB SIO: Further fix bidirectional transfer starting - GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716) + - GBA BIOS: Include timing in degenerate ArcTan2 cases (fixes mgba.io/i/2763) - GBA Video: Ignore disabled backgrounds as OBJ blend target (fixes mgba.io/i/2489) - - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) Other fixes: - GBA: Fix forceskip BIOS logic for multiboot ROMs (fixes mgba.io/i/2753) - GBA Cheats: Fix issues detecting unencrypted cheats (fixes mgba.io/i/2724) - Qt: Manually split filename to avoid overzealous splitting (fixes mgba.io/i/2681) - - Qt: Expand criteria for tag branch names (fixes mgba.io/i/2679) - Qt: Fix scanning specific e-Reader dotcodes (fixes mgba.io/i/2693) - Qt: Don't re-enable sync if GBA link modes aren't the same (fixes mgba.io/i/2044) - Qt: Improve handling of multiplayer syncing (fixes mgba.io/i/2720) + - Qt: Fix initializing update revision info + - Qt: Redo stable branch detection heuristic (fixes mgba.io/i/2679) - Res: Fix species name location in Ruby/Sapphire revs 1/2 (fixes mgba.io/i/2685) - VFS: Fix minizip write returning 0 on success instead of size Misc: - - GB Serialize: Add missing savestate support for MBC6 and NT (newer) - - GBA: Improve detection of valid ELF ROMs - macOS: Add category to plist (closes mgba.io/i/2691) - macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700) - Qt: Keep track of current palette preset name (fixes mgba.io/i/2680) diff --git a/include/mgba/internal/script/socket.h b/include/mgba/internal/script/socket.h index 014a765bb..98953fb80 100644 --- a/include/mgba/internal/script/socket.h +++ b/include/mgba/internal/script/socket.h @@ -6,6 +6,10 @@ #ifndef M_SCRIPT_SOCKET_H #define M_SCRIPT_SOCKET_H +#include + +CXX_GUARD_START + enum mSocketErrorCode { mSCRIPT_SOCKERR_UNKNOWN_ERROR = -1, mSCRIPT_SOCKERR_OK = 0, @@ -22,4 +26,6 @@ enum mSocketErrorCode { mSCRIPT_SOCKERR_UNSUPPORTED, }; +CXX_GUARD_END + #endif diff --git a/src/core/test/scripting.c b/src/core/test/scripting.c index ddcb448c5..2e26b096f 100644 --- a/src/core/test/scripting.c +++ b/src/core/test/scripting.c @@ -12,6 +12,8 @@ #include #include +#include "script/test.h" + #ifdef M_CORE_GBA #include #define TEST_PLATFORM mPLATFORM_GBA @@ -66,22 +68,6 @@ static const uint8_t _fakeGBROM[0x4000] = { mCoreConfigDeinit(&core->config); \ core->deinit(core) -#define LOAD_PROGRAM(PROG) \ - do { \ - struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \ - assert_true(lua->load(lua, NULL, vf)); \ - vf->close(vf); \ - } while(0) - -#define TEST_VALUE(TYPE, NAME, VALUE) \ - do { \ - struct mScriptValue val = mSCRIPT_MAKE(TYPE, VALUE); \ - struct mScriptValue* global = lua->getGlobal(lua, NAME); \ - assert_non_null(global); \ - assert_true(global->type->equal(global, &val)); \ - mScriptValueDeref(global); \ - } while(0) - static void _mScriptTestLog(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) { UNUSED(category); struct mScriptTestLogger* logger = (struct mScriptTestLogger*) log; diff --git a/src/gb/audio.c b/src/gb/audio.c index 8bce46e07..d2d6a9260 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -499,7 +499,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { if (!audio->enable) { return; } - if (audio->p && channels != 0xF && timestamp - audio->lastSample > (int) (SAMPLE_INTERVAL * audio->timingFactor)) { + if (audio->p && channels != 0x1F && timestamp - audio->lastSample > (int) (SAMPLE_INTERVAL * audio->timingFactor)) { GBAudioSample(audio, timestamp); } @@ -779,7 +779,7 @@ void GBAudioSample(struct GBAudio* audio, int32_t timestamp) { for (sample = audio->sampleIndex; timestamp >= interval && sample < GB_MAX_SAMPLES; ++sample, timestamp -= interval) { int16_t sampleLeft = 0; int16_t sampleRight = 0; - GBAudioRun(audio, sample * interval + audio->lastSample, 0xF); + GBAudioRun(audio, sample * interval + audio->lastSample, 0x1F); GBAudioSamplePSG(audio, &sampleLeft, &sampleRight); sampleLeft = (sampleLeft * audio->masterVolume * 6) >> 7; sampleRight = (sampleRight * audio->masterVolume * 6) >> 7; diff --git a/src/gba/bios.c b/src/gba/bios.c index d824830aa..1d0c0dd10 100644 --- a/src/gba/bios.c +++ b/src/gba/bios.c @@ -336,12 +336,14 @@ static int16_t _ArcTan(int32_t i, int32_t* r1, int32_t* r3, uint32_t* cycles) { static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, uint32_t* cycles) { if (!y) { + *cycles = 11; if (x >= 0) { return 0; } return 0x8000; } if (!x) { + *cycles = 11; if (y >= 0) { return 0x4000; } diff --git a/src/gba/cheats.c b/src/gba/cheats.c index 08848077b..04082d48a 100644 --- a/src/gba/cheats.c +++ b/src/gba/cheats.c @@ -105,36 +105,36 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_ char line[18] = "XXXXXXXX XXXXXXXX"; snprintf(line, sizeof(line), "%08X %08X", op1, op2); - int gsaP, rgsaP, parP, rparP; + int nextProbability; int maxProbability = INT_MIN; switch (set->gsaVersion) { case 0: // Try to detect GameShark version GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds); - gsaP = GBACheatGameSharkProbability(o1, o2); + nextProbability = GBACheatGameSharkProbability(o1, o2); o1 = op1; o2 = op2; - if (gsaP > maxProbability) { - maxProbability = gsaP; + if (nextProbability > maxProbability) { + maxProbability = nextProbability; GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1); } GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds); - parP = GBACheatProActionReplayProbability(o1, o2); - if (parP > maxProbability) { - maxProbability = parP; + nextProbability = GBACheatProActionReplayProbability(o1, o2); + if (nextProbability > maxProbability) { + maxProbability = nextProbability; GBACheatSetGameSharkVersion(set, GBA_GS_PARV3); } - rgsaP = GBACheatGameSharkProbability(op1, op2); - if (rgsaP > maxProbability) { - maxProbability = rgsaP; + nextProbability = GBACheatGameSharkProbability(op1, op2); + if (nextProbability > maxProbability) { + maxProbability = nextProbability; GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW); } - rparP = GBACheatProActionReplayProbability(op1, op2); - if (rparP > maxProbability) { - maxProbability = rparP; + nextProbability = GBACheatProActionReplayProbability(op1, op2); + if (nextProbability > maxProbability) { + maxProbability = nextProbability; GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW); } diff --git a/src/platform/qt/ApplicationUpdater.cpp b/src/platform/qt/ApplicationUpdater.cpp index a0efca23d..21def050c 100644 --- a/src/platform/qt/ApplicationUpdater.cpp +++ b/src/platform/qt/ApplicationUpdater.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "ApplicationUpdatePrompt.h" #include "ConfigController.h" @@ -71,9 +72,10 @@ QStringList ApplicationUpdater::listChannels() { } QString ApplicationUpdater::currentChannel() { - QLatin1String version(projectVersion); - QLatin1String branch(gitBranch); - if (branch == QLatin1String("heads/") + version || branch == version) { + QString version(projectVersion); + QString branch(gitBranch); + QRegularExpression stable("^(?:(?:refs/)?(?:tags|heads)/)?[0-9]+\\.[0-9]+\\.[0-9]+$"); + if (branch.contains(stable) || (branch == "(unknown)" && version.contains(stable))) { return QLatin1String("stable"); } else { return QLatin1String("dev"); @@ -174,7 +176,8 @@ const char* ApplicationUpdater::platform() { } ApplicationUpdater::UpdateInfo::UpdateInfo(const QString& prefix, const mUpdate* update) - : size(update->size) + : rev(-1) + , size(update->size) , url(prefix + update->path) { if (update->rev > 0) { diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 0493045a4..f873f7c39 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -673,8 +673,20 @@ void PainterGL::filter(bool filter) { } } +#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#endif + void PainterGL::start() { makeCurrent(); +#if defined(BUILD_GLES3) && !defined(Q_OS_MAC) + if (glContextHasBug(OpenGLBug::GLTHREAD_BLOCKS_SWAP)) { + // Suggested on Discord as a way to strongly hint that glthread should be disabled + // See https://gitlab.freedesktop.org/mesa/mesa/-/issues/8035 + QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); + fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + } +#endif #if defined(BUILD_GLES2) || defined(BUILD_GLES3) if (m_supportsShaders && m_shader.passes) { diff --git a/src/platform/qt/ForwarderView.ui b/src/platform/qt/ForwarderView.ui index 1c72e3caa..f83facf1c 100644 --- a/src/platform/qt/ForwarderView.ui +++ b/src/platform/qt/ForwarderView.ui @@ -71,7 +71,7 @@ - Latest stable verison + Latest stable version diff --git a/src/platform/qt/OpenGLBug.cpp b/src/platform/qt/OpenGLBug.cpp index e00310c56..df007c1cb 100644 --- a/src/platform/qt/OpenGLBug.cpp +++ b/src/platform/qt/OpenGLBug.cpp @@ -18,6 +18,7 @@ bool glContextHasBug(OpenGLBug bug) { QOpenGLFunctions* fn = context->functions(); QString vendor(reinterpret_cast(fn->glGetString(GL_VENDOR))); QString renderer(reinterpret_cast(fn->glGetString(GL_RENDERER))); + QString version(reinterpret_cast(fn->glGetString(GL_VERSION))); switch (bug) { case OpenGLBug::CROSS_THREAD_FLUSH: @@ -26,6 +27,10 @@ bool glContextHasBug(OpenGLBug bug) { #else return vendor == "Intel"; #endif + + case OpenGLBug::GLTHREAD_BLOCKS_SWAP: + return version.contains(" Mesa "); + default: return false; } diff --git a/src/platform/qt/OpenGLBug.h b/src/platform/qt/OpenGLBug.h index fda0ed555..5b5bc7736 100644 --- a/src/platform/qt/OpenGLBug.h +++ b/src/platform/qt/OpenGLBug.h @@ -8,8 +8,8 @@ namespace QGBA { enum class OpenGLBug { - // mgba.io/i/2761 - CROSS_THREAD_FLUSH + CROSS_THREAD_FLUSH, // mgba.io/i/2761 + GLTHREAD_BLOCKS_SWAP, // mgba.io/i/2767 }; bool glContextHasBug(OpenGLBug); diff --git a/src/platform/qt/ReportView.cpp b/src/platform/qt/ReportView.cpp index 61a7a2cd1..494f45a64 100644 --- a/src/platform/qt/ReportView.cpp +++ b/src/platform/qt/ReportView.cpp @@ -308,6 +308,7 @@ void ReportView::generateReport() { deferredBinaries.append(qMakePair(QString("Save %1").arg(winId), save)); } mStateExtdataDeinit(&extdata); + vf->close(vf); } } } else { diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index 6ac93f494..b282d874f 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -6,8 +6,8 @@ 0 0 - 885 - 797 + 880 + 700 @@ -95,7 +95,7 @@ - 9 + 1 @@ -2171,45 +2171,37 @@ - - - - Default color palette only - - - gbColors - - - - - - - SGB color palette if available - - - gbColors - - - - - - - GBC color palette if available - - - gbColors - - - - - - - SGB (preferred) or GBC color palette if available - - - gbColors - - + + + + + + SGB color palette if available + + + + + + + Default color palette only + + + + + + + GBC color palette if available + + + + + + + SGB (preferred) or GBC color palette if available + + + + diff --git a/src/script/test.h b/src/script/test.h new file mode 100644 index 000000000..f526bce30 --- /dev/null +++ b/src/script/test.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SCRIPT_TEST_H +#define M_SCRIPT_TEST_H + +#define LOAD_PROGRAM(PROG) \ + do { \ + struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \ + assert_true(lua->load(lua, NULL, vf)); \ + vf->close(vf); \ + } while(0) + +#define TEST_VALUE(TYPE, NAME, VALUE) \ + do { \ + struct mScriptValue val = mSCRIPT_MAKE(TYPE, VALUE); \ + struct mScriptValue* global = lua->getGlobal(lua, NAME); \ + assert_non_null(global); \ + assert_true(global->type->equal(global, &val)); \ + mScriptValueDeref(global); \ + } while(0) + +#define TEST_PROGRAM(PROG) \ + LOAD_PROGRAM(PROG); \ + assert_true(lua->run(lua)); \ + +#endif diff --git a/src/script/test/lua.c b/src/script/test/lua.c index 2cc7fcbff..73954e91e 100644 --- a/src/script/test/lua.c +++ b/src/script/test/lua.c @@ -8,22 +8,13 @@ #include #include +#include "script/test.h" + #define SETUP_LUA \ struct mScriptContext context; \ mScriptContextInit(&context); \ struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA) -#define LOAD_PROGRAM(PROG) \ - do { \ - struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \ - assert_true(lua->load(lua, NULL, vf)); \ - vf->close(vf); \ - } while(0) - -#define TEST_PROGRAM(PROG) \ - LOAD_PROGRAM(PROG); \ - assert_true(lua->run(lua)); \ - struct Test { int32_t i; int32_t (*ifn0)(struct Test*); diff --git a/src/script/test/stdlib.c b/src/script/test/stdlib.c index d4c57605b..63ddda4fc 100644 --- a/src/script/test/stdlib.c +++ b/src/script/test/stdlib.c @@ -10,32 +10,14 @@ #include #include +#include "script/test.h" + #define SETUP_LUA \ struct mScriptContext context; \ mScriptContextInit(&context); \ struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ mScriptContextAttachStdlib(&context) -#define LOAD_PROGRAM(PROG) \ - do { \ - struct VFile* vf = VFileFromConstMemory(PROG, strlen(PROG)); \ - assert_true(lua->load(lua, NULL, vf)); \ - vf->close(vf); \ - } while(0) - -#define TEST_PROGRAM(PROG) \ - LOAD_PROGRAM(PROG); \ - assert_true(lua->run(lua)); \ - -#define TEST_VALUE(TYPE, NAME, VALUE) \ - do { \ - struct mScriptValue val = mSCRIPT_MAKE(TYPE, VALUE); \ - struct mScriptValue* global = lua->getGlobal(lua, NAME); \ - assert_non_null(global); \ - assert_true(global->type->equal(global, &val)); \ - mScriptValueDeref(global); \ - } while(0) - M_TEST_SUITE_SETUP(mScriptStdlib) { if (mSCRIPT_ENGINE_LUA->init) { mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);