Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2020-06-17 22:26:14 -07:00
commit 5f46f126c1
23 changed files with 7709 additions and 1777 deletions

View File

@ -29,15 +29,21 @@ Emulation fixes:
- GBA BIOS: Improve HLE BIOS timing
- GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320)
- GBA Memory: Improve gamepak prefetch timing
- GBA SIO: Fix Multiplayer busy bit
- GBA SIO: Fix double-unloading active driver
- GBA SIO: Fix copying Normal mode transfer values
- GBA Timers: Fix deserializing count-up timers
- GBA Video: Latch scanline at end of Hblank (fixes mgba.io/i/1319)
- GBA Video: Fix Hblank timing
Other fixes:
- Core: Ensure ELF regions can be written before trying
- Core: Fix ELF loading regression (fixes mgba.io/i/1669)
- Core: Fix crash modifying hash table entry (fixes mgba.io/i/1673)
- GB Video: Fix some cases where SGB border doesn't draw to mutli-buffers
- GBA: Reject incorrectly sized BIOSes
- Debugger: Don't skip undefined instructions when debugger attached
- Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642)
- Qt: Fix OpenGL 2.1 support (fixes mgba.io/i/1678)
Misc:
- FFmpeg: Add looping option for GIF/APNG
- Qt: Renderer can be changed while a game is running

View File

@ -121,7 +121,7 @@ typedef intptr_t ssize_t;
// newlib doesn't support %z properly by default
#define PRIz ""
#elif defined(_WIN64)
#define PRIz "ll"
#define PRIz "I64"
#elif defined(_WIN32)
#define PRIz ""
#else

View File

@ -154,9 +154,9 @@ struct GBAVideoSoftwareRenderer {
int16_t objOffsetY;
uint32_t scanlineDirty[5];
uint16_t nextIo[REG_SOUND1CNT_LO];
uint16_t nextIo[REG_SOUND1CNT_LO >> 1];
struct ScanlineCache {
uint16_t io[REG_SOUND1CNT_LO];
uint16_t io[REG_SOUND1CNT_LO >> 1];
int32_t scale[2][2];
} cache[GBA_VIDEO_VERTICAL_PIXELS];
int nextY;

View File

@ -47,7 +47,7 @@ DECL_BIT(GBASIOMultiplayer, Slave, 2);
DECL_BIT(GBASIOMultiplayer, Ready, 3);
DECL_BITS(GBASIOMultiplayer, Id, 4, 2);
DECL_BIT(GBASIOMultiplayer, Error, 6);
DECL_BIT(GBASIOMultiplayer, Busy, 8);
DECL_BIT(GBASIOMultiplayer, Busy, 7);
DECL_BIT(GBASIOMultiplayer, Irq, 14);
struct GBASIODriverSet {

View File

@ -27,6 +27,10 @@
#include <mgba-util/platform/3ds/3ds-vfs.h>
#endif
#ifdef __HAIKU__
#include <FindDirectory.h>
#endif
#define SECTION_NAME_MAX 128
struct mCoreConfigEnumerateData {
@ -227,6 +231,20 @@ void mCoreConfigDirectory(char* out, size_t outLength) {
UNUSED(portable);
snprintf(out, outLength, "/%s", projectName);
FSUSER_CreateDirectory(sdmcArchive, fsMakePath(PATH_ASCII, out), 0);
#elif defined(__HAIKU__)
getcwd(out, outLength);
strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));
portable = VFileOpen(out, O_RDONLY);
if (portable) {
getcwd(out, outLength);
portable->close(portable);
return;
}
char path[B_PATH_NAME_LENGTH];
find_directory(B_USER_SETTINGS_DIRECTORY, 0, false, path, B_PATH_NAME_LENGTH);
snprintf(out, outLength, "%s/%s", path, binaryName);
mkdir(out, 0755);
#else
getcwd(out, outLength);
strncat(out, PATH_SEP "portable.ini", outLength - strlen(out));

View File

@ -977,7 +977,7 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r
case DEBUGGER_ENTER_BREAKPOINT:
if (info) {
if (info->pointId > 0) {
cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %zi at 0x%08X\n", info->pointId, info->address);
cliDebugger->backend->printf(cliDebugger->backend, "Hit breakpoint %" PRIz "i at 0x%08X\n", info->pointId, info->address);
} else {
cliDebugger->backend->printf(cliDebugger->backend, "Hit unknown breakpoint at 0x%08X\n", info->address);
}
@ -988,9 +988,9 @@ static void _reportEntry(struct mDebugger* debugger, enum mDebuggerEntryReason r
case DEBUGGER_ENTER_WATCHPOINT:
if (info) {
if (info->type.wp.accessType & WATCHPOINT_WRITE) {
cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %zi at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->pointId, info->address, info->type.wp.newValue, info->type.wp.oldValue);
cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %" PRIz "i at 0x%08X: (new value = 0x%08X, old value = 0x%08X)\n", info->pointId, info->address, info->type.wp.newValue, info->type.wp.oldValue);
} else {
cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %zi at 0x%08X: (value = 0x%08X)\n", info->pointId, info->address, info->type.wp.oldValue);
cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint %" PRIz "i at 0x%08X: (value = 0x%08X)\n", info->pointId, info->address, info->type.wp.oldValue);
}
} else {
cliDebugger->backend->printf(cliDebugger->backend, "Hit watchpoint\n");

View File

@ -705,7 +705,9 @@ static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer)
case SGB_PAL_TRN:
case SGB_CHR_TRN:
case SGB_PCT_TRN:
if (softwareRenderer->sgbTransfer > 0 && softwareRenderer->sgbBorders && !renderer->sgbRenderMode) {
case SGB_ATRC_EN:
case SGB_MASK_EN:
if (softwareRenderer->sgbBorders && !renderer->sgbRenderMode) {
// Make sure every buffer sees this if we're multibuffering
_regenerateSGBBorder(softwareRenderer);
}

View File

@ -375,7 +375,6 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c
if (gbacore->renderer.outputBuffer) {
renderer = &gbacore->renderer.d;
}
int fakeBool;
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);
@ -563,7 +562,7 @@ static void _GBACoreReset(struct mCore* core) {
if (gbacore->renderer.outputBuffer) {
renderer = &gbacore->renderer.d;
}
int fakeBool;
int fakeBool ATTRIBUTE_UNUSED;
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) {
mCoreConfigGetIntValue(&core->config, "videoScale", &gbacore->glRenderer.scale);

View File

@ -51,7 +51,7 @@ static void _triggerIRQ(struct mTiming*, void* user, uint32_t cyclesLate);
#ifdef USE_DEBUGGERS
static bool _setSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t* opcode);
static bool _clearSoftwareBreakpoint(struct ARMDebugger*, uint32_t address, enum ExecutionMode mode, uint32_t opcode);
static void _clearSoftwareBreakpoint(struct ARMDebugger*, const struct ARMDebugBreakpoint*);
#endif
#ifdef FIXED_ROM_BUFFER
@ -917,8 +917,7 @@ static bool _setSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t addres
return true;
}
static bool _clearSoftwareBreakpoint(struct ARMDebugger* debugger, uint32_t address, enum ExecutionMode mode, uint32_t opcode) {
GBAClearBreakpoint((struct GBA*) debugger->cpu->master, address, mode, opcode);
return true;
static void _clearSoftwareBreakpoint(struct ARMDebugger* debugger, const struct ARMDebugBreakpoint* breakpoint) {
GBAClearBreakpoint((struct GBA*) debugger->cpu->master, breakpoint->d.address, breakpoint->sw.mode, breakpoint->sw.opcode);
}
#endif

View File

@ -723,8 +723,7 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
GBATimerUpdateRegister(gba, 3, 2);
break;
case REG_KEYINPUT:
{
case REG_KEYINPUT: {
size_t c;
for (c = 0; c < mCoreCallbacksListSize(&gba->coreCallbacks); ++c) {
struct mCoreCallbacks* callbacks = mCoreCallbacksListGetPointer(&gba->coreCallbacks, c);
@ -732,29 +731,28 @@ uint16_t GBAIORead(struct GBA* gba, uint32_t address) {
callbacks->keysRead(callbacks->context);
}
}
}
uint16_t input = 0;
if (gba->keyCallback) {
input = gba->keyCallback->readKeys(gba->keyCallback);
if (gba->keySource) {
*gba->keySource = input;
}
} else if (gba->keySource) {
input = *gba->keySource;
if (!gba->allowOpposingDirections) {
unsigned rl = input & 0x030;
unsigned ud = input & 0x0C0;
input &= 0x30F;
if (rl != 0x030) {
input |= rl;
uint16_t input = 0;
if (gba->keyCallback) {
input = gba->keyCallback->readKeys(gba->keyCallback);
if (gba->keySource) {
*gba->keySource = input;
}
if (ud != 0x0C0) {
input |= ud;
} else if (gba->keySource) {
input = *gba->keySource;
if (!gba->allowOpposingDirections) {
unsigned rl = input & 0x030;
unsigned ud = input & 0x0C0;
input &= 0x30F;
if (rl != 0x030) {
input |= rl;
}
if (ud != 0x0C0) {
input |= ud;
}
}
}
return 0x3FF ^ input;
}
case REG_SIOCNT:
return gba->sio.siocnt;
case REG_RCNT:
@ -964,16 +962,13 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) {
for (i = 0; i < 4; ++i) {
LOAD_16(gba->timers[i].reload, 0, &state->timers[i].reload);
LOAD_32(gba->timers[i].flags, 0, &state->timers[i].flags);
if (i > 0 && GBATimerFlagsIsCountUp(gba->timers[i].flags)) {
// Overwrite invalid values in savestate
gba->timers[i].lastEvent = 0;
} else {
LOAD_32(when, 0, &state->timers[i].lastEvent);
gba->timers[i].lastEvent = when + mTimingCurrentTime(&gba->timing);
}
LOAD_32(when, 0, &state->timers[i].lastEvent);
gba->timers[i].lastEvent = when + mTimingCurrentTime(&gba->timing);
LOAD_32(when, 0, &state->timers[i].nextEvent);
if (GBATimerFlagsIsEnable(gba->timers[i].flags)) {
if ((i < 1 || !GBATimerFlagsIsCountUp(gba->timers[i].flags)) && GBATimerFlagsIsEnable(gba->timers[i].flags)) {
mTimingSchedule(&gba->timing, &gba->timers[i].event, when);
} else {
gba->timers[i].event.when = when + mTimingCurrentTime(&gba->timing);
}
LOAD_16(gba->memory.dma[i].reg, (REG_DMA0CNT_HI + i * 12), state->io);

View File

@ -242,7 +242,8 @@ int GBAVideoSoftwareRendererPreprocessSprite(struct GBAVideoSoftwareRenderer* re
int32_t x = (uint32_t) GBAObjAttributesBGetX(sprite->b) << 23;
x >>= 23;
x += renderer->objOffsetX;
unsigned charBase = GBAObjAttributesCGetTile(sprite->c);
unsigned align = GBAObjAttributesAIs256Color(sprite->a) && !GBARegisterDISPCNTIsObjCharacterMapping(renderer->dispcnt);
unsigned charBase = GBAObjAttributesCGetTile(sprite->c) & ~align;
if (GBAObjAttributesAGetMode(sprite->a) == OBJ_MODE_BITMAP && renderer->bitmapStride) {
charBase = (charBase & (renderer->bitmapStride - 1)) * 0x10 + (charBase & ~(renderer->bitmapStride - 1)) * 0x80;
} else {

View File

@ -75,10 +75,13 @@ void GBASIODeinit(struct GBASIO* sio) {
}
void GBASIOReset(struct GBASIO* sio) {
GBASIODeinit(sio);
if (sio->activeDriver && sio->activeDriver->unload) {
sio->activeDriver->unload(sio->activeDriver);
}
sio->rcnt = RCNT_INITIAL;
sio->siocnt = 0;
sio->mode = -1;
sio->activeDriver = NULL;
_switchMode(sio);
}

View File

@ -279,19 +279,39 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
case TRANSFER_IDLE:
// If the master hasn't initiated a transfer, it can keep going.
node->nextEvent += LOCKSTEP_INCREMENT;
node->d.p->siocnt = GBASIOMultiplayerSetReady(node->d.p->siocnt, attachedMulti == attached);
if (node->mode == SIO_MULTI) {
node->d.p->siocnt = GBASIOMultiplayerSetReady(node->d.p->siocnt, attachedMulti == attached);
}
break;
case TRANSFER_STARTING:
// Start the transfer, but wait for the other GBAs to catch up
node->transferFinished = false;
node->p->multiRecv[0] = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1];
node->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI3 >> 1] = 0xFFFF;
node->p->multiRecv[1] = 0xFFFF;
node->p->multiRecv[2] = 0xFFFF;
node->p->multiRecv[3] = 0xFFFF;
switch (node->mode) {
case SIO_MULTI:
node->p->multiRecv[0] = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1];
node->d.p->p->memory.io[REG_SIOMULTI0 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI1 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI2 >> 1] = 0xFFFF;
node->d.p->p->memory.io[REG_SIOMULTI3 >> 1] = 0xFFFF;
node->p->multiRecv[1] = 0xFFFF;
node->p->multiRecv[2] = 0xFFFF;
node->p->multiRecv[3] = 0xFFFF;
break;
case SIO_NORMAL_8:
node->p->multiRecv[0] = 0xFFFF;
node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA8 >> 1] & 0xFF;
break;
case SIO_NORMAL_32:
node->p->multiRecv[0] = 0xFFFF;
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_LO <- %04x", node->id, node->d.p->p->memory.io[REG_SIODATA32_LO >> 1]);
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, node->d.p->p->memory.io[REG_SIODATA32_HI >> 1]);
node->p->normalRecv[0] = node->d.p->p->memory.io[REG_SIODATA32_LO >> 1];
node->p->normalRecv[0] |= node->d.p->p->memory.io[REG_SIODATA32_HI >> 1] << 16;
break;
default:
node->p->multiRecv[0] = 0xFFFF;
break;
}
needsToWait = true;
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTED);
node->nextEvent += LOCKSTEP_TRANSFER;
@ -456,7 +476,7 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value);
value &= 0xFF8B;
if (!node->id) {
driver->p->siocnt = GBASIONormalFillSi(driver->p->siocnt);
value = GBASIONormalFillSi(value);
}
if (value & 0x0080 && !node->id) {
// Internal shift clock

View File

@ -21,6 +21,9 @@ static const GLchar* const _gles2Header =
"#version 100\n"
"precision mediump float;\n";
static const GLchar* const _gl2Header =
"#version 120\n";
static const GLchar* const _gl32VHeader =
"#version 150 core\n"
"#define attribute in\n"
@ -462,10 +465,12 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f
shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* shaderBuffer[2];
const GLubyte* version = glGetString(GL_VERSION);
if (strncmp((const char*) version, "OpenGL ES ", strlen("OpenGL ES "))) {
shaderBuffer[0] = _gl32VHeader;
} else {
if (strncmp((const char*) version, "OpenGL ES ", strlen("OpenGL ES ")) == 0) {
shaderBuffer[0] = _gles2Header;
} else if (version[0] == '2') {
shaderBuffer[0] = _gl2Header;
} else {
shaderBuffer[0] = _gl32VHeader;
}
if (vs) {
shaderBuffer[1] = vs;
@ -474,7 +479,7 @@ void mGLES2ShaderInit(struct mGLES2Shader* shader, const char* vs, const char* f
}
glShaderSource(shader->vertexShader, 2, shaderBuffer, 0);
if (strncmp((const char*) version, "OpenGL ES ", strlen("OpenGL ES "))) {
if (shaderBuffer[0] == _gl32VHeader) {
shaderBuffer[0] = _gl32FHeader;
}
if (fs) {

View File

@ -683,7 +683,7 @@ void CoreController::scanCard(const QString& path) {
#else
size = image.byteCount();
#endif
m_eReaderData.setRawData(reinterpret_cast<const char*>(bits), image.sizeInBytes());
m_eReaderData.setRawData(reinterpret_cast<const char*>(bits), size);
}
mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* thread) {

View File

@ -21,6 +21,7 @@ MemorySearch::MemorySearch(std::shared_ptr<CoreController> controller, QWidget*
mCoreMemorySearchResultsInit(&m_results, 0);
connect(m_ui.search, &QPushButton::clicked, this, &MemorySearch::search);
connect(m_ui.value, &QLineEdit::returnPressed, this, &MemorySearch::search);
connect(m_ui.searchWithin, &QPushButton::clicked, this, &MemorySearch::searchWithin);
connect(m_ui.refresh, &QPushButton::clicked, this, &MemorySearch::refresh);
connect(m_ui.numHex, &QPushButton::clicked, this, &MemorySearch::refresh);

View File

@ -388,8 +388,8 @@ void InputController::setPreferredGamepad(uint32_t type, int index) {
return;
}
#ifdef BUILD_SDL
char name[34] = {0};
#if SDL_VERSION_ATLEAST(2, 0, 0)
char name[34] = {0};
SDL_JoystickGetGUIDString(SDL_JoystickGetGUID(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, index)->joystick), name, sizeof(name));
#else
const char* name = SDL_JoystickName(SDL_JoystickIndex(SDL_JoystickListGetPointer(&s_sdlEvents.joysticks, index)->joystick));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -246,6 +246,9 @@ void mSDLDetachPlayer(struct mSDLEvents* events, struct mSDLPlayer* player) {
}
--events->playersAttached;
CircleBufferDeinit(&player->rotation.zHistory);
#if SDL_VERSION_ATLEAST(2, 0, 0)
CircleBufferDeinit(&player->rumble.history);
#endif
}
void mSDLPlayerLoadConfig(struct mSDLPlayer* context, const struct Configuration* config) {
@ -349,10 +352,10 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
continue;
}
ssize_t joysticks[MAX_PLAYERS];
size_t i;
ssize_t i;
// Pointers can get invalidated, so we'll need to refresh them
for (i = 0; i < events->playersAttached && i < MAX_PLAYERS; ++i) {
joysticks[i] = events->players[i]->joystick ? SDL_JoystickListIndex(&events->joysticks, events->players[i]->joystick) : SIZE_MAX;
joysticks[i] = events->players[i]->joystick ? (ssize_t) SDL_JoystickListIndex(&events->joysticks, events->players[i]->joystick) : -1;
events->players[i]->joystick = NULL;
}
struct SDL_JoystickCombo* joystick = SDL_JoystickListAppend(&events->joysticks);
@ -363,7 +366,7 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
joystick->haptic = SDL_HapticOpenFromJoystick(joystick->joystick);
#endif
for (i = 0; i < events->playersAttached && i < MAX_PLAYERS; ++i) {
if (joysticks[i] != SIZE_MAX) {
if (joysticks[i] != -1) {
events->players[i]->joystick = SDL_JoystickListGetPointer(&events->joysticks, joysticks[i]);
}
}
@ -394,7 +397,11 @@ void mSDLUpdateJoysticks(struct mSDLEvents* events, const struct Configuration*
continue;
}
events->players[i]->joystick = joystick;
if (config && events->players[i]->bindings && joystickName) {
if (config && events->players[i]->bindings
#if !SDL_VERSION_ATLEAST(2, 0, 0)
&& joystickName
#endif
) {
mInputProfileLoad(events->players[i]->bindings, SDL_BINDING_BUTTON, config, joystickName);
}
break;

View File

@ -44,7 +44,7 @@ static bool _dispatchExiting = false;
int main(int argc, char** argv) {
signal(SIGINT, _fuzzShutdown);
struct FuzzOpts fuzzOpts = { false, 0, 0, 0, 0 };
struct FuzzOpts fuzzOpts = { false, 0, 0, 0 };
struct mSubParser subparser = {
.usage = FUZZ_USAGE,
.parse = _parseFuzzOpts,

View File

@ -52,7 +52,7 @@ OutputBaseFilename={#AppName}-setup-{#CleanVersionString}-win{#WinBits}
UsePreviousLanguage=False
DisableWelcomePage=False
VersionInfoDescription={#AppName} is an open-source Game Boy Advance emulator
VersionInfoCopyright=© 20132019 Jeffrey Pfau
VersionInfoCopyright=© 20132020 Jeffrey Pfau
VersionInfoProductName={#AppName}
VersionInfoVersion={#AppVer}
Compression=lzma2/ultra64