mirror of https://github.com/mgba-emu/mgba.git
Merge branch 'master' (early part) into medusa
This commit is contained in:
commit
407a338a0f
|
@ -10,10 +10,12 @@
|
|||
*.a
|
||||
*.dylib
|
||||
*.dll
|
||||
*.lib
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CMakeSettings.json
|
||||
cmake_install.cmake
|
||||
version.c
|
||||
|
|
14
CHANGES
14
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)
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#ifndef M_SCRIPT_SOCKET_H
|
||||
#define M_SCRIPT_SOCKET_H
|
||||
|
||||
#include <mgba-util/common.h>
|
||||
|
||||
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
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <mgba/script/context.h>
|
||||
#include <mgba/script/types.h>
|
||||
|
||||
#include "script/test.h"
|
||||
|
||||
#ifdef M_CORE_GBA
|
||||
#include <mgba/internal/gba/memory.h>
|
||||
#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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#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) {
|
||||
|
|
|
@ -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<QOpenGLFunctions_Baseline>();
|
||||
fn->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (m_supportsShaders && m_shader.passes) {
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Latest stable verison</string>
|
||||
<string>Latest stable version</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
|
|
|
@ -18,6 +18,7 @@ bool glContextHasBug(OpenGLBug bug) {
|
|||
QOpenGLFunctions* fn = context->functions();
|
||||
QString vendor(reinterpret_cast<const char*>(fn->glGetString(GL_VENDOR)));
|
||||
QString renderer(reinterpret_cast<const char*>(fn->glGetString(GL_RENDERER)));
|
||||
QString version(reinterpret_cast<const char*>(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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -308,6 +308,7 @@ void ReportView::generateReport() {
|
|||
deferredBinaries.append(qMakePair(QString("Save %1").arg(winId), save));
|
||||
}
|
||||
mStateExtdataDeinit(&extdata);
|
||||
vf->close(vf);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>885</width>
|
||||
<height>797</height>
|
||||
<width>880</width>
|
||||
<height>700</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -95,7 +95,7 @@
|
|||
<item row="1" column="1">
|
||||
<widget class="QStackedWidget" name="stackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>9</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="av">
|
||||
<layout class="QVBoxLayout" name="formLayout">
|
||||
|
@ -2171,45 +2171,37 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QRadioButton" name="gbColor">
|
||||
<property name="text">
|
||||
<string>Default color palette only</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">gbColors</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QRadioButton" name="sgbColor">
|
||||
<property name="text">
|
||||
<string>SGB color palette if available</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">gbColors</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QRadioButton" name="cgbColor">
|
||||
<property name="text">
|
||||
<string>GBC color palette if available</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">gbColors</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<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 row="5" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QRadioButton" name="sgbColor">
|
||||
<property name="text">
|
||||
<string>SGB color palette if available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="gbColor">
|
||||
<property name="text">
|
||||
<string>Default color palette only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="cgbColor">
|
||||
<property name="text">
|
||||
<string>GBC color palette if available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QRadioButton" name="scgbColor">
|
||||
<property name="text">
|
||||
<string>SGB (preferred) or GBC color palette if available</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -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
|
|
@ -8,22 +8,13 @@
|
|||
#include <mgba/internal/script/lua.h>
|
||||
#include <mgba/script/macros.h>
|
||||
|
||||
#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*);
|
||||
|
|
|
@ -10,32 +10,14 @@
|
|||
#include <mgba/script/macros.h>
|
||||
#include <mgba/script/types.h>
|
||||
|
||||
#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);
|
||||
|
|
Loading…
Reference in New Issue