Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2023-05-03 02:43:01 -07:00
commit 407a338a0f
17 changed files with 132 additions and 115 deletions

2
.gitignore vendored
View File

@ -10,10 +10,12 @@
*.a *.a
*.dylib *.dylib
*.dll *.dll
*.lib
*.exe *.exe
*.o *.o
*.so *.so
CMakeCache.txt CMakeCache.txt
CMakeFiles CMakeFiles
CMakeSettings.json CMakeSettings.json
cmake_install.cmake
version.c version.c

14
CHANGES
View File

@ -43,6 +43,13 @@ Misc:
Features: Features:
- New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81
- Debugger: Add range watchpoints - 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: Emulation fixes:
- GB Audio: Fix channels 1/2 not playing when resetting volume (fixes mgba.io/i/2614) - 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) - 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 Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694)
- GB SIO: Further fix bidirectional transfer starting - GB SIO: Further fix bidirectional transfer starting
- GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716) - 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: 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: Other fixes:
- GBA: Fix forceskip BIOS logic for multiboot ROMs (fixes mgba.io/i/2753) - 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) - 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: 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: 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: 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: 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) - 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 - VFS: Fix minizip write returning 0 on success instead of size
Misc: 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: Add category to plist (closes mgba.io/i/2691)
- macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700) - macOS: Fix modern build with libepoxy (fixes mgba.io/i/2700)
- Qt: Keep track of current palette preset name (fixes mgba.io/i/2680) - Qt: Keep track of current palette preset name (fixes mgba.io/i/2680)

View File

@ -6,6 +6,10 @@
#ifndef M_SCRIPT_SOCKET_H #ifndef M_SCRIPT_SOCKET_H
#define M_SCRIPT_SOCKET_H #define M_SCRIPT_SOCKET_H
#include <mgba-util/common.h>
CXX_GUARD_START
enum mSocketErrorCode { enum mSocketErrorCode {
mSCRIPT_SOCKERR_UNKNOWN_ERROR = -1, mSCRIPT_SOCKERR_UNKNOWN_ERROR = -1,
mSCRIPT_SOCKERR_OK = 0, mSCRIPT_SOCKERR_OK = 0,
@ -22,4 +26,6 @@ enum mSocketErrorCode {
mSCRIPT_SOCKERR_UNSUPPORTED, mSCRIPT_SOCKERR_UNSUPPORTED,
}; };
CXX_GUARD_END
#endif #endif

View File

@ -12,6 +12,8 @@
#include <mgba/script/context.h> #include <mgba/script/context.h>
#include <mgba/script/types.h> #include <mgba/script/types.h>
#include "script/test.h"
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
#include <mgba/internal/gba/memory.h> #include <mgba/internal/gba/memory.h>
#define TEST_PLATFORM mPLATFORM_GBA #define TEST_PLATFORM mPLATFORM_GBA
@ -66,22 +68,6 @@ static const uint8_t _fakeGBROM[0x4000] = {
mCoreConfigDeinit(&core->config); \ mCoreConfigDeinit(&core->config); \
core->deinit(core) 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) { static void _mScriptTestLog(struct mLogger* log, int category, enum mLogLevel level, const char* format, va_list args) {
UNUSED(category); UNUSED(category);
struct mScriptTestLogger* logger = (struct mScriptTestLogger*) log; struct mScriptTestLogger* logger = (struct mScriptTestLogger*) log;

View File

@ -499,7 +499,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) {
if (!audio->enable) { if (!audio->enable) {
return; 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); 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) { for (sample = audio->sampleIndex; timestamp >= interval && sample < GB_MAX_SAMPLES; ++sample, timestamp -= interval) {
int16_t sampleLeft = 0; int16_t sampleLeft = 0;
int16_t sampleRight = 0; int16_t sampleRight = 0;
GBAudioRun(audio, sample * interval + audio->lastSample, 0xF); GBAudioRun(audio, sample * interval + audio->lastSample, 0x1F);
GBAudioSamplePSG(audio, &sampleLeft, &sampleRight); GBAudioSamplePSG(audio, &sampleLeft, &sampleRight);
sampleLeft = (sampleLeft * audio->masterVolume * 6) >> 7; sampleLeft = (sampleLeft * audio->masterVolume * 6) >> 7;
sampleRight = (sampleRight * audio->masterVolume * 6) >> 7; sampleRight = (sampleRight * audio->masterVolume * 6) >> 7;

View File

@ -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) { static int16_t _ArcTan2(int32_t x, int32_t y, int32_t* r1, uint32_t* cycles) {
if (!y) { if (!y) {
*cycles = 11;
if (x >= 0) { if (x >= 0) {
return 0; return 0;
} }
return 0x8000; return 0x8000;
} }
if (!x) { if (!x) {
*cycles = 11;
if (y >= 0) { if (y >= 0) {
return 0x4000; return 0x4000;
} }

View File

@ -105,36 +105,36 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_
char line[18] = "XXXXXXXX XXXXXXXX"; char line[18] = "XXXXXXXX XXXXXXXX";
snprintf(line, sizeof(line), "%08X %08X", op1, op2); snprintf(line, sizeof(line), "%08X %08X", op1, op2);
int gsaP, rgsaP, parP, rparP; int nextProbability;
int maxProbability = INT_MIN; int maxProbability = INT_MIN;
switch (set->gsaVersion) { switch (set->gsaVersion) {
case 0: case 0:
// Try to detect GameShark version // Try to detect GameShark version
GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds); GBACheatDecryptGameShark(&o1, &o2, GBACheatGameSharkSeeds);
gsaP = GBACheatGameSharkProbability(o1, o2); nextProbability = GBACheatGameSharkProbability(o1, o2);
o1 = op1; o1 = op1;
o2 = op2; o2 = op2;
if (gsaP > maxProbability) { if (nextProbability > maxProbability) {
maxProbability = gsaP; maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1); GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1);
} }
GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds); GBACheatDecryptGameShark(&o1, &o2, GBACheatProActionReplaySeeds);
parP = GBACheatProActionReplayProbability(o1, o2); nextProbability = GBACheatProActionReplayProbability(o1, o2);
if (parP > maxProbability) { if (nextProbability > maxProbability) {
maxProbability = parP; maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_PARV3); GBACheatSetGameSharkVersion(set, GBA_GS_PARV3);
} }
rgsaP = GBACheatGameSharkProbability(op1, op2); nextProbability = GBACheatGameSharkProbability(op1, op2);
if (rgsaP > maxProbability) { if (nextProbability > maxProbability) {
maxProbability = rgsaP; maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW); GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW);
} }
rparP = GBACheatProActionReplayProbability(op1, op2); nextProbability = GBACheatProActionReplayProbability(op1, op2);
if (rparP > maxProbability) { if (nextProbability > maxProbability) {
maxProbability = rparP; maxProbability = nextProbability;
GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW); GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW);
} }

View File

@ -7,6 +7,7 @@
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QRegularExpression>
#include "ApplicationUpdatePrompt.h" #include "ApplicationUpdatePrompt.h"
#include "ConfigController.h" #include "ConfigController.h"
@ -71,9 +72,10 @@ QStringList ApplicationUpdater::listChannels() {
} }
QString ApplicationUpdater::currentChannel() { QString ApplicationUpdater::currentChannel() {
QLatin1String version(projectVersion); QString version(projectVersion);
QLatin1String branch(gitBranch); QString branch(gitBranch);
if (branch == QLatin1String("heads/") + version || branch == version) { QRegularExpression stable("^(?:(?:refs/)?(?:tags|heads)/)?[0-9]+\\.[0-9]+\\.[0-9]+$");
if (branch.contains(stable) || (branch == "(unknown)" && version.contains(stable))) {
return QLatin1String("stable"); return QLatin1String("stable");
} else { } else {
return QLatin1String("dev"); return QLatin1String("dev");
@ -174,7 +176,8 @@ const char* ApplicationUpdater::platform() {
} }
ApplicationUpdater::UpdateInfo::UpdateInfo(const QString& prefix, const mUpdate* update) ApplicationUpdater::UpdateInfo::UpdateInfo(const QString& prefix, const mUpdate* update)
: size(update->size) : rev(-1)
, size(update->size)
, url(prefix + update->path) , url(prefix + update->path)
{ {
if (update->rev > 0) { if (update->rev > 0) {

View File

@ -673,8 +673,20 @@ void PainterGL::filter(bool filter) {
} }
} }
#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS
#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
#endif
void PainterGL::start() { void PainterGL::start() {
makeCurrent(); 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<QOpenGLFunctions_Baseline>();
fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
#endif
#if defined(BUILD_GLES2) || defined(BUILD_GLES3) #if defined(BUILD_GLES2) || defined(BUILD_GLES3)
if (m_supportsShaders && m_shader.passes) { if (m_supportsShaders && m_shader.passes) {

View File

@ -71,7 +71,7 @@
</property> </property>
<item> <item>
<property name="text"> <property name="text">
<string>Latest stable verison</string> <string>Latest stable version</string>
</property> </property>
</item> </item>
<item> <item>

View File

@ -18,6 +18,7 @@ bool glContextHasBug(OpenGLBug bug) {
QOpenGLFunctions* fn = context->functions(); QOpenGLFunctions* fn = context->functions();
QString vendor(reinterpret_cast<const char*>(fn->glGetString(GL_VENDOR))); QString vendor(reinterpret_cast<const char*>(fn->glGetString(GL_VENDOR)));
QString renderer(reinterpret_cast<const char*>(fn->glGetString(GL_RENDERER))); QString renderer(reinterpret_cast<const char*>(fn->glGetString(GL_RENDERER)));
QString version(reinterpret_cast<const char*>(fn->glGetString(GL_VERSION)));
switch (bug) { switch (bug) {
case OpenGLBug::CROSS_THREAD_FLUSH: case OpenGLBug::CROSS_THREAD_FLUSH:
@ -26,6 +27,10 @@ bool glContextHasBug(OpenGLBug bug) {
#else #else
return vendor == "Intel"; return vendor == "Intel";
#endif #endif
case OpenGLBug::GLTHREAD_BLOCKS_SWAP:
return version.contains(" Mesa ");
default: default:
return false; return false;
} }

View File

@ -8,8 +8,8 @@
namespace QGBA { namespace QGBA {
enum class OpenGLBug { enum class OpenGLBug {
// mgba.io/i/2761 CROSS_THREAD_FLUSH, // mgba.io/i/2761
CROSS_THREAD_FLUSH GLTHREAD_BLOCKS_SWAP, // mgba.io/i/2767
}; };
bool glContextHasBug(OpenGLBug); bool glContextHasBug(OpenGLBug);

View File

@ -308,6 +308,7 @@ void ReportView::generateReport() {
deferredBinaries.append(qMakePair(QString("Save %1").arg(winId), save)); deferredBinaries.append(qMakePair(QString("Save %1").arg(winId), save));
} }
mStateExtdataDeinit(&extdata); mStateExtdataDeinit(&extdata);
vf->close(vf);
} }
} }
} else { } else {

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>885</width> <width>880</width>
<height>797</height> <height>700</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -95,7 +95,7 @@
<item row="1" column="1"> <item row="1" column="1">
<widget class="QStackedWidget" name="stackedWidget"> <widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>9</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="av"> <widget class="QWidget" name="av">
<layout class="QVBoxLayout" name="formLayout"> <layout class="QVBoxLayout" name="formLayout">
@ -2171,45 +2171,37 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="5" column="0" colspan="2">
<widget class="QRadioButton" name="gbColor"> <layout class="QGridLayout" name="gridLayout_2">
<property name="text"> <item row="0" column="1">
<string>Default color palette only</string> <widget class="QRadioButton" name="sgbColor">
</property> <property name="text">
<attribute name="buttonGroup"> <string>SGB color palette if available</string>
<string notr="true">gbColors</string> </property>
</attribute> </widget>
</widget> </item>
</item> <item row="0" column="0">
<item row="6" column="1"> <widget class="QRadioButton" name="gbColor">
<widget class="QRadioButton" name="sgbColor"> <property name="text">
<property name="text"> <string>Default color palette only</string>
<string>SGB color palette if available</string> </property>
</property> </widget>
<attribute name="buttonGroup"> </item>
<string notr="true">gbColors</string> <item row="1" column="0">
</attribute> <widget class="QRadioButton" name="cgbColor">
</widget> <property name="text">
</item> <string>GBC color palette if available</string>
<item row="7" column="1"> </property>
<widget class="QRadioButton" name="cgbColor"> </widget>
<property name="text"> </item>
<string>GBC color palette if available</string> <item row="1" column="1">
</property> <widget class="QRadioButton" name="scgbColor">
<attribute name="buttonGroup"> <property name="text">
<string notr="true">gbColors</string> <string>SGB (preferred) or GBC color palette if available</string>
</attribute> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> </layout>
<widget class="QRadioButton" name="scgbColor">
<property name="text">
<string>SGB (preferred) or GBC color palette if available</string>
</property>
<attribute name="buttonGroup">
<string notr="true">gbColors</string>
</attribute>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>

29
src/script/test.h Normal file
View File

@ -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

View File

@ -8,22 +8,13 @@
#include <mgba/internal/script/lua.h> #include <mgba/internal/script/lua.h>
#include <mgba/script/macros.h> #include <mgba/script/macros.h>
#include "script/test.h"
#define SETUP_LUA \ #define SETUP_LUA \
struct mScriptContext context; \ struct mScriptContext context; \
mScriptContextInit(&context); \ mScriptContextInit(&context); \
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA) 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 { struct Test {
int32_t i; int32_t i;
int32_t (*ifn0)(struct Test*); int32_t (*ifn0)(struct Test*);

View File

@ -10,32 +10,14 @@
#include <mgba/script/macros.h> #include <mgba/script/macros.h>
#include <mgba/script/types.h> #include <mgba/script/types.h>
#include "script/test.h"
#define SETUP_LUA \ #define SETUP_LUA \
struct mScriptContext context; \ struct mScriptContext context; \
mScriptContextInit(&context); \ mScriptContextInit(&context); \
struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \
mScriptContextAttachStdlib(&context) 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) { M_TEST_SUITE_SETUP(mScriptStdlib) {
if (mSCRIPT_ENGINE_LUA->init) { if (mSCRIPT_ENGINE_LUA->init) {
mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA); mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA);