Merge branch 'master' (early part) into medusa

This commit is contained in:
Vicki Pfau 2019-09-28 15:03:36 -07:00
commit 2f79211cd5
49 changed files with 1745 additions and 1421 deletions

View File

@ -42,6 +42,7 @@ Emulation fixes:
- GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340) - GB Timer: Fix timing adjustments when writing to TAC (fixes mgba.io/i/1340)
- GBA Memory: Fix writing to OBJ memory in modes 3 and 5 - GBA Memory: Fix writing to OBJ memory in modes 3 and 5
- GBA: Fix RTC on non-standard sized ROMs (fixes mgba.io/i/1400) - GBA: Fix RTC on non-standard sized ROMs (fixes mgba.io/i/1400)
- GBA Memory: Prevent writing to mirrored BG VRAM (fixes mgba.io/i/743)
Other fixes: Other fixes:
- Qt: More app metadata fixes - Qt: More app metadata fixes
- Qt: Fix load recent from archive (fixes mgba.io/i/1325) - Qt: Fix load recent from archive (fixes mgba.io/i/1325)
@ -57,6 +58,8 @@ Other fixes:
- Qt: Fix adjusting magnification in tile viewer when not fitting to window - Qt: Fix adjusting magnification in tile viewer when not fitting to window
- FFmpeg: Improve initialization reliability and cleanup - FFmpeg: Improve initialization reliability and cleanup
- Wii: Fix aspect ratio (fixes mgba.io/i/500) - Wii: Fix aspect ratio (fixes mgba.io/i/500)
- Qt: Fix some Qt display driver race conditions
- FFmpeg: Fix audio conversion producing gaps
Misc: Misc:
- GBA Savedata: EEPROM performance fixes - GBA Savedata: EEPROM performance fixes
- GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash - GBA Savedata: Automatically map 1Mbit Flash files as 1Mbit Flash
@ -74,6 +77,8 @@ Misc:
- Debugger: Make tracing compatible with breakpoints/watchpoints - Debugger: Make tracing compatible with breakpoints/watchpoints
- Debugger: Print breakpoint/watchpoint number when inserting - Debugger: Print breakpoint/watchpoint number when inserting
- Qt: Open a message box for Qt frontend errors - Qt: Open a message box for Qt frontend errors
- GBA Video: Clean up dead code in sprite rendering loop
- FFmpeg: Support audio-only recording
0.7.1: (2019-02-24) 0.7.1: (2019-02-24)
Bugfixes: Bugfixes:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

View File

@ -81,17 +81,33 @@ typedef intptr_t ssize_t;
#define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE) #define ATOMIC_STORE(DST, SRC) __atomic_store_n(&DST, SRC, __ATOMIC_RELEASE)
#define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE) #define ATOMIC_LOAD(DST, SRC) DST = __atomic_load_n(&SRC, __ATOMIC_ACQUIRE)
#define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_ADD(DST, OP) __atomic_add_fetch(&DST, OP, __ATOMIC_RELEASE)
#define ATOMIC_SUB(DST, OP) __atomic_sub_fetch(&DST, OP, __ATOMIC_RELEASE)
#define ATOMIC_OR(DST, OP) __atomic_or_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_OR(DST, OP) __atomic_or_fetch(&DST, OP, __ATOMIC_RELEASE)
#define ATOMIC_AND(DST, OP) __atomic_and_fetch(&DST, OP, __ATOMIC_RELEASE) #define ATOMIC_AND(DST, OP) __atomic_and_fetch(&DST, OP, __ATOMIC_RELEASE)
#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true,__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE) #define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) __atomic_compare_exchange_n(&DST, &EXPECTED, SRC, true,__ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE)
#define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC)
#define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC)
#elif defined _MSC_VER
#define ATOMIC_STORE(DST, SRC) InterlockedExchange(&DST, SRC)
#define ATOMIC_LOAD(DST, SRC) DST = InterlockedOrAcquire(&SRC, 0)
#define ATOMIC_ADD(DST, OP) InterlockedAddRelease(&DST, OP)
#define ATOMIC_SUB(DST, OP) InterlockedAddRelease(&DST, -OP)
#define ATOMIC_OR(DST, OP) InterlockedOrRelease(&DST, OP)
#define ATOMIC_AND(DST, OP) InterlockedAndRelease(&DST, OP)
#define ATOMIC_CMPXCHG(DST, EXPECTED, SRC) (InterlockedCompareExchange(&DST, SRC, EXPECTED) == EXPECTED)
#define ATOMIC_STORE_PTR(DST, SRC) InterlockedExchangePointer(DST, SRC)
#define ATOMIC_LOAD_PTR(DST, SRC) DST = InterlockedCompareExchangePointer(SRC, 0, 0)
#else #else
// TODO // TODO
#define ATOMIC_STORE(DST, SRC) DST = SRC #define ATOMIC_STORE(DST, SRC) DST = SRC
#define ATOMIC_LOAD(DST, SRC) DST = SRC #define ATOMIC_LOAD(DST, SRC) DST = SRC
#define ATOMIC_ADD(DST, OP) DST += OP #define ATOMIC_ADD(DST, OP) DST += OP
#define ATOMIC_SUB(DST, OP) DST -= OP
#define ATOMIC_OR(DST, OP) DST |= OP #define ATOMIC_OR(DST, OP) DST |= OP
#define ATOMIC_AND(DST, OP) DST &= OP #define ATOMIC_AND(DST, OP) DST &= OP
#define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false) #define ATOMIC_CMPXCHG(DST, EXPECTED, OP) ((DST == EXPECTED) ? ((DST = OP), true) : false)
#define ATOMIC_STORE_PTR(DST, SRC) ATOMIC_STORE(DST, SRC)
#define ATOMIC_LOAD_PTR(DST, SRC) ATOMIC_LOAD(DST, SRC)
#endif #endif
#if defined(_3DS) || defined(GEKKO) || defined(PSP2) #if defined(_3DS) || defined(GEKKO) || defined(PSP2)

View File

@ -23,10 +23,14 @@ struct mLockstep {
enum mLockstepPhase transferActive; enum mLockstepPhase transferActive;
int32_t transferCycles; int32_t transferCycles;
void (*lock)(struct mLockstep*);
void (*unlock)(struct mLockstep*);
bool (*signal)(struct mLockstep*, unsigned mask); bool (*signal)(struct mLockstep*, unsigned mask);
bool (*wait)(struct mLockstep*, unsigned mask); bool (*wait)(struct mLockstep*, unsigned mask);
void (*addCycles)(struct mLockstep*, int id, int32_t cycles); void (*addCycles)(struct mLockstep*, int id, int32_t cycles);
int32_t (*useCycles)(struct mLockstep*, int id, int32_t cycles); int32_t (*useCycles)(struct mLockstep*, int id, int32_t cycles);
int32_t (*unusedCycles)(struct mLockstep*, int id);
void (*unload)(struct mLockstep*, int id); void (*unload)(struct mLockstep*, int id);
void* context; void* context;
#ifndef NDEBUG #ifndef NDEBUG
@ -35,6 +39,19 @@ struct mLockstep {
}; };
void mLockstepInit(struct mLockstep*); void mLockstepInit(struct mLockstep*);
void mLockstepDeinit(struct mLockstep*);
static inline void mLockstepLock(struct mLockstep* lockstep) {
if (lockstep->lock) {
lockstep->lock(lockstep);
}
}
static inline void mLockstepUnlock(struct mLockstep* lockstep) {
if (lockstep->unlock) {
lockstep->unlock(lockstep);
}
}
CXX_GUARD_END CXX_GUARD_END

View File

@ -126,7 +126,7 @@ struct ARMMemory {
uint32_t (*storeMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction, uint32_t (*storeMultiple)(struct ARMCore*, uint32_t baseAddress, int mask, enum LSMDirection direction,
int* cycleCounter); int* cycleCounter);
uint32_t* activeRegion; const uint32_t* activeRegion;
uint32_t activeMask; uint32_t activeMask;
uint32_t activeSeqCycles32; uint32_t activeSeqCycles32;
uint32_t activeSeqCycles16; uint32_t activeSeqCycles16;

View File

@ -56,7 +56,7 @@ struct LR35902Memory {
int (*currentSegment)(struct LR35902Core*, uint16_t address); int (*currentSegment)(struct LR35902Core*, uint16_t address);
uint8_t* activeRegion; const uint8_t* activeRegion;
uint16_t activeMask; uint16_t activeMask;
uint16_t activeRegionEnd; uint16_t activeRegionEnd;
void (*setActiveRegion)(struct LR35902Core*, uint16_t address); void (*setActiveRegion)(struct LR35902Core*, uint16_t address);

View File

@ -230,7 +230,7 @@ bool mCheatSaveFile(struct mCheatDevice* device, struct VFile* vf) {
char directive[64]; char directive[64];
ssize_t len = snprintf(directive, sizeof(directive) - 1, "!%s\n", *StringListGetPointer(&directives, d)); ssize_t len = snprintf(directive, sizeof(directive) - 1, "!%s\n", *StringListGetPointer(&directives, d));
if (len > 1) { if (len > 1) {
vf->write(vf, directive, (size_t) len > sizeof(directive) ? sizeof(directive) : len); vf->write(vf, directive, (size_t) len > sizeof(directive) ? sizeof(directive) : (size_t) len);
} }
} }

View File

@ -230,13 +230,13 @@ bool mCoreLoadState(struct mCore* core, int slot, int flags) {
} }
struct VFile* mCoreGetState(struct mCore* core, int slot, bool write) { struct VFile* mCoreGetState(struct mCore* core, int slot, bool write) {
char name[PATH_MAX]; char name[PATH_MAX + 14]; // Quash warning
snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot); snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot);
return core->dirs.state->openFile(core->dirs.state, name, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY); return core->dirs.state->openFile(core->dirs.state, name, write ? (O_CREAT | O_TRUNC | O_RDWR) : O_RDONLY);
} }
void mCoreDeleteState(struct mCore* core, int slot) { void mCoreDeleteState(struct mCore* core, int slot) {
char name[PATH_MAX]; char name[PATH_MAX + 14]; // Quash warning
snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot); snprintf(name, sizeof(name), "%s.ss%i", core->dirs.baseName, slot);
core->dirs.state->deleteFile(core->dirs.state, name); core->dirs.state->deleteFile(core->dirs.state, name);
} }

View File

@ -341,7 +341,7 @@ static void _mLibraryDeleteEntry(struct mLibrary* library, struct mLibraryEntry*
} }
void mLibraryClear(struct mLibrary* library) { void mLibraryClear(struct mLibrary* library) {
int result = sqlite3_exec(library->db, sqlite3_exec(library->db,
" BEGIN TRANSACTION;" " BEGIN TRANSACTION;"
"\n DELETE FROM roots;" "\n DELETE FROM roots;"
"\n DELETE FROM roms;" "\n DELETE FROM roms;"

View File

@ -11,6 +11,12 @@ void mLockstepInit(struct mLockstep* lockstep) {
#ifndef NDEBUG #ifndef NDEBUG
lockstep->transferId = 0; lockstep->transferId = 0;
#endif #endif
lockstep->lock = NULL;
lockstep->unlock = NULL;
}
void mLockstepDeinit(struct mLockstep* lockstep) {
UNUSED(lockstep);
} }
// TODO: Migrate nodes // TODO: Migrate nodes

View File

@ -14,6 +14,7 @@ void mTimingInit(struct mTiming* timing, int32_t* relativeCycles, int32_t* nextE
} }
void mTimingDeinit(struct mTiming* timing) { void mTimingDeinit(struct mTiming* timing) {
UNUSED(timing);
} }
void mTimingClear(struct mTiming* timing) { void mTimingClear(struct mTiming* timing) {

View File

@ -263,6 +263,8 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
free((void*) dbType); free((void*) dbType);
free((void*) dbVersion); free((void*) dbVersion);
sqlite3_finalize(gamedbTable);
sqlite3_finalize(gamedbDrop);
sqlite3_finalize(gameTable); sqlite3_finalize(gameTable);
sqlite3_finalize(romTable); sqlite3_finalize(romTable);
@ -275,6 +277,7 @@ bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf) {
} }
void NoIntroDBDestroy(struct NoIntroDB* db) { void NoIntroDBDestroy(struct NoIntroDB* db) {
sqlite3_finalize(db->crc32);
sqlite3_close(db->db); sqlite3_close(db->db);
free(db); free(db);
} }

View File

@ -508,7 +508,7 @@ static void GBVideoSoftwareRendererDrawRange(struct GBVideoRenderer* renderer, i
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy == y && wx <= endX) { if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && wy == y && wx <= endX) {
softwareRenderer->hasWindow = true; softwareRenderer->hasWindow = true;
} }
if (softwareRenderer->hasWindow && wx <= endX) { if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->hasWindow && wx <= endX) {
if (wx > 0 && !softwareRenderer->d.disableBG) { if (wx > 0 && !softwareRenderer->d.disableBG) {
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy); GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, startX, wx, softwareRenderer->scx - softwareRenderer->offsetScx, softwareRenderer->scy + y - softwareRenderer->offsetScy);
} }

View File

@ -17,7 +17,6 @@ static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t valu
static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate); static void _GBSIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate);
void GBSIOLockstepInit(struct GBSIOLockstep* lockstep) { void GBSIOLockstepInit(struct GBSIOLockstep* lockstep) {
mLockstepInit(&lockstep->d);
lockstep->players[0] = NULL; lockstep->players[0] = NULL;
lockstep->players[1] = NULL; lockstep->players[1] = NULL;
lockstep->pendingSB[0] = 0xFF; lockstep->pendingSB[0] = 0xFF;
@ -236,6 +235,8 @@ static uint8_t GBSIOLockstepNodeWriteSC(struct GBSIODriver* driver, uint8_t valu
mTimingDeschedule(&driver->p->p->timing, &driver->p->event); mTimingDeschedule(&driver->p->p->timing, &driver->p->event);
mTimingDeschedule(&driver->p->p->timing, &node->event); mTimingDeschedule(&driver->p->p->timing, &node->event);
mTimingSchedule(&driver->p->p->timing, &node->event, 0); mTimingSchedule(&driver->p->p->timing, &node->event, 0);
} else {
mLOG(GB_SIO, FATAL, "GBSIOLockstepNodeWriteSC() failed to write to masterClaimed\n");
} }
} }
return value; return value;

View File

@ -94,6 +94,7 @@ void _battlechipTransfer(struct GBASIOBattlechipGate* gate) {
} }
void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cyclesLate) { void _battlechipTransferEvent(struct mTiming* timing, void* user, uint32_t cyclesLate) {
UNUSED(timing);
struct GBASIOBattlechipGate* gate = user; struct GBASIOBattlechipGate* gate = user;
if (gate->d.p->mode == SIO_NORMAL_32) { if (gate->d.p->mode == SIO_NORMAL_32) {

View File

@ -390,11 +390,15 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) {
wait += waitstatesRegion[REGION_PALETTE_RAM]; wait += waitstatesRegion[REGION_PALETTE_RAM];
#define LOAD_VRAM \ #define LOAD_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \ if ((address & 0x0001FFFF) >= SIZE_VRAM) { \
LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \ if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \
} else { \ mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load32: 0x%08X", address); \
LOAD_32(value, address & 0x00017FFC, gba->video.vram); \ value = 0; \
break; \
} \
address &= 0x00017FFC; \
} \ } \
LOAD_32(value, address & 0x0001FFFC, gba->video.vram); \
wait += waitstatesRegion[REGION_VRAM]; wait += waitstatesRegion[REGION_VRAM];
#define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw); #define LOAD_OAM LOAD_32(value, address & (SIZE_OAM - 4), gba->video.oam.raw);
@ -520,11 +524,15 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette); LOAD_16(value, address & (SIZE_PALETTE_RAM - 2), gba->video.palette);
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
LOAD_16(value, address & 0x0001FFFE, gba->video.vram); if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
} else { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load16: 0x%08X", address);
LOAD_16(value, address & 0x00017FFE, gba->video.vram); value = 0;
break;
}
address &= 0x00017FFE;
} }
LOAD_16(value, address & 0x0001FFFE, gba->video.vram);
break; break;
case REGION_OAM: case REGION_OAM:
LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw); LOAD_16(value, address & (SIZE_OAM - 2), gba->video.oam.raw);
@ -631,11 +639,15 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)]; value = ((uint8_t*) gba->video.palette)[address & (SIZE_PALETTE_RAM - 1)];
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF]; if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
} else { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Load8: 0x%08X", address);
value = ((uint8_t*) gba->video.vram)[address & 0x00017FFF]; value = 0;
break;
}
address &= 0x00017FFF;
} }
value = ((uint8_t*) gba->video.vram)[address & 0x0001FFFF];
break; break;
case REGION_OAM: case REGION_OAM:
value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)]; value = ((uint8_t*) gba->video.oam.raw)[address & (SIZE_OAM - 1)];
@ -717,20 +729,18 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
wait += waitstatesRegion[REGION_PALETTE_RAM]; wait += waitstatesRegion[REGION_PALETTE_RAM];
#define STORE_VRAM \ #define STORE_VRAM \
if ((address & 0x0001FFFF) < SIZE_VRAM) { \ if ((address & 0x0001FFFF) >= SIZE_VRAM) { \
LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \ if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) { \
if (oldValue != value) { \ mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store32: 0x%08X", address); \
STORE_32(value, address & 0x0001FFFC, gba->video.vram); \ break; \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
} \
} else { \
LOAD_32(oldValue, address & 0x00017FFC, gba->video.vram); \
if (oldValue != value) { \
STORE_32(value, address & 0x00017FFC, gba->video.vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x00017FFC)); \
} \ } \
address &= 0x00017FFC; \
} \
LOAD_32(oldValue, address & 0x0001FFFC, gba->video.vram); \
if (oldValue != value) { \
STORE_32(value, address & 0x0001FFFC, gba->video.vram); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC) + 2); \
gba->video.renderer->writeVRAM(gba->video.renderer, (address & 0x0001FFFC)); \
} \ } \
wait += waitstatesRegion[REGION_VRAM]; wait += waitstatesRegion[REGION_VRAM];
@ -840,18 +850,17 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
} }
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) < SIZE_VRAM) { if ((address & 0x0001FFFF) >= SIZE_VRAM) {
LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram); if ((address & (SIZE_VRAM | 0x00014000)) == SIZE_VRAM && (GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3)) {
if (value != oldValue) { mLOG(GBA_MEM, GAME_ERROR, "Bad VRAM Store16: 0x%08X", address);
STORE_16(value, address & 0x0001FFFE, gba->video.vram); break;
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
}
} else {
LOAD_16(oldValue, address & 0x00017FFE, gba->video.vram);
if (value != oldValue) {
STORE_16(value, address & 0x00017FFE, gba->video.vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x00017FFE);
} }
address &= 0x00017FFE;
}
LOAD_16(oldValue, address & 0x0001FFFE, gba->video.vram);
if (value != oldValue) {
STORE_16(value, address & 0x0001FFFE, gba->video.vram);
gba->video.renderer->writeVRAM(gba->video.renderer, address & 0x0001FFFE);
} }
break; break;
case REGION_OAM: case REGION_OAM:
@ -939,7 +948,6 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
break; break;
case REGION_VRAM: case REGION_VRAM:
if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) { if ((address & 0x0001FFFF) >= ((GBARegisterDISPCNTGetMode(gba->memory.io[REG_DISPCNT >> 1]) >= 3) ? 0x00014000 : 0x00010000)) {
// TODO: check BG mode
mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address); mLOG(GBA_MEM, GAME_ERROR, "Cannot Store8 to OBJ: 0x%08X", address);
break; break;
} }

View File

@ -67,12 +67,8 @@
LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \ LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \
current = renderer->spriteLayer[outX]; \ current = renderer->spriteLayer[outX]; \
if ((current & FLAG_ORDER_MASK) > flags) { \ if ((current & FLAG_UNWRITTEN) == FLAG_UNWRITTEN && tileData) { \
if (tileData) { \ renderer->spriteLayer[outX] = palette[tileData] | flags; \
renderer->spriteLayer[outX] = palette[tileData] | flags; \
} else if (current != FLAG_UNWRITTEN) { \
renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \
} \
} }
#define SPRITE_DRAW_PIXEL_16_NORMAL_OBJWIN(localX) \ #define SPRITE_DRAW_PIXEL_16_NORMAL_OBJWIN(localX) \
@ -84,13 +80,9 @@
LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \ LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \ tileData = (tileData >> ((localX & 3) << 2)) & 0xF; \
current = renderer->spriteLayer[outX]; \ current = renderer->spriteLayer[outX]; \
if ((current & FLAG_ORDER_MASK) > flags) { \ if ((current & FLAG_UNWRITTEN) == FLAG_UNWRITTEN && tileData) { \
if (tileData) { \ unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \
unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \ renderer->spriteLayer[outX] = color | flags; \
renderer->spriteLayer[outX] = color | flags; \
} else if (current != FLAG_UNWRITTEN) { \
renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \
} \
} }
#define SPRITE_DRAW_PIXEL_16_OBJWIN(localX) \ #define SPRITE_DRAW_PIXEL_16_OBJWIN(localX) \
@ -117,12 +109,8 @@
LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \ LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \
current = renderer->spriteLayer[outX]; \ current = renderer->spriteLayer[outX]; \
if ((current & FLAG_ORDER_MASK) > flags) { \ if ((current & FLAG_UNWRITTEN) == FLAG_UNWRITTEN && tileData) { \
if (tileData) { \ renderer->spriteLayer[outX] = palette[tileData] | flags; \
renderer->spriteLayer[outX] = palette[tileData] | flags; \
} else if (current != FLAG_UNWRITTEN) { \
renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \
} \
} }
#define SPRITE_DRAW_PIXEL_256_NORMAL_OBJWIN(localX) \ #define SPRITE_DRAW_PIXEL_256_NORMAL_OBJWIN(localX) \
@ -134,13 +122,9 @@
LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \ LOAD_16(tileData, spriteBase & VRAM_BLOCK_MASK, vramBase); \
tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \ tileData = (tileData >> ((localX & 1) << 3)) & 0xFF; \
current = renderer->spriteLayer[outX]; \ current = renderer->spriteLayer[outX]; \
if ((current & FLAG_ORDER_MASK) > flags) { \ if ((current & FLAG_UNWRITTEN) == FLAG_UNWRITTEN && tileData) { \
if (tileData) { \ unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \
unsigned color = (renderer->row[outX] & FLAG_OBJWIN) ? objwinPalette[tileData] : palette[tileData]; \ renderer->spriteLayer[outX] = color | flags; \
renderer->spriteLayer[outX] = color | flags; \
} else if (current != FLAG_UNWRITTEN) { \
renderer->spriteLayer[outX] = (current & ~FLAG_ORDER_MASK) | GBAObjAttributesCGetPriority(sprite->c) << OFFSET_PRIORITY; \
} \
} }
#define SPRITE_DRAW_PIXEL_256_OBJWIN(localX) \ #define SPRITE_DRAW_PIXEL_256_OBJWIN(localX) \

View File

@ -8,7 +8,8 @@
#include <mgba/internal/gba/gba.h> #include <mgba/internal/gba/gba.h>
#include <mgba/internal/gba/io.h> #include <mgba/internal/gba/io.h>
#define LOCKSTEP_INCREMENT 3000 #define LOCKSTEP_INCREMENT 2000
#define LOCKSTEP_TRANSFER 512
static bool GBASIOLockstepNodeInit(struct GBASIODriver* driver); static bool GBASIOLockstepNodeInit(struct GBASIODriver* driver);
static void GBASIOLockstepNodeDeinit(struct GBASIODriver* driver); static void GBASIOLockstepNodeDeinit(struct GBASIODriver* driver);
@ -17,9 +18,9 @@ static bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver);
static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value);
static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate); static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* driver, uint32_t cyclesLate);
static void _finishTransfer(struct GBASIOLockstepNode* node);
void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) { void GBASIOLockstepInit(struct GBASIOLockstep* lockstep) {
mLockstepInit(&lockstep->d);
lockstep->players[0] = 0; lockstep->players[0] = 0;
lockstep->players[1] = 0; lockstep->players[1] = 0;
lockstep->players[2] = 0; lockstep->players[2] = 0;
@ -88,12 +89,16 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
node->nextEvent = 0; node->nextEvent = 0;
node->eventDiff = 0; node->eventDiff = 0;
mTimingSchedule(&driver->p->p->timing, &node->event, 0); mTimingSchedule(&driver->p->p->timing, &node->event, 0);
mLockstepLock(&node->p->d);
node->mode = driver->p->mode; node->mode = driver->p->mode;
switch (node->mode) { switch (node->mode) {
case SIO_MULTI: case SIO_MULTI:
node->d.writeRegister = GBASIOLockstepNodeMultiWriteRegister; node->d.writeRegister = GBASIOLockstepNodeMultiWriteRegister;
node->d.p->rcnt |= 3; node->d.p->rcnt |= 3;
++node->p->attachedMulti; ATOMIC_ADD(node->p->attachedMulti, 1);
node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached;
if (node->id) { if (node->id) {
node->d.p->rcnt |= 4; node->d.p->rcnt |= 4;
@ -110,35 +115,83 @@ bool GBASIOLockstepNodeLoad(struct GBASIODriver* driver) {
node->phase = node->p->d.transferActive; node->phase = node->p->d.transferActive;
node->transferId = node->p->d.transferId; node->transferId = node->p->d.transferId;
#endif #endif
mLockstepUnlock(&node->p->d);
return true; return true;
} }
bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) { bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
mLockstepLock(&node->p->d);
node->mode = driver->p->mode; node->mode = driver->p->mode;
switch (node->mode) { switch (node->mode) {
case SIO_MULTI: case SIO_MULTI:
--node->p->attachedMulti; ATOMIC_SUB(node->p->attachedMulti, 1);
break; break;
default: default:
break; break;
} }
// Flush ongoing transfer
if (mTimingIsScheduled(&driver->p->p->timing, &node->event)) {
int oldWhen = node->event.when;
mTimingDeschedule(&driver->p->p->timing, &node->event);
mTimingSchedule(&driver->p->p->timing, &node->event, 0);
node->eventDiff -= oldWhen - node->event.when;
mTimingDeschedule(&driver->p->p->timing, &node->event);
}
node->p->d.unload(&node->p->d, node->id); node->p->d.unload(&node->p->d, node->id);
mTimingDeschedule(&driver->p->p->timing, &node->event);
node->p->multiRecv[0] = 0xFFFF;
node->p->multiRecv[1] = 0xFFFF;
node->p->multiRecv[2] = 0xFFFF;
node->p->multiRecv[3] = 0xFFFF;
_finishTransfer(node);
if (!node->id) {
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_IDLE);
}
// Invalidate SIO mode
node->mode = SIO_GPIO;
mLockstepUnlock(&node->p->d);
return true; return true;
} }
static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
mLockstepLock(&node->p->d);
if (address == REG_SIOCNT) { if (address == REG_SIOCNT) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value);
if (value & 0x0080 && node->p->d.transferActive == TRANSFER_IDLE) {
enum mLockstepPhase transferActive;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
if (value & 0x0080 && transferActive == TRANSFER_IDLE) {
if (!node->id && node->d.p->multiplayerControl.ready) { if (!node->id && node->d.p->multiplayerControl.ready) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id); mLOG(GBA_SIO, DEBUG, "Lockstep %i: Transfer initiated", node->id);
node->p->d.transferActive = TRANSFER_STARTING; ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
node->p->d.transferCycles = GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->d.attached - 1]; ATOMIC_STORE(node->p->d.transferCycles, GBASIOCyclesPerTransfer[node->d.p->multiplayerControl.baud][node->p->d.attached - 1]);
bool scheduled = mTimingIsScheduled(&driver->p->p->timing, &node->event);
int oldWhen = node->event.when;
mTimingDeschedule(&driver->p->p->timing, &node->event); mTimingDeschedule(&driver->p->p->timing, &node->event);
mTimingSchedule(&driver->p->p->timing, &node->event, 0); mTimingSchedule(&driver->p->p->timing, &node->event, 0);
if (scheduled) {
node->eventDiff -= oldWhen - node->event.when;
}
} else { } else {
value &= ~0x0080; value &= ~0x0080;
} }
@ -148,6 +201,9 @@ static uint16_t GBASIOLockstepNodeMultiWriteRegister(struct GBASIODriver* driver
} else if (address == REG_SIOMLT_SEND) { } else if (address == REG_SIOMLT_SEND) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04x", node->id, value); mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOMLT_SEND <- %04x", node->id, value);
} }
mLockstepUnlock(&node->p->d);
return value; return value;
} }
@ -155,6 +211,7 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) {
if (node->transferFinished) { if (node->transferFinished) {
return; return;
} }
struct GBASIO* sio = node->d.p; struct GBASIO* sio = node->d.p;
switch (node->mode) { switch (node->mode) {
case SIO_MULTI: case SIO_MULTI:
@ -209,27 +266,38 @@ static void _finishTransfer(struct GBASIOLockstepNode* node) {
static int32_t _masterUpdate(struct GBASIOLockstepNode* node) { static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
bool needsToWait = false; bool needsToWait = false;
int i; int i;
switch (node->p->d.transferActive) {
enum mLockstepPhase transferActive;
int attachedMulti, attached;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(attachedMulti, node->p->attachedMulti);
ATOMIC_LOAD(attached, node->p->d.attached);
switch (transferActive) {
case TRANSFER_IDLE: case TRANSFER_IDLE:
// If the master hasn't initiated a transfer, it can keep going. // If the master hasn't initiated a transfer, it can keep going.
node->nextEvent += LOCKSTEP_INCREMENT; node->nextEvent += LOCKSTEP_INCREMENT;
node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; node->d.p->multiplayerControl.ready = attachedMulti == attached;
break; break;
case TRANSFER_STARTING: case TRANSFER_STARTING:
// Start the transfer, but wait for the other GBAs to catch up // Start the transfer, but wait for the other GBAs to catch up
node->transferFinished = false; node->transferFinished = false;
node->p->multiRecv[0] = 0xFFFF; 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[1] = 0xFFFF;
node->p->multiRecv[2] = 0xFFFF; node->p->multiRecv[2] = 0xFFFF;
node->p->multiRecv[3] = 0xFFFF; node->p->multiRecv[3] = 0xFFFF;
needsToWait = true; needsToWait = true;
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTED); ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTED);
node->nextEvent += 512; node->nextEvent += LOCKSTEP_TRANSFER;
break; break;
case TRANSFER_STARTED: case TRANSFER_STARTED:
// All the other GBAs have caught up and are sleeping, we can all continue now // All the other GBAs have caught up and are sleeping, we can all continue now
node->p->multiRecv[0] = node->d.p->p->memory.io[REG_SIOMLT_SEND >> 1]; node->nextEvent += LOCKSTEP_TRANSFER;
node->nextEvent += 512;
ATOMIC_STORE(node->p->d.transferActive, TRANSFER_FINISHING); ATOMIC_STORE(node->p->d.transferActive, TRANSFER_FINISHING);
break; break;
case TRANSFER_FINISHING: case TRANSFER_FINISHING:
@ -269,6 +337,7 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
#ifndef NDEBUG #ifndef NDEBUG
node->phase = node->p->d.transferActive; node->phase = node->p->d.transferActive;
#endif #endif
if (needsToWait) { if (needsToWait) {
return 0; return 0;
} }
@ -276,9 +345,16 @@ static int32_t _masterUpdate(struct GBASIOLockstepNode* node) {
} }
static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) { static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) {
node->d.p->multiplayerControl.ready = node->p->attachedMulti == node->p->d.attached; enum mLockstepPhase transferActive;
int attachedMulti, attached;
ATOMIC_LOAD(transferActive, node->p->d.transferActive);
ATOMIC_LOAD(attachedMulti, node->p->attachedMulti);
ATOMIC_LOAD(attached, node->p->d.attached);
node->d.p->multiplayerControl.ready = attachedMulti == attached;
bool signal = false; bool signal = false;
switch (node->p->d.transferActive) { switch (transferActive) {
case TRANSFER_IDLE: case TRANSFER_IDLE:
if (!node->d.p->multiplayerControl.ready) { if (!node->d.p->multiplayerControl.ready) {
node->p->d.addCycles(&node->p->d, node->id, LOCKSTEP_INCREMENT); node->p->d.addCycles(&node->p->d, node->id, LOCKSTEP_INCREMENT);
@ -288,6 +364,9 @@ static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) {
case TRANSFER_FINISHING: case TRANSFER_FINISHING:
break; break;
case TRANSFER_STARTED: case TRANSFER_STARTED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) {
break;
}
node->transferFinished = false; node->transferFinished = false;
switch (node->mode) { switch (node->mode) {
case SIO_MULTI: case SIO_MULTI:
@ -315,6 +394,9 @@ static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) {
signal = true; signal = true;
break; break;
case TRANSFER_FINISHED: case TRANSFER_FINISHED:
if (node->p->d.unusedCycles(&node->p->d, node->id) > node->eventDiff) {
break;
}
_finishTransfer(node); _finishTransfer(node);
signal = true; signal = true;
break; break;
@ -325,16 +407,20 @@ static uint32_t _slaveUpdate(struct GBASIOLockstepNode* node) {
if (signal) { if (signal) {
node->p->d.signal(&node->p->d, 1 << node->id); node->p->d.signal(&node->p->d, 1 << node->id);
} }
return 0; return 0;
} }
static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) {
struct GBASIOLockstepNode* node = user; struct GBASIOLockstepNode* node = user;
mLockstepLock(&node->p->d);
if (node->p->d.attached < 2) { if (node->p->d.attached < 2) {
mLockstepUnlock(&node->p->d);
return; return;
} }
int32_t cycles = 0; int32_t cycles = 0;
node->nextEvent -= cyclesLate; node->nextEvent -= cyclesLate;
node->eventDiff += cyclesLate;
if (node->nextEvent <= 0) { if (node->nextEvent <= 0) {
if (!node->id) { if (!node->id) {
cycles = _masterUpdate(node); cycles = _masterUpdate(node);
@ -353,12 +439,18 @@ static void _GBASIOLockstepNodeProcessEvents(struct mTiming* timing, void* user,
mTimingSchedule(timing, &node->event, cycles); mTimingSchedule(timing, &node->event, cycles);
} else { } else {
node->d.p->p->earlyExit = true; node->d.p->p->earlyExit = true;
mTimingSchedule(timing, &node->event, cyclesLate + 1); node->eventDiff += 1;
mTimingSchedule(timing, &node->event, 1);
} }
mLockstepUnlock(&node->p->d);
} }
static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) {
struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver; struct GBASIOLockstepNode* node = (struct GBASIOLockstepNode*) driver;
mLockstepLock(&node->p->d);
if (address == REG_SIOCNT) { if (address == REG_SIOCNT) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value); mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIOCNT <- %04x", node->id, value);
value &= 0xFF8B; value &= 0xFF8B;
@ -368,7 +460,7 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
if (value & 0x0080 && !node->id) { if (value & 0x0080 && !node->id) {
// Internal shift clock // Internal shift clock
if (value & 1) { if (value & 1) {
node->p->d.transferActive = TRANSFER_STARTING; ATOMIC_STORE(node->p->d.transferActive, TRANSFER_STARTING);
} }
// Frequency // Frequency
if (value & 2) { if (value & 2) {
@ -382,5 +474,8 @@ static uint16_t GBASIOLockstepNodeNormalWriteRegister(struct GBASIODriver* drive
} else if (address == REG_SIODATA32_HI) { } else if (address == REG_SIODATA32_HI) {
mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, value); mLOG(GBA_SIO, DEBUG, "Lockstep %i: SIODATA32_HI <- %04x", node->id, value);
} }
mLockstepUnlock(&node->p->d);
return value; return value;
} }

View File

@ -1,14 +1,4 @@
if(DEFINED ENV{DEVKITPRO}) include(${CMAKE_CURRENT_LIST_DIR}/../cmake/devkitPro.cmake)
set(DEVKITPRO $ENV{DEVKITPRO})
else()
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
endif()
if(DEFINED ENV{DEVKITARM})
set(DEVKITARM $ENV{DEVKITARM})
else()
set(DEVKITARM ${DEVKITPRO}/devkitARM)
endif()
if(DEFINED ENV{CTRULIB}) if(DEFINED ENV{CTRULIB})
set(CTRULIB $ENV{CTRULIB}) set(CTRULIB $ENV{CTRULIB})
@ -16,40 +6,17 @@ else()
set(CTRULIB ${DEVKITPRO}/libctru) set(CTRULIB ${DEVKITPRO}/libctru)
endif() endif()
set(extension)
if (CMAKE_HOST_WIN32)
set(extension .exe)
endif()
set(CMAKE_PROGRAM_PATH ${DEVKITARM}/bin)
set(cross_prefix arm-none-eabi-) set(cross_prefix arm-none-eabi-)
set(arch_flags "-march=armv6k -mtune=mpcore -mfloat-abi=hard -ffunction-sections") set(arch_flags "-march=armv6k -mtune=mpcore -mfloat-abi=hard -ffunction-sections")
set(inc_flags "-I${CTRULIB}/include ${arch_flags} -mword-relocations") set(inc_flags "-I${CTRULIB}/include ${arch_flags} -mword-relocations")
set(link_flags "-L${CTRULIB}/lib -lctru -specs=3dsx.specs ${arch_flags} -Wl,--gc-sections") set(link_flags "-L${CTRULIB}/lib -lctru -specs=3dsx.specs ${arch_flags} -Wl,--gc-sections")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor") set(CMAKE_SYSTEM_PROCESSOR arm CACHE INTERNAL "processor")
set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi CACHE INTERNAL "abi") set(CMAKE_LIBRARY_ARCHITECTURE arm-none-eabi CACHE INTERNAL "abi")
find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension})
find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension})
find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM}/arm-none-eabi ${DEVKITPRO}/portlibs/3ds)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")
set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE)
set(3DS ON) set(3DS ON)
add_definitions(-D_3DS -DARM11) add_definitions(-D_3DS -DARM11)
create_devkit(ARM)
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM}/${CMAKE_LIBRARY_ARCHITECTURE} ${DEVKITPRO}/portlibs/3ds)

View File

@ -0,0 +1,41 @@
if(DEFINED ENV{DEVKITPRO})
set(DEVKITPRO $ENV{DEVKITPRO})
else()
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
endif()
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
function(create_devkit DEVKIT)
if(DEFINED ENV{DEVKIT${DEVKIT}})
set(DEVKIT${DEVKIT} $ENV{DEVKIT${DEVKIT}} PARENT_SCOPE)
else()
set(DEVKIT${DEVKIT} ${DEVKITPRO}/devkit${DEVKIT} PARENT_SCOPE)
endif()
set(CMAKE_PROGRAM_PATH ${DEVKIT${DEVKIT}}/bin CACHE INTERNAL "program path")
set(extension)
if (CMAKE_HOST_WIN32)
set(extension .exe)
endif()
find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension})
find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension})
find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")
set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE)
endfunction()

View File

@ -30,8 +30,11 @@ void ActionMapper::clearMenu(const QString& name) {
emit menuCleared(name); emit menuCleared(name);
} }
void ActionMapper::rebuildMenu(QMenuBar* menubar, const ShortcutController& shortcuts) { void ActionMapper::rebuildMenu(QMenuBar* menubar, QWidget* context, const ShortcutController& shortcuts) {
menubar->clear(); menubar->clear();
for (QAction* action : context->actions()) {
context->removeAction(action);
}
for (const QString& m : m_menus[{}]) { for (const QString& m : m_menus[{}]) {
if (m_hiddenActions.contains(m)) { if (m_hiddenActions.contains(m)) {
continue; continue;
@ -39,11 +42,11 @@ void ActionMapper::rebuildMenu(QMenuBar* menubar, const ShortcutController& shor
QString menu = m.mid(1); QString menu = m.mid(1);
QMenu* qmenu = menubar->addMenu(m_menuNames[menu]); QMenu* qmenu = menubar->addMenu(m_menuNames[menu]);
rebuildMenu(menu, qmenu, shortcuts); rebuildMenu(menu, qmenu, context, shortcuts);
} }
} }
void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, const ShortcutController& shortcuts) { void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* context, const ShortcutController& shortcuts) {
for (const QString& actionName : m_menus[menu]) { for (const QString& actionName : m_menus[menu]) {
if (actionName.isNull()) { if (actionName.isNull()) {
qmenu->addSeparator(); qmenu->addSeparator();
@ -55,12 +58,13 @@ void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, const Shortcut
if (actionName[0] == '.') { if (actionName[0] == '.') {
QString name = actionName.mid(1); QString name = actionName.mid(1);
QMenu* newMenu = qmenu->addMenu(m_menuNames[name]); QMenu* newMenu = qmenu->addMenu(m_menuNames[name]);
rebuildMenu(name, newMenu, shortcuts); rebuildMenu(name, newMenu, context, shortcuts);
continue; continue;
} }
Action* action = &m_actions[actionName]; Action* action = &m_actions[actionName];
QAction* qaction = qmenu->addAction(action->visibleName()); QAction* qaction = qmenu->addAction(action->visibleName());
qaction->setEnabled(action->isEnabled()); qaction->setEnabled(action->isEnabled());
qaction->setShortcutContext(Qt::WidgetShortcut);
if (action->isExclusive() || action->booleanAction()) { if (action->isExclusive() || action->booleanAction()) {
qaction->setCheckable(true); qaction->setCheckable(true);
} }
@ -88,6 +92,7 @@ void ActionMapper::rebuildMenu(const QString& menu, QMenu* qmenu, const Shortcut
qaction->setShortcut(QKeySequence(shortcut)); qaction->setShortcut(QKeySequence(shortcut));
}); });
} }
context->addAction(qaction);
} }
} }

View File

@ -29,7 +29,7 @@ public:
void addMenu(const QString& visibleName, const QString& name, const QString& parent = {}); void addMenu(const QString& visibleName, const QString& name, const QString& parent = {});
void addHiddenMenu(const QString& visibleName, const QString& name, const QString& parent = {}); void addHiddenMenu(const QString& visibleName, const QString& name, const QString& parent = {});
void clearMenu(const QString& name); void clearMenu(const QString& name);
void rebuildMenu(QMenuBar*, const ShortcutController&); void rebuildMenu(QMenuBar*, QWidget* context, const ShortcutController&);
void addSeparator(const QString& menu); void addSeparator(const QString& menu);
@ -59,7 +59,7 @@ signals:
void menuCleared(const QString& name); void menuCleared(const QString& name);
private: private:
void rebuildMenu(const QString& menu, QMenu* qmenu, const ShortcutController&); void rebuildMenu(const QString& menu, QMenu* qmenu, QWidget* context, const ShortcutController&);
Action* addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut); Action* addAction(const Action& act, const QString& name, const QString& menu, const QKeySequence& shortcut);
QHash<QString, Action> m_actions; QHash<QString, Action> m_actions;

View File

@ -37,6 +37,7 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent)
m_painter = new PainterGL(format.majorVersion() < 2 ? 1 : m_gl->format().majorVersion(), m_gl); m_painter = new PainterGL(format.majorVersion() < 2 ? 1 : m_gl->format().majorVersion(), m_gl);
m_gl->setMouseTracking(true); m_gl->setMouseTracking(true);
m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work? m_gl->setAttribute(Qt::WA_TransparentForMouseEvents); // This doesn't seem to work?
setUpdatesEnabled(false); // Prevent paint events, which can cause race conditions
} }
DisplayGL::~DisplayGL() { DisplayGL::~DisplayGL() {
@ -223,6 +224,9 @@ PainterGL::PainterGL(int majorVersion, QGLWidget* parent)
#endif #endif
m_backend->swap = [](VideoBackend* v) { m_backend->swap = [](VideoBackend* v) {
PainterGL* painter = static_cast<PainterGL*>(v->user); PainterGL* painter = static_cast<PainterGL*>(v->user);
if (!painter->m_gl->isVisible()) {
return;
}
painter->m_gl->swapBuffers(); painter->m_gl->swapBuffers();
}; };

View File

@ -32,7 +32,7 @@ public:
EmptyGLWidget(const QGLFormat& format, QWidget* parent) : QGLWidget(format, parent) { setAutoBufferSwap(false); } EmptyGLWidget(const QGLFormat& format, QWidget* parent) : QGLWidget(format, parent) { setAutoBufferSwap(false); }
protected: protected:
void paintEvent(QPaintEvent*) override {} void paintEvent(QPaintEvent* event) override { event->ignore(); }
void resizeEvent(QResizeEvent*) override {} void resizeEvent(QResizeEvent*) override {}
void mouseMoveEvent(QMouseEvent* event) override { event->ignore(); } void mouseMoveEvent(QMouseEvent* event) override { event->ignore(); }
}; };

View File

@ -79,7 +79,9 @@ void MessagePainter::redraw() {
} }
void MessagePainter::paint(QPainter* painter) { void MessagePainter::paint(QPainter* painter) {
painter->drawPixmap(m_local, m_pixmap); if (!m_message.text().isEmpty()) {
painter->drawPixmap(m_local, m_pixmap);
}
} }

View File

@ -16,26 +16,43 @@
using namespace QGBA; using namespace QGBA;
MultiplayerController::Player::Player(CoreController* coreController, GBSIOLockstepNode* node)
: controller(coreController)
, gbNode(node)
{
}
MultiplayerController::Player::Player(CoreController* coreController, GBASIOLockstepNode* node)
: controller(coreController)
, gbaNode(node)
{
}
MultiplayerController::MultiplayerController() { MultiplayerController::MultiplayerController() {
mLockstepInit(&m_lockstep); mLockstepInit(&m_lockstep);
m_lockstep.context = this; m_lockstep.context = this;
m_lockstep.lock = [](mLockstep* lockstep) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.lock();
};
m_lockstep.unlock = [](mLockstep* lockstep) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.unlock();
};
m_lockstep.signal = [](mLockstep* lockstep, unsigned mask) { m_lockstep.signal = [](mLockstep* lockstep, unsigned mask) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context); MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
Player* player = &controller->m_players[0]; Player* player = &controller->m_players[0];
bool woke = false; bool woke = false;
controller->m_lock.lock();
player->waitMask &= ~mask; player->waitMask &= ~mask;
if (!player->waitMask && player->awake < 1) { if (!player->waitMask && player->awake < 1) {
mCoreThreadStopWaiting(player->controller->thread()); mCoreThreadStopWaiting(player->controller->thread());
player->awake = 1; player->awake = 1;
woke = true; woke = true;
} }
controller->m_lock.unlock();
return woke; return woke;
}; };
m_lockstep.wait = [](mLockstep* lockstep, unsigned mask) { m_lockstep.wait = [](mLockstep* lockstep, unsigned mask) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context); MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.lock();
Player* player = &controller->m_players[0]; Player* player = &controller->m_players[0];
bool slept = false; bool slept = false;
player->waitMask |= mask; player->waitMask |= mask;
@ -44,7 +61,6 @@ MultiplayerController::MultiplayerController() {
player->awake = 0; player->awake = 0;
slept = true; slept = true;
} }
controller->m_lock.unlock();
return slept; return slept;
}; };
m_lockstep.addCycles = [](mLockstep* lockstep, int id, int32_t cycles) { m_lockstep.addCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
@ -52,7 +68,6 @@ MultiplayerController::MultiplayerController() {
abort(); abort();
} }
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context); MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.lock();
if (!id) { if (!id) {
for (int i = 1; i < controller->m_players.count(); ++i) { for (int i = 1; i < controller->m_players.count(); ++i) {
Player* player = &controller->m_players[i]; Player* player = &controller->m_players[i];
@ -85,11 +100,9 @@ MultiplayerController::MultiplayerController() {
controller->m_players[id].controller->setSync(true); controller->m_players[id].controller->setSync(true);
controller->m_players[id].cyclesPosted += cycles; controller->m_players[id].cyclesPosted += cycles;
} }
controller->m_lock.unlock();
}; };
m_lockstep.useCycles = [](mLockstep* lockstep, int id, int32_t cycles) { m_lockstep.useCycles = [](mLockstep* lockstep, int id, int32_t cycles) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context); MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.lock();
Player* player = &controller->m_players[id]; Player* player = &controller->m_players[id];
player->cyclesPosted -= cycles; player->cyclesPosted -= cycles;
if (player->cyclesPosted <= 0) { if (player->cyclesPosted <= 0) {
@ -97,15 +110,23 @@ MultiplayerController::MultiplayerController() {
player->awake = 0; player->awake = 0;
} }
cycles = player->cyclesPosted; cycles = player->cyclesPosted;
controller->m_lock.unlock(); return cycles;
};
m_lockstep.unusedCycles= [](mLockstep* lockstep, int id) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
Player* player = &controller->m_players[id];
auto cycles = player->cyclesPosted;
return cycles; return cycles;
}; };
m_lockstep.unload = [](mLockstep* lockstep, int id) { m_lockstep.unload = [](mLockstep* lockstep, int id) {
MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context); MultiplayerController* controller = static_cast<MultiplayerController*>(lockstep->context);
controller->m_lock.lock();
Player* player = &controller->m_players[id];
if (id) { if (id) {
Player* player = &controller->m_players[id];
player->controller->setSync(true); player->controller->setSync(true);
player->cyclesPosted = 0;
// release master GBA if it is waiting for this GBA
player = &controller->m_players[0];
player->waitMask &= ~(1 << id); player->waitMask &= ~(1 << id);
if (!player->waitMask && player->awake < 1) { if (!player->waitMask && player->awake < 1) {
mCoreThreadStopWaiting(player->controller->thread()); mCoreThreadStopWaiting(player->controller->thread());
@ -149,10 +170,13 @@ MultiplayerController::MultiplayerController() {
} }
} }
} }
controller->m_lock.unlock();
}; };
} }
MultiplayerController::~MultiplayerController() {
mLockstepDeinit(&m_lockstep);
}
bool MultiplayerController::attachGame(CoreController* controller) { bool MultiplayerController::attachGame(CoreController* controller) {
if (m_lockstep.attached == MAX_GBAS) { if (m_lockstep.attached == MAX_GBAS) {
return false; return false;
@ -188,14 +212,7 @@ bool MultiplayerController::attachGame(CoreController* controller) {
GBASIOLockstepNode* node = new GBASIOLockstepNode; GBASIOLockstepNode* node = new GBASIOLockstepNode;
GBASIOLockstepNodeCreate(node); GBASIOLockstepNodeCreate(node);
GBASIOLockstepAttachNode(&m_gbaLockstep, node); GBASIOLockstepAttachNode(&m_gbaLockstep, node);
m_players.append({ m_players.append({controller, node});
controller,
nullptr,
node,
1,
0,
0
});
GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI); GBASIOSetDriver(&gba->sio, &node->d, SIO_MULTI);
@ -210,14 +227,7 @@ bool MultiplayerController::attachGame(CoreController* controller) {
GBSIOLockstepNode* node = new GBSIOLockstepNode; GBSIOLockstepNode* node = new GBSIOLockstepNode;
GBSIOLockstepNodeCreate(node); GBSIOLockstepNodeCreate(node);
GBSIOLockstepAttachNode(&m_gbLockstep, node); GBSIOLockstepAttachNode(&m_gbLockstep, node);
m_players.append({ m_players.append({controller, node});
controller,
node,
nullptr,
1,
0,
0
});
GBSIOSetDriver(&gb->sio, &node->d); GBSIOSetDriver(&gb->sio, &node->d);

View File

@ -17,6 +17,8 @@
#include <mgba/internal/gb/sio/lockstep.h> #include <mgba/internal/gb/sio/lockstep.h>
#endif #endif
#include <memory>
struct GBSIOLockstepNode; struct GBSIOLockstepNode;
struct GBASIOLockstepNode; struct GBASIOLockstepNode;
@ -29,6 +31,7 @@ Q_OBJECT
public: public:
MultiplayerController(); MultiplayerController();
~MultiplayerController();
bool attachGame(CoreController*); bool attachGame(CoreController*);
void detachGame(CoreController*); void detachGame(CoreController*);
@ -42,12 +45,15 @@ signals:
private: private:
struct Player { struct Player {
Player(CoreController* controller, GBSIOLockstepNode* node);
Player(CoreController* controller, GBASIOLockstepNode* node);
CoreController* controller; CoreController* controller;
GBSIOLockstepNode* gbNode; GBSIOLockstepNode* gbNode = nullptr;
GBASIOLockstepNode* gbaNode; GBASIOLockstepNode* gbaNode = nullptr;
int awake; int awake = 1;
int32_t cyclesPosted; int32_t cyclesPosted = 0;
unsigned waitMask; unsigned waitMask = 0;
}; };
union { union {
mLockstep m_lockstep; mLockstep m_lockstep;

View File

@ -279,7 +279,11 @@ void VideoView::setAudioCodec(const QString& codec, bool manual) {
void VideoView::setVideoCodec(const QString& codec, bool manual) { void VideoView::setVideoCodec(const QString& codec, bool manual) {
free(m_videoCodecCstr); free(m_videoCodecCstr);
m_videoCodec = sanitizeCodec(codec, s_vcodecMap); m_videoCodec = sanitizeCodec(codec, s_vcodecMap);
m_videoCodecCstr = strdup(m_videoCodec.toUtf8().constData()); if (m_videoCodec == "none") {
m_videoCodecCstr = nullptr;
} else {
m_videoCodecCstr = strdup(m_videoCodec.toUtf8().constData());
}
if (!FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr)) { if (!FFmpegEncoderSetVideo(&m_encoder, m_videoCodecCstr, m_vbr)) {
free(m_videoCodecCstr); free(m_videoCodecCstr);
m_videoCodecCstr = nullptr; m_videoCodecCstr = nullptr;

View File

@ -608,9 +608,7 @@ void Window::resizeEvent(QResizeEvent* event) {
} }
m_savedScale = factor; m_savedScale = factor;
for (QMap<int, Action*>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) { for (QMap<int, Action*>::iterator iter = m_frameSizes.begin(); iter != m_frameSizes.end(); ++iter) {
bool enableSignals = iter.value()->blockSignals(true);
iter.value()->setActive(iter.key() == factor); iter.value()->setActive(iter.key() == factor);
iter.value()->blockSignals(enableSignals);
} }
m_config->setOption("fullscreen", isFullScreen()); m_config->setOption("fullscreen", isFullScreen());
@ -636,6 +634,7 @@ void Window::showEvent(QShowEvent* event) {
m_fullscreenOnStart = false; m_fullscreenOnStart = false;
} }
reloadDisplayDriver(); reloadDisplayDriver();
setFocus();
} }
void Window::closeEvent(QCloseEvent* event) { void Window::closeEvent(QCloseEvent* event) {
@ -835,7 +834,7 @@ void Window::gameStarted() {
action->setActive(true); action->setActive(true);
} }
} }
m_actions.rebuildMenu(menuBar(), *m_shortcutController); m_actions.rebuildMenu(menuBar(), this, *m_shortcutController);
#ifdef USE_DISCORD_RPC #ifdef USE_DISCORD_RPC
@ -1382,9 +1381,7 @@ void Window::setupMenu(QMenuBar* menubar) {
m_savedScale = i; m_savedScale = i;
m_config->setOption("scaleMultiplier", i); // TODO: Port to other m_config->setOption("scaleMultiplier", i); // TODO: Port to other
resizeFrame(size); resizeFrame(size);
bool enableSignals = setSize->blockSignals(true);
setSize->setActive(true); setSize->setActive(true);
setSize->blockSignals(enableSignals);
}, "frame"); }, "frame");
setSize->setExclusive(true); setSize->setExclusive(true);
if (m_savedScale == i) { if (m_savedScale == i) {
@ -1481,18 +1478,13 @@ void Window::setupMenu(QMenuBar* menubar) {
#endif #endif
#ifdef USE_FFMPEG #ifdef USE_FFMPEG
addGameAction(tr("Record output..."), "recordOutput", this, &Window::openVideoWindow, "av"); addGameAction(tr("Record A/V..."), "recordOutput", this, &Window::openVideoWindow, "av");
#endif #endif
#ifdef USE_MAGICK #ifdef USE_MAGICK
addGameAction(tr("Record GIF..."), "recordGIF", this, &Window::openGIFWindow, "av"); addGameAction(tr("Record GIF..."), "recordGIF", this, &Window::openGIFWindow, "av");
#endif #endif
addGameAction(tr("Record video log..."), "recordVL", this, &Window::startVideoLog, "av");
addGameAction(tr("Stop video log"), "stopVL", [this]() {
m_controller->endVideoLog();
}, "av");
m_actions.addSeparator("av"); m_actions.addSeparator("av");
m_actions.addMenu(tr("Video layers"), "videoLayers", "av"); m_actions.addMenu(tr("Video layers"), "videoLayers", "av");
m_actions.addMenu(tr("Audio channels"), "audioChannels", "av"); m_actions.addMenu(tr("Audio channels"), "audioChannels", "av");
@ -1552,6 +1544,12 @@ void Window::setupMenu(QMenuBar* menubar) {
m_platformActions.insert(PLATFORM_GBA, ioViewer); m_platformActions.insert(PLATFORM_GBA, ioViewer);
#endif #endif
m_actions.addSeparator("tools");
addGameAction(tr("Record debug video log..."), "recordVL", this, &Window::startVideoLog, "tools");
addGameAction(tr("Stop debug video log"), "stopVL", [this]() {
m_controller->endVideoLog();
}, "tools");
ConfigOption* skipBios = m_config->addOption("skipBios"); ConfigOption* skipBios = m_config->addOption("skipBios");
skipBios->connect([this](const QVariant& value) { skipBios->connect([this](const QVariant& value) {
reloadConfig(); reloadConfig();
@ -1642,7 +1640,7 @@ void Window::setupMenu(QMenuBar* menubar) {
} }
m_shortcutController->rebuildItems(); m_shortcutController->rebuildItems();
m_actions.rebuildMenu(menubar, *m_shortcutController); m_actions.rebuildMenu(menuBar(), this, *m_shortcutController);
} }
void Window::attachWidget(QWidget* widget) { void Window::attachWidget(QWidget* widget) {
@ -1679,7 +1677,7 @@ void Window::updateMRU() {
} }
m_config->setMRU(m_mruFiles); m_config->setMRU(m_mruFiles);
m_config->write(); m_config->write();
m_actions.rebuildMenu(menuBar(), *m_shortcutController); m_actions.rebuildMenu(menuBar(), this, *m_shortcutController);
} }
Action* Window::addGameAction(const QString& visibleName, const QString& name, Action::Function function, const QString& menu, const QKeySequence& shortcut) { Action* Window::addGameAction(const QString& visibleName, const QString& name, Action::Function function, const QString& menu, const QKeySequence& shortcut) {

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,7 @@ set(MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/main.c)
if(BUILD_RASPI) if(BUILD_RASPI)
add_definitions(-DBUILD_RASPI) add_definitions(-DBUILD_RASPI)
list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c) list(APPEND PLATFORM_SRC ${CMAKE_SOURCE_DIR}/src/platform/opengl/gles2.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/gl-common.c ${CMAKE_SOURCE_DIR}/src/platform/sdl/rpi-common.c)
list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c) list(APPEND MAIN_SRC ${CMAKE_SOURCE_DIR}/src/platform/sdl/gles2-sdl.c)
set(OPENGLES2_LIBRARY "-lEGL -lGLESv2 -lbcm_host") set(OPENGLES2_LIBRARY "-lEGL -lGLESv2 -lbcm_host")
set(BUILD_GLES2 ON CACHE BOOL "Using OpenGL|ES 2" FORCE) set(BUILD_GLES2 ON CACHE BOOL "Using OpenGL|ES 2" FORCE)

View File

@ -6,6 +6,9 @@
#include "main.h" #include "main.h"
#include "gl-common.h" #include "gl-common.h"
#ifdef BUILD_RASPI
#include "rpi-common.h"
#endif
#include <mgba/core/core.h> #include <mgba/core/core.h>
#include <mgba/core/thread.h> #include <mgba/core/thread.h>
@ -26,74 +29,7 @@ void mSDLGLES2Create(struct mSDLRenderer* renderer) {
bool mSDLGLES2Init(struct mSDLRenderer* renderer) { bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
#ifdef BUILD_RASPI #ifdef BUILD_RASPI
bcm_host_init(); mRPIGLCommonInit(renderer);
renderer->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
int major, minor;
if (EGL_FALSE == eglInitialize(renderer->display, &major, &minor)) {
printf("Failed to initialize EGL");
return false;
}
if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
printf("Failed to get GLES API");
return false;
}
const EGLint requestConfig[] = {
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 5,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, 1,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLConfig config;
EGLint numConfigs;
if (EGL_FALSE == eglChooseConfig(renderer->display, requestConfig, &config, 1, &numConfigs)) {
printf("Failed to choose EGL config\n");
return false;
}
const EGLint contextAttributes[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
int dispWidth = 240, dispHeight = 160, adjWidth;
renderer->context = eglCreateContext(renderer->display, config, EGL_NO_CONTEXT, contextAttributes);
graphics_get_display_size(0, &dispWidth, &dispHeight);
adjWidth = dispHeight / 2 * 3;
DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
VC_RECT_T destRect = {
.x = (dispWidth - adjWidth) / 2,
.y = 0,
.width = adjWidth,
.height = dispHeight
};
VC_RECT_T srcRect = {
.x = 0,
.y = 0,
.width = 240 << 16,
.height = 160 << 16
};
DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
vc_dispmanx_update_submit_sync(update);
renderer->window.element = element;
renderer->window.width = dispWidth;
renderer->window.height = dispHeight;
renderer->surface = eglCreateWindowSurface(renderer->display, config, &renderer->window, 0);
if (EGL_FALSE == eglMakeCurrent(renderer->display, renderer->surface, renderer->surface, renderer->context)) {
return false;
}
#else #else
mSDLGLCommonInit(renderer); mSDLGLCommonInit(renderer);
#endif #endif
@ -112,7 +48,11 @@ bool mSDLGLES2Init(struct mSDLRenderer* renderer) {
renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio; renderer->gl2.d.lockAspectRatio = renderer->lockAspectRatio;
renderer->gl2.d.lockIntegerScaling = renderer->lockIntegerScaling; renderer->gl2.d.lockIntegerScaling = renderer->lockIntegerScaling;
renderer->gl2.d.filter = renderer->filter; renderer->gl2.d.filter = renderer->filter;
#ifdef BUILD_RASPI
renderer->gl2.d.swap = mRPIGLCommonSwap;
#else
renderer->gl2.d.swap = mSDLGLCommonSwap; renderer->gl2.d.swap = mSDLGLCommonSwap;
#endif
renderer->gl2.d.init(&renderer->gl2.d, 0); renderer->gl2.d.init(&renderer->gl2.d, 0);
renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height); renderer->gl2.d.setDimensions(&renderer->gl2.d, renderer->width, renderer->height);
@ -147,11 +87,7 @@ void mSDLGLES2Runloop(struct mSDLRenderer* renderer, void* user) {
} }
mCoreSyncWaitFrameEnd(&context->impl->sync); mCoreSyncWaitFrameEnd(&context->impl->sync);
v->drawFrame(v); v->drawFrame(v);
#ifdef BUILD_RASPI
eglSwapBuffers(renderer->display, renderer->surface);
#else
v->swap(v); v->swap(v);
#endif
} }
} }
@ -160,10 +96,10 @@ void mSDLGLES2Deinit(struct mSDLRenderer* renderer) {
renderer->gl2.d.deinit(&renderer->gl2.d); renderer->gl2.d.deinit(&renderer->gl2.d);
} }
#ifdef BUILD_RASPI #ifdef BUILD_RASPI
eglMakeCurrent(renderer->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglMakeCurrent(renderer->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(renderer->display, renderer->surface); eglDestroySurface(renderer->eglDisplay, renderer->eglSurface);
eglDestroyContext(renderer->display, renderer->context); eglDestroyContext(renderer->eglDisplay, renderer->eglContext);
eglTerminate(renderer->display); eglTerminate(renderer->eglDisplay);
bcm_host_deinit(); bcm_host_deinit();
#elif SDL_VERSION_ATLEAST(2, 0, 0) #elif SDL_VERSION_ATLEAST(2, 0, 0)
SDL_GL_DeleteContext(renderer->glCtx); SDL_GL_DeleteContext(renderer->glCtx);

View File

@ -81,10 +81,10 @@ struct mSDLRenderer {
#endif #endif
#ifdef BUILD_RASPI #ifdef BUILD_RASPI
EGLDisplay display; EGLDisplay eglDisplay;
EGLSurface surface; EGLSurface eglSurface;
EGLContext context; EGLContext eglContext;
EGL_DISPMANX_WINDOW_T window; EGL_DISPMANX_WINDOW_T eglWindow;
#endif #endif
#ifdef BUILD_PANDORA #ifdef BUILD_PANDORA

View File

@ -0,0 +1,84 @@
/* Copyright (c) 2013-2015 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/. */
#include "main.h"
#include <mgba/core/version.h>
void mRPIGLCommonSwap(struct VideoBackend* context) {
struct mSDLRenderer* renderer = (struct mSDLRenderer*) context->user;
eglSwapBuffers(renderer->eglDisplay, renderer->eglSurface);
}
void mRPIGLCommonInit(struct mSDLRenderer* renderer) {
bcm_host_init();
renderer->eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
int major, minor;
if (EGL_FALSE == eglInitialize(renderer->eglDisplay, &major, &minor)) {
printf("Failed to initialize EGL");
return false;
}
if (EGL_FALSE == eglBindAPI(EGL_OPENGL_ES_API)) {
printf("Failed to get GLES API");
return false;
}
const EGLint requestConfig[] = {
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 5,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, 1,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLConfig config;
EGLint numConfigs;
if (EGL_FALSE == eglChooseConfig(renderer->eglDisplay, requestConfig, &config, 1, &numConfigs)) {
printf("Failed to choose EGL config\n");
return false;
}
const EGLint contextAttributes[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
int dispWidth = 240, dispHeight = 160, adjWidth;
renderer->eglContext = eglCreateContext(renderer->eglDisplay, config, EGL_NO_CONTEXT, contextAttributes);
graphics_get_display_size(0, &dispWidth, &dispHeight);
adjWidth = dispHeight / 2 * 3;
DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(0);
DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
VC_RECT_T destRect = {
.x = (dispWidth - adjWidth) / 2,
.y = 0,
.width = adjWidth,
.height = dispHeight
};
VC_RECT_T srcRect = {
.x = 0,
.y = 0,
.width = 240 << 16,
.height = 160 << 16
};
DISPMANX_ELEMENT_HANDLE_T element = vc_dispmanx_element_add(update, display, 0, &destRect, 0, &srcRect, DISPMANX_PROTECTION_NONE, 0, 0, 0);
vc_dispmanx_update_submit_sync(update);
renderer->eglWindow.element = element;
renderer->eglWindow.width = dispWidth;
renderer->eglWindow.height = dispHeight;
renderer->eglSurface = eglCreateWindowSurface(renderer->eglDisplay, config, &renderer->eglWindow, 0);
if (EGL_FALSE == eglMakeCurrent(renderer->eglDisplay, renderer->eglSurface, renderer->eglSurface, renderer->eglContext)) {
return false;
}
}

View File

@ -0,0 +1,20 @@
/* Copyright (c) 2013-2015 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 SDL_RPI_COMMON_H
#define SDL_RPI_COMMON_H
#include <mgba-util/common.h>
CXX_GUARD_START
#include "main.h"
void mRPIGLCommonSwap(struct VideoBackend* context);
void mRPIGLCommonInit(struct mSDLRenderer* renderer);
CXX_GUARD_END
#endif

View File

@ -1,14 +1,4 @@
if(DEFINED ENV{DEVKITPRO}) include(${CMAKE_CURRENT_LIST_DIR}/../cmake/devkitPro.cmake)
set(DEVKITPRO $ENV{DEVKITPRO})
else()
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
endif()
if(DEFINED ENV{DEVKITA64})
set(DEVKITA64 $ENV{DEVKITA64})
else()
set(DEVKITA64 ${DEVKITPRO}/devkitA64)
endif()
if(DEFINED ENV{LIBNX}) if(DEFINED ENV{LIBNX})
set(LIBNX $ENV{LIBNX}) set(LIBNX $ENV{LIBNX})
@ -16,41 +6,17 @@ else()
set(LIBNX ${DEVKITPRO}/libnx) set(LIBNX ${DEVKITPRO}/libnx)
endif() endif()
set(extension)
if (CMAKE_HOST_WIN32)
set(extension .exe)
endif()
set(CMAKE_PROGRAM_PATH ${DEVKITA64}/bin)
set(cross_prefix aarch64-none-elf-) set(cross_prefix aarch64-none-elf-)
set(arch_flags "-mtune=cortex-a57 -ffunction-sections -march=armv8-a -mtp=soft -fPIC -ftls-model=local-exec") set(arch_flags "-mtune=cortex-a57 -ffunction-sections -march=armv8-a -mtp=soft -fPIC -ftls-model=local-exec")
set(inc_flags "-I${LIBNX}/include ${arch_flags}") set(inc_flags "-I${LIBNX}/include ${arch_flags}")
set(link_flags "-L${LIBNX}/lib -lnx -specs=${LIBNX}/switch.specs ${arch_flags}") set(link_flags "-L${LIBNX}/lib -lnx -specs=${LIBNX}/switch.specs ${arch_flags}")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR aarch64 CACHE INTERNAL "processor") set(CMAKE_SYSTEM_PROCESSOR aarch64 CACHE INTERNAL "processor")
set(CMAKE_LIBRARY_ARCHITECTURE aarch64-none-elf CACHE INTERNAL "abi") set(CMAKE_LIBRARY_ARCHITECTURE aarch64-none-elf CACHE INTERNAL "abi")
find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension})
find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension})
find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")
SET(CMAKE_ASM_COMPILE_OBJECT "<CMAKE_ASM_COMPILER> <DEFINES> <FLAGS> -o <OBJECT> -c <SOURCE>")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM}/aarch64-none-elf ${DEVKITPRO}/portlibs/switch)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")
set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE)
set(SWITCH ON) set(SWITCH ON)
add_definitions(-D__SWITCH__) add_definitions(-D__SWITCH__)
create_devkit(A64)
set(CMAKE_FIND_ROOT_PATH ${DEVKITA64}/${CMAKE_LIBRARY_ARCHITECTURE} ${DEVKITPRO}/portlibs/switch)

View File

@ -1,49 +1,16 @@
if(DEFINED ENV{DEVKITPRO}) include(${CMAKE_CURRENT_LIST_DIR}/../cmake/devkitPro.cmake)
set(DEVKITPRO $ENV{DEVKITPRO})
else()
message(FATAL_ERROR "Could not find DEVKITPRO in environment")
endif()
if(DEFINED ENV{DEVKITPPC})
set(DEVKITPPC $ENV{DEVKITPPC})
else()
set(DEVKITPPC ${DEVKITPRO}/devkitPPC)
endif()
set(extension)
if (CMAKE_HOST_WIN32)
set(extension .exe)
endif()
set(CMAKE_PROGRAM_PATH ${DEVKITPPC}/bin)
set(cross_prefix powerpc-eabi-) set(cross_prefix powerpc-eabi-)
set(arch_flags "-mrvl -mcpu=750 -meabi -mhard-float -g") set(arch_flags "-mrvl -mcpu=750 -meabi -mhard-float -g")
set(inc_flags "-I${DEVKITPRO}/libogc/include ${arch_flags}") set(inc_flags "-I${DEVKITPRO}/libogc/include ${arch_flags}")
set(link_flags "-L${DEVKITPRO}/libogc/lib/wii ${arch_flags}") set(link_flags "-L${DEVKITPRO}/libogc/lib/wii ${arch_flags}")
set(CMAKE_SYSTEM_NAME Generic CACHE INTERNAL "system name")
set(CMAKE_SYSTEM_PROCESSOR powerpc CACHE INTERNAL "processor") set(CMAKE_SYSTEM_PROCESSOR powerpc CACHE INTERNAL "processor")
set(CMAKE_LIBRARY_ARCHITECTURE powerpc-none-eabi CACHE INTERNAL "abi") set(CMAKE_LIBRARY_ARCHITECTURE powerpc-none-eabi CACHE INTERNAL "abi")
find_program(CMAKE_AR ${cross_prefix}gcc-ar${extension})
find_program(CMAKE_RANLIB ${cross_prefix}gcc-ranlib${extension})
find_program(CMAKE_C_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_CXX_COMPILER ${cross_prefix}g++${extension})
find_program(CMAKE_ASM_COMPILER ${cross_prefix}gcc${extension})
find_program(CMAKE_LINKER ${cross_prefix}ld${extension})
set(CMAKE_C_FLAGS ${inc_flags} CACHE INTERNAL "c compiler flags")
set(CMAKE_ASM_FLAGS ${inc_flags} CACHE INTERNAL "assembler flags")
set(CMAKE_CXX_FLAGS ${inc_flags} CACHE INTERNAL "cxx compiler flags")
set(CMAKE_EXE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "exe link flags")
set(CMAKE_MODULE_LINKER_FLAGS ${link_flags} CACHE INTERNAL "module link flags")
set(CMAKE_SHARED_LINKER_FLAGS ${link_flags} CACHE INTERNAL "shared link flags")
set(CMAKE_FIND_ROOT_PATH ${DEVKITPPC}/powerpc-eabi ${DEVKITPRO}/portlibs/ppc)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY CACHE INTERNAL "")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY CACHE INTERNAL "")
set(PKG_CONFIG_EXECUTABLE "/dev/null" CACHE INTERNAL "" FORCE)
set(WII ON) set(WII ON)
add_definitions(-DGEKKO) add_definitions(-DGEKKO)
create_devkit(PPC)
set(CMAKE_FIND_ROOT_PATH ${DEVKITPPC}/powerpc-eabi ${DEVKITPRO}/portlibs/ppc)

View File

@ -25,8 +25,8 @@ size_t RingFIFOCapacity(const struct RingFIFO* buffer) {
size_t RingFIFOSize(const struct RingFIFO* buffer) { size_t RingFIFOSize(const struct RingFIFO* buffer) {
const void* read; const void* read;
const void* write; const void* write;
ATOMIC_LOAD(read, buffer->readPtr); ATOMIC_LOAD_PTR(read, buffer->readPtr);
ATOMIC_LOAD(write, buffer->writePtr); ATOMIC_LOAD_PTR(write, buffer->writePtr);
if (read <= write) { if (read <= write) {
return (uintptr_t) write - (uintptr_t) read; return (uintptr_t) write - (uintptr_t) read;
} else { } else {
@ -35,14 +35,14 @@ size_t RingFIFOSize(const struct RingFIFO* buffer) {
} }
void RingFIFOClear(struct RingFIFO* buffer) { void RingFIFOClear(struct RingFIFO* buffer) {
ATOMIC_STORE(buffer->readPtr, buffer->data); ATOMIC_STORE_PTR(buffer->readPtr, buffer->data);
ATOMIC_STORE(buffer->writePtr, buffer->data); ATOMIC_STORE_PTR(buffer->writePtr, buffer->data);
} }
size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) { size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length) {
void* data = buffer->writePtr; void* data = buffer->writePtr;
void* end; void* end;
ATOMIC_LOAD(end, buffer->readPtr); ATOMIC_LOAD_PTR(end, buffer->readPtr);
// Wrap around if we can't fit enough in here // Wrap around if we can't fit enough in here
if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) { if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) {
@ -67,14 +67,14 @@ size_t RingFIFOWrite(struct RingFIFO* buffer, const void* value, size_t length)
if (value) { if (value) {
memcpy(data, value, length); memcpy(data, value, length);
} }
ATOMIC_STORE(buffer->writePtr, (void*) ((intptr_t) data + length)); ATOMIC_STORE_PTR(buffer->writePtr, (void*) ((intptr_t) data + length));
return length; return length;
} }
size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) { size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) {
void* data = buffer->readPtr; void* data = buffer->readPtr;
void* end; void* end;
ATOMIC_LOAD(end, buffer->writePtr); ATOMIC_LOAD_PTR(end, buffer->writePtr);
// Wrap around if we can't fit enough in here // Wrap around if we can't fit enough in here
if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) { if ((uintptr_t) data - (uintptr_t) buffer->data + length >= buffer->capacity) {
@ -99,6 +99,6 @@ size_t RingFIFORead(struct RingFIFO* buffer, void* output, size_t length) {
if (output) { if (output) {
memcpy(output, data, length); memcpy(output, data, length);
} }
ATOMIC_STORE(buffer->readPtr, (void*) ((uintptr_t) data + length)); ATOMIC_STORE_PTR(buffer->readPtr, (void*) ((uintptr_t) data + length));
return length; return length;
} }

View File

@ -18,7 +18,7 @@
#define M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, _testSuite_setup_ ## NAME, _testSuite_teardown_ ## NAME, __VA_ARGS__) #define M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(NAME, ...) M_TEST_SUITE_DEFINE_EX(NAME, _testSuite_setup_ ## NAME, _testSuite_teardown_ ## NAME, __VA_ARGS__)
#define M_TEST_SUITE_DEFINE_EX(NAME, SETUP, TEARDOWN, ...) \ #define M_TEST_SUITE_DEFINE_EX(NAME, SETUP, TEARDOWN, ...) \
int main(void) { \ int main(void) { \
const static struct CMUnitTest tests[] = { \ static const struct CMUnitTest tests[] = { \
__VA_ARGS__ \ __VA_ARGS__ \
}; \ }; \
return cmocka_run_group_tests_name(# NAME, tests, SETUP, TEARDOWN); \ return cmocka_run_group_tests_name(# NAME, tests, SETUP, TEARDOWN); \