From 9a192d9ab10ee88990dd7a8942be489aca8fa272 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 3 Apr 2021 00:32:48 -0700 Subject: [PATCH 01/10] GBA Memory: Remove unused variable --- src/gba/memory.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gba/memory.c b/src/gba/memory.c index 25d8a6a68..05cec7c67 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -930,7 +930,6 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle if ((address & 0x00FFFFFF) >= AGB_PRINT_BASE) { uint32_t agbPrintAddr = address & 0x00FFFFFF; if (agbPrintAddr == AGB_PRINT_PROTECT) { - bool wasProtected = memory->agbPrintProtect != 0x20; memory->agbPrintProtect = value; if (!memory->agbPrintBuffer) { From bc16a1bfe33e26f9d781bf5de01fe94cc5293689 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 3 Apr 2021 01:18:23 -0700 Subject: [PATCH 02/10] GBA Cart: Refactor hardware.c into cart/gpio.c etc --- .../internal/gba/{hardware.h => cart/gpio.h} | 71 +------- include/mgba/internal/gba/{ => cart}/matrix.h | 0 include/mgba/internal/gba/{ => cart}/vfame.h | 0 include/mgba/internal/gba/memory.h | 6 +- include/mgba/internal/gba/sio.h | 5 +- include/mgba/internal/gba/sio/gbp.h | 37 ++++ src/gba/CMakeLists.txt | 11 +- src/gba/{ => cart}/ereader.c | 2 +- src/gba/{hardware.c => cart/gpio.c} | 164 ++---------------- src/gba/{ => cart}/matrix.c | 2 +- src/gba/{ => cart}/vfame.c | 2 +- src/gba/gba.c | 4 +- src/gba/overrides.c | 2 +- src/gba/sio.c | 7 + src/gba/sio/gbp.c | 148 ++++++++++++++++ 15 files changed, 230 insertions(+), 231 deletions(-) rename include/mgba/internal/gba/{hardware.h => cart/gpio.h} (63%) rename include/mgba/internal/gba/{ => cart}/matrix.h (100%) rename include/mgba/internal/gba/{ => cart}/vfame.h (100%) create mode 100644 include/mgba/internal/gba/sio/gbp.h rename src/gba/{ => cart}/ereader.c (99%) rename src/gba/{hardware.c => cart/gpio.c} (73%) rename src/gba/{ => cart}/matrix.c (98%) rename src/gba/{ => cart}/vfame.c (99%) create mode 100644 src/gba/sio/gbp.c diff --git a/include/mgba/internal/gba/hardware.h b/include/mgba/internal/gba/cart/gpio.h similarity index 63% rename from include/mgba/internal/gba/hardware.h rename to include/mgba/internal/gba/cart/gpio.h index 88ae5c29b..93fd359bd 100644 --- a/include/mgba/internal/gba/hardware.h +++ b/include/mgba/internal/gba/cart/gpio.h @@ -13,13 +13,10 @@ CXX_GUARD_START #include #include #include +#include mLOG_DECLARE_CATEGORY(GBA_HW); -#define EREADER_DOTCODE_STRIDE 1420 -#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40) -#define EREADER_CARDS_MAX 16 - #define IS_GPIO_REGISTER(reg) ((reg) == GPIO_REG_DATA || (reg) == GPIO_REG_DIRECTION || (reg) == GPIO_REG_CONTROL) struct GBARTCGenericSource { @@ -82,57 +79,8 @@ struct GBARTC { uint8_t time[7]; }; -struct GBAGBPKeyCallback { - struct mKeyCallback d; - struct GBACartridgeHardware* p; -}; - -struct GBAGBPSIODriver { - struct GBASIODriver d; - struct GBACartridgeHardware* p; -}; - DECL_BITFIELD(GPIOPin, uint16_t); -DECL_BITFIELD(EReaderControl0, uint8_t); -DECL_BIT(EReaderControl0, Data, 0); -DECL_BIT(EReaderControl0, Clock, 1); -DECL_BIT(EReaderControl0, Direction, 2); -DECL_BIT(EReaderControl0, LedEnable, 3); -DECL_BIT(EReaderControl0, Scan, 4); -DECL_BIT(EReaderControl0, Phi, 5); -DECL_BIT(EReaderControl0, PowerEnable, 6); -DECL_BITFIELD(EReaderControl1, uint8_t); -DECL_BIT(EReaderControl1, Scanline, 1); -DECL_BIT(EReaderControl1, Unk1, 4); -DECL_BIT(EReaderControl1, Voltage, 5); - -enum EReaderStateMachine { - EREADER_SERIAL_INACTIVE = 0, - EREADER_SERIAL_STARTING, - EREADER_SERIAL_BIT_0, - EREADER_SERIAL_BIT_1, - EREADER_SERIAL_BIT_2, - EREADER_SERIAL_BIT_3, - EREADER_SERIAL_BIT_4, - EREADER_SERIAL_BIT_5, - EREADER_SERIAL_BIT_6, - EREADER_SERIAL_BIT_7, - EREADER_SERIAL_END_BIT, -}; - -enum EReaderCommand { - EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware - EREADER_COMMAND_WRITE_DATA = 1, - EREADER_COMMAND_SET_INDEX = 0x22, - EREADER_COMMAND_READ_DATA = 0x23, -}; - -struct EReaderCard { - void* data; - size_t size; -}; - struct GBACartridgeHardware { struct GBA* p; uint32_t devices; @@ -155,12 +103,6 @@ struct GBACartridgeHardware { uint16_t tiltY; int tiltState; - unsigned gbpInputsPosted; - int gbpTxPosition; - struct mTimingEvent gbpNextEvent; - struct GBAGBPKeyCallback gbpCallback; - struct GBAGBPSIODriver gbpDriver; - uint16_t eReaderData[44]; uint8_t eReaderSerial[92]; uint16_t eReaderRegisterUnk; @@ -193,17 +135,6 @@ void GBAHardwareGPIOWrite(struct GBACartridgeHardware* gpio, uint32_t address, u void GBAHardwareTiltWrite(struct GBACartridgeHardware* gpio, uint32_t address, uint8_t value); uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* gpio, uint32_t address); -struct GBAVideo; -void GBAHardwarePlayerUpdate(struct GBA* gba); -bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video); - -void GBAHardwareInitEReader(struct GBACartridgeHardware* hw); -void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value); -void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value); -uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address); -uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address); -void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size); - void GBARTCGenericSourceInit(struct GBARTCGenericSource* rtc, struct GBA* gba); struct GBASerializedState; diff --git a/include/mgba/internal/gba/matrix.h b/include/mgba/internal/gba/cart/matrix.h similarity index 100% rename from include/mgba/internal/gba/matrix.h rename to include/mgba/internal/gba/cart/matrix.h diff --git a/include/mgba/internal/gba/vfame.h b/include/mgba/internal/gba/cart/vfame.h similarity index 100% rename from include/mgba/internal/gba/vfame.h rename to include/mgba/internal/gba/cart/vfame.h diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index caf1d689b..fac001de4 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -14,10 +14,10 @@ CXX_GUARD_START #include #include -#include #include -#include -#include +#include +#include +#include enum GBAMemoryRegion { REGION_BIOS = 0x0, diff --git a/include/mgba/internal/gba/sio.h b/include/mgba/internal/gba/sio.h index 2c06af698..e0fca7812 100644 --- a/include/mgba/internal/gba/sio.h +++ b/include/mgba/internal/gba/sio.h @@ -10,8 +10,9 @@ CXX_GUARD_START -#include #include +#include +#include #define MAX_GBAS 4 @@ -69,6 +70,8 @@ struct GBASIO { uint16_t rcnt; uint16_t siocnt; + + struct GBASIOPlayer gbp; }; void GBASIOInit(struct GBASIO* sio); diff --git a/include/mgba/internal/gba/sio/gbp.h b/include/mgba/internal/gba/sio/gbp.h new file mode 100644 index 000000000..f9ab6beaf --- /dev/null +++ b/include/mgba/internal/gba/sio/gbp.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-2021 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 GBA_GBP_H +#define GBA_GBP_H + +#include + +CXX_GUARD_START + +struct GBASIOPlayer; +struct GBASIOPlayerKeyCallback { + struct mKeyCallback d; + struct GBASIOPlayer* p; +}; + +struct GBASIOPlayer { + struct GBASIODriver d; + struct GBA* p; + unsigned inputsPosted; + int txPosition; + struct mTimingEvent event; + struct GBASIOPlayerKeyCallback callback; +}; + +void GBASIOPlayerInit(struct GBASIOPlayer* gbp); +void GBASIOPlayerReset(struct GBASIOPlayer* gbp); + +struct GBAVideo; +void GBASIOPlayerUpdate(struct GBA* gba); +bool GBASIOPlayerCheckScreen(const struct GBAVideo* video); + +CXX_GUARD_END + +#endif diff --git a/src/gba/CMakeLists.txt b/src/gba/CMakeLists.txt index ba9c298dc..4bf354f3a 100644 --- a/src/gba/CMakeLists.txt +++ b/src/gba/CMakeLists.txt @@ -3,19 +3,20 @@ set(SOURCE_FILES ../gb/audio.c audio.c bios.c + cart/ereader.c + cart/gpio.c + cart/matrix.c + cart/vfame.c cheats.c cheats/codebreaker.c cheats/gameshark.c cheats/parv3.c core.c dma.c - ereader.c gba.c - hardware.c hle-bios.c input.c io.c - matrix.c memory.c overrides.c renderers/cache-set.c @@ -29,13 +30,13 @@ set(SOURCE_FILES serialize.c sharkport.c sio.c + sio/gbp.c + sio/joybus.c timer.c - vfame.c video.c) set(SIO_FILES sio/dolphin.c - sio/joybus.c sio/lockstep.c) set(EXTRA_FILES diff --git a/src/gba/ereader.c b/src/gba/cart/ereader.c similarity index 99% rename from src/gba/ereader.c rename to src/gba/cart/ereader.c index c50ae5a97..d79bd8dbb 100644 --- a/src/gba/ereader.c +++ b/src/gba/cart/ereader.c @@ -4,7 +4,7 @@ * 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 +#include #include #include diff --git a/src/gba/hardware.c b/src/gba/cart/gpio.c similarity index 73% rename from src/gba/hardware.c rename to src/gba/cart/gpio.c index 2629228af..92196b243 100644 --- a/src/gba/hardware.c +++ b/src/gba/cart/gpio.c @@ -1,9 +1,9 @@ -/* Copyright (c) 2013-2015 Jeffrey Pfau +/* Copyright (c) 2013-2021 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 +#include #include #include @@ -33,10 +33,6 @@ static void _rumbleReadPins(struct GBACartridgeHardware* hw); static void _lightReadPins(struct GBACartridgeHardware* hw); -static uint16_t _gbpRead(struct mKeyCallback*); -static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); -static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate); - static const int RTC_BYTES[8] = { 0, // Force reset 0, // Empty @@ -53,19 +49,6 @@ void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) { hw->eReaderDots = NULL; memset(hw->eReaderCards, 0, sizeof(hw->eReaderCards)); GBAHardwareClear(hw); - - hw->gbpCallback.d.readKeys = _gbpRead; - hw->gbpCallback.p = hw; - hw->gbpDriver.d.init = 0; - hw->gbpDriver.d.deinit = 0; - hw->gbpDriver.d.load = 0; - hw->gbpDriver.d.unload = 0; - hw->gbpDriver.d.writeRegister = _gbpSioWriteRegister; - hw->gbpDriver.p = hw; - hw->gbpNextEvent.context = &hw->gbpDriver; - hw->gbpNextEvent.name = "GBA SIO Game Boy Player"; - hw->gbpNextEvent.callback = _gbpSioProcessEvents; - hw->gbpNextEvent.priority = 0x80; } void GBAHardwareClear(struct GBACartridgeHardware* hw) { @@ -87,10 +70,6 @@ void GBAHardwareClear(struct GBACartridgeHardware* hw) { hw->eReaderCards[i].data = NULL; hw->eReaderCards[i].size = 0; } - - if (hw->p->sio.drivers.normal == &hw->gbpDriver.d) { - GBASIOSetDriver(&hw->p->sio, 0, SIO_NORMAL_32); - } } void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) { @@ -504,124 +483,10 @@ uint8_t GBAHardwareTiltRead(struct GBACartridgeHardware* hw, uint32_t address) { return 0xFF; } -// == Game Boy Player - -static const uint8_t _logoPalette[] = { - 0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68, - 0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED, - 0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72, - 0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B, - 0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F, - 0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2, - 0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF, - 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const uint32_t _logoHash = 0xEEDA6963; - -static const uint32_t _gbpTxData[] = { - 0x0000494E, 0x0000494E, - 0xB6B1494E, 0xB6B1544E, - 0xABB1544E, 0xABB14E45, - 0xB1BA4E45, 0xB1BA4F44, - 0xB0BB4F44, 0xB0BB8002, - 0x10000010, 0x20000013, - 0x30000003 -}; - -bool GBAHardwarePlayerCheckScreen(const struct GBAVideo* video) { - if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) { - return false; - } - uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0); - return hash == _logoHash; -} - -void GBAHardwarePlayerUpdate(struct GBA* gba) { - if (gba->memory.hw.devices & HW_GB_PLAYER) { - if (GBAHardwarePlayerCheckScreen(&gba->video)) { - ++gba->memory.hw.gbpInputsPosted; - gba->memory.hw.gbpInputsPosted %= 3; - gba->keyCallback = &gba->memory.hw.gbpCallback.d; - } else { - // TODO: Save and restore - gba->keyCallback = 0; - } - gba->memory.hw.gbpTxPosition = 0; - return; - } - if (gba->keyCallback) { - return; - } - if (GBAHardwarePlayerCheckScreen(&gba->video)) { - gba->memory.hw.devices |= HW_GB_PLAYER; - gba->memory.hw.gbpInputsPosted = 0; - gba->keyCallback = &gba->memory.hw.gbpCallback.d; - // TODO: Check if the SIO driver is actually used first - GBASIOSetDriver(&gba->sio, &gba->memory.hw.gbpDriver.d, SIO_NORMAL_32); - } -} - -uint16_t _gbpRead(struct mKeyCallback* callback) { - struct GBAGBPKeyCallback* gbpCallback = (struct GBAGBPKeyCallback*) callback; - if (gbpCallback->p->gbpInputsPosted == 2) { - return 0xF0; - } - return 0; -} - -uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { - struct GBAGBPSIODriver* gbp = (struct GBAGBPSIODriver*) driver; - if (address == REG_SIOCNT) { - if (value & 0x0080) { - uint32_t rx = gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] << 16); - if (gbp->p->gbpTxPosition < 12 && gbp->p->gbpTxPosition > 0) { - // TODO: Check expected - } else if (gbp->p->gbpTxPosition >= 12) { - uint32_t mask = 0x33; - // 0x00 = Stop - // 0x11 = Hard Stop - // 0x22 = Start - if (gbp->p->p->rumble) { - gbp->p->p->rumble->setRumble(gbp->p->p->rumble, (rx & mask) == 0x22); - } - } - mTimingDeschedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent); - mTimingSchedule(&gbp->p->p->timing, &gbp->p->gbpNextEvent, 2048); - } - value &= 0x78FB; - } - return value; -} - -void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { - UNUSED(timing); - UNUSED(cyclesLate); - struct GBAGBPSIODriver* gbp = user; - uint32_t tx = 0; - int txPosition = gbp->p->gbpTxPosition; - if (txPosition > 16) { - gbp->p->gbpTxPosition = 0; - txPosition = 0; - } else if (txPosition > 12) { - txPosition = 12; - } - tx = _gbpTxData[txPosition]; - ++gbp->p->gbpTxPosition; - gbp->p->p->memory.io[REG_SIODATA32_LO >> 1] = tx; - gbp->p->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; - if (GBASIONormalIsIrq(gbp->d.p->siocnt)) { - GBARaiseIRQ(gbp->p->p, IRQ_SIO, cyclesLate); - } - gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt); - gbp->p->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080; -} - // == Serialization void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASerializedState* state) { GBASerializedHWFlags1 flags1 = 0; - GBASerializedHWFlags2 flags2 = 0; flags1 = GBASerializedHWFlags1SetReadWrite(flags1, hw->readWrite); STORE_16(hw->pinState, 0, &state->hw.pinState); STORE_16(hw->direction, 0, &state->hw.pinDirection); @@ -640,14 +505,19 @@ void GBAHardwareSerialize(const struct GBACartridgeHardware* hw, struct GBASeria flags1 = GBASerializedHWFlags1SetGyroEdge(flags1, hw->gyroEdge); STORE_16(hw->tiltX, 0, &state->hw.tiltSampleX); STORE_16(hw->tiltY, 0, &state->hw.tiltSampleY); - flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); - flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); state->hw.lightSample = hw->lightSample; flags1 = GBASerializedHWFlags1SetLightEdge(flags1, hw->lightEdge); - flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->gbpInputsPosted); - flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->gbpTxPosition); - STORE_32(hw->gbpNextEvent.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent); STORE_16(flags1, 0, &state->hw.flags1); + + GBASerializedHWFlags2 flags2 = 0; + flags2 = GBASerializedHWFlags2SetTiltState(flags2, hw->tiltState); + flags2 = GBASerializedHWFlags1SetLightCounter(flags2, hw->lightCounter); + + // GBP stuff is only here for legacy reasons + flags2 = GBASerializedHWFlags2SetGbpInputsPosted(flags2, hw->p->sio.gbp.inputsPosted); + flags2 = GBASerializedHWFlags2SetGbpTxPosition(flags2, hw->p->sio.gbp.txPosition); + STORE_32(hw->p->sio.gbp.event.when - mTimingCurrentTime(&hw->p->timing), 0, &state->hw.gbpNextEvent); + state->hw.flags2 = flags2; } @@ -676,15 +546,17 @@ void GBAHardwareDeserialize(struct GBACartridgeHardware* hw, const struct GBASer hw->lightCounter = GBASerializedHWFlags1GetLightCounter(flags1); hw->lightSample = state->hw.lightSample; hw->lightEdge = GBASerializedHWFlags1GetLightEdge(flags1); - hw->gbpInputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); - hw->gbpTxPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); + + // GBP stuff is only here for legacy reasons + hw->p->sio.gbp.inputsPosted = GBASerializedHWFlags2GetGbpInputsPosted(state->hw.flags2); + hw->p->sio.gbp.txPosition = GBASerializedHWFlags2GetGbpTxPosition(state->hw.flags2); uint32_t when; LOAD_32(when, 0, &state->hw.gbpNextEvent); if (hw->devices & HW_GB_PLAYER) { - GBASIOSetDriver(&hw->p->sio, &hw->gbpDriver.d, SIO_NORMAL_32); + GBASIOSetDriver(&hw->p->sio, &hw->p->sio.gbp.d, SIO_NORMAL_32); if (hw->p->memory.io[REG_SIOCNT >> 1] & 0x0080) { - mTimingSchedule(&hw->p->timing, &hw->gbpNextEvent, when); + mTimingSchedule(&hw->p->timing, &hw->p->sio.gbp.event, when); } } } diff --git a/src/gba/matrix.c b/src/gba/cart/matrix.c similarity index 98% rename from src/gba/matrix.c rename to src/gba/cart/matrix.c index fb72e052f..c594d66b9 100644 --- a/src/gba/matrix.c +++ b/src/gba/cart/matrix.c @@ -3,7 +3,7 @@ * 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 +#include #include #include diff --git a/src/gba/vfame.c b/src/gba/cart/vfame.c similarity index 99% rename from src/gba/vfame.c rename to src/gba/cart/vfame.c index 0ac834cc9..57b6d903b 100644 --- a/src/gba/vfame.c +++ b/src/gba/cart/vfame.c @@ -3,7 +3,7 @@ * 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 +#include #include #include diff --git a/src/gba/gba.c b/src/gba/gba.c index a328b55da..7e9d3d47a 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -219,7 +219,7 @@ void GBAReset(struct ARMCore* cpu) { // GB Player SIO control should not be engaged before detection, even if we already know it's GBP gba->memory.hw.devices &= ~HW_GB_PLAYER; - if (gba->sio.drivers.normal == &gba->memory.hw.gbpDriver.d) { + if (gba->sio.drivers.normal == &gba->sio.gbp.d) { GBASIOSetDriver(&gba->sio, NULL, SIO_NORMAL_32); } @@ -855,7 +855,7 @@ void GBAFrameEnded(struct GBA* gba) { } if (gba->memory.hw.devices & (HW_GB_PLAYER | HW_GB_PLAYER_DETECTION)) { - GBAHardwarePlayerUpdate(gba); + GBASIOPlayerUpdate(gba); } size_t c; diff --git a/src/gba/overrides.c b/src/gba/overrides.c index a84ccd2de..86446fbab 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include diff --git a/src/gba/sio.c b/src/gba/sio.c index bf85f510f..8feaeb624 100644 --- a/src/gba/sio.c +++ b/src/gba/sio.c @@ -7,6 +7,7 @@ #include #include +#include mLOG_DEFINE_CATEGORY(GBA_SIO, "GBA Serial I/O", "gba.sio"); @@ -76,6 +77,10 @@ void GBASIOInit(struct GBASIO* sio) { sio->drivers.multiplayer = 0; sio->drivers.joybus = 0; sio->activeDriver = 0; + + sio->gbp.p = sio->p; + GBASIOPlayerInit(&sio->gbp); + GBASIOReset(sio); } @@ -103,6 +108,8 @@ void GBASIOReset(struct GBASIO* sio) { sio->mode = -1; sio->activeDriver = NULL; _switchMode(sio); + + GBASIOPlayerReset(&sio->gbp); } void GBASIOSetDriverSet(struct GBASIO* sio, struct GBASIODriverSet* drivers) { diff --git a/src/gba/sio/gbp.c b/src/gba/sio/gbp.c new file mode 100644 index 000000000..8ffafd1c8 --- /dev/null +++ b/src/gba/sio/gbp.c @@ -0,0 +1,148 @@ +/* Copyright (c) 2013-2021 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 + +#include +#include +#include +#include +#include +#include + +static uint16_t _gbpRead(struct mKeyCallback*); +static uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value); +static void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate); + +static const uint8_t _logoPalette[] = { + 0xDF, 0xFF, 0x0C, 0x64, 0x0C, 0xE4, 0x2D, 0xE4, 0x4E, 0x64, 0x4E, 0xE4, 0x6E, 0xE4, 0xAF, 0x68, + 0xB0, 0xE8, 0xD0, 0x68, 0xF0, 0x68, 0x11, 0x69, 0x11, 0xE9, 0x32, 0x6D, 0x32, 0xED, 0x73, 0xED, + 0x93, 0x6D, 0x94, 0xED, 0xB4, 0x6D, 0xD5, 0xF1, 0xF5, 0x71, 0xF6, 0xF1, 0x16, 0x72, 0x57, 0x72, + 0x57, 0xF6, 0x78, 0x76, 0x78, 0xF6, 0x99, 0xF6, 0xB9, 0xF6, 0xD9, 0x76, 0xDA, 0xF6, 0x1B, 0x7B, + 0x1B, 0xFB, 0x3C, 0xFB, 0x5C, 0x7B, 0x7D, 0x7B, 0x7D, 0xFF, 0x9D, 0x7F, 0xBE, 0x7F, 0xFF, 0x7F, + 0x2D, 0x64, 0x8E, 0x64, 0x8F, 0xE8, 0xF1, 0xE8, 0x52, 0x6D, 0x73, 0x6D, 0xB4, 0xF1, 0x16, 0xF2, + 0x37, 0x72, 0x98, 0x76, 0xFA, 0x7A, 0xFA, 0xFA, 0x5C, 0xFB, 0xBE, 0xFF, 0xDE, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const uint32_t _logoHash = 0xEEDA6963; + +static const uint32_t _gbpTxData[] = { + 0x0000494E, 0x0000494E, + 0xB6B1494E, 0xB6B1544E, + 0xABB1544E, 0xABB14E45, + 0xB1BA4E45, 0xB1BA4F44, + 0xB0BB4F44, 0xB0BB8002, + 0x10000010, 0x20000013, + 0x30000003 +}; + +void GBASIOPlayerInit(struct GBASIOPlayer* gbp) { + gbp->callback.d.readKeys = _gbpRead; + gbp->callback.p = gbp; + gbp->d.init = 0; + gbp->d.deinit = 0; + gbp->d.load = 0; + gbp->d.unload = 0; + gbp->d.writeRegister = _gbpSioWriteRegister; + gbp->event.context = gbp; + gbp->event.name = "GBA SIO Game Boy Player"; + gbp->event.callback = _gbpSioProcessEvents; + gbp->event.priority = 0x80; +} + +void GBASIOPlayerReset(struct GBASIOPlayer* gbp) { + if (gbp->p->sio.drivers.normal == &gbp->d) { + GBASIOSetDriver(&gbp->p->sio, NULL, SIO_NORMAL_32); + } +} + +bool GBASIOPlayerCheckScreen(const struct GBAVideo* video) { + if (memcmp(video->palette, _logoPalette, sizeof(_logoPalette)) != 0) { + return false; + } + uint32_t hash = hash32(&video->renderer->vram[0x4000], 0x4000, 0); + return hash == _logoHash; +} + +void GBASIOPlayerUpdate(struct GBA* gba) { + if (gba->memory.hw.devices & HW_GB_PLAYER) { + if (GBASIOPlayerCheckScreen(&gba->video)) { + ++gba->sio.gbp.inputsPosted; + gba->sio.gbp.inputsPosted %= 3; + gba->keyCallback = &gba->sio.gbp.callback.d; + } else { + // TODO: Save and restore + gba->keyCallback = 0; + } + gba->sio.gbp.txPosition = 0; + return; + } + if (gba->keyCallback) { + return; + } + if (GBASIOPlayerCheckScreen(&gba->video)) { + gba->memory.hw.devices |= HW_GB_PLAYER; + gba->sio.gbp.inputsPosted = 0; + gba->keyCallback = &gba->sio.gbp.callback.d; + // TODO: Check if the SIO driver is actually used first + GBASIOSetDriver(&gba->sio, &gba->sio.gbp.d, SIO_NORMAL_32); + } +} + +uint16_t _gbpRead(struct mKeyCallback* callback) { + struct GBASIOPlayerKeyCallback* gbpCallback = (struct GBASIOPlayerKeyCallback*) callback; + if (gbpCallback->p->inputsPosted == 2) { + return 0xF0; + } + return 0; +} + +uint16_t _gbpSioWriteRegister(struct GBASIODriver* driver, uint32_t address, uint16_t value) { + struct GBASIOPlayer* gbp = (struct GBASIOPlayer*) driver; + if (address == REG_SIOCNT) { + if (value & 0x0080) { + uint32_t rx = gbp->p->memory.io[REG_SIODATA32_LO >> 1] | (gbp->p->memory.io[REG_SIODATA32_HI >> 1] << 16); + if (gbp->txPosition < 12 && gbp->txPosition > 0) { + // TODO: Check expected + } else if (gbp->txPosition >= 12) { + uint32_t mask = 0x33; + // 0x00 = Stop + // 0x11 = Hard Stop + // 0x22 = Start + if (gbp->p->rumble) { + gbp->p->rumble->setRumble(gbp->p->rumble, (rx & mask) == 0x22); + } + } + mTimingDeschedule(&gbp->p->timing, &gbp->event); + mTimingSchedule(&gbp->p->timing, &gbp->event, 2048); + } + value &= 0x78FB; + } + return value; +} + +void _gbpSioProcessEvents(struct mTiming* timing, void* user, uint32_t cyclesLate) { + UNUSED(timing); + UNUSED(cyclesLate); + struct GBASIOPlayer* gbp = user; + uint32_t tx = 0; + int txPosition = gbp->txPosition; + if (txPosition > 16) { + gbp->txPosition = 0; + txPosition = 0; + } else if (txPosition > 12) { + txPosition = 12; + } + tx = _gbpTxData[txPosition]; + ++gbp->txPosition; + gbp->p->memory.io[REG_SIODATA32_LO >> 1] = tx; + gbp->p->memory.io[REG_SIODATA32_HI >> 1] = tx >> 16; + if (GBASIONormalIsIrq(gbp->d.p->siocnt)) { + GBARaiseIRQ(gbp->p, IRQ_SIO, cyclesLate); + } + gbp->d.p->siocnt = GBASIONormalClearStart(gbp->d.p->siocnt); + gbp->p->memory.io[REG_SIOCNT >> 1] = gbp->d.p->siocnt & ~0x0080; +} From 23b5a458b8b9d1f181fa93769ec57a04e098d751 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 3 Apr 2021 02:06:42 -0700 Subject: [PATCH 03/10] GBA e-Reader: Refactor out of GPIO code --- include/mgba/gba/interface.h | 2 +- include/mgba/internal/gba/cart/ereader.h | 90 +++++++ include/mgba/internal/gba/cart/gpio.h | 19 -- include/mgba/internal/gba/memory.h | 2 + src/gba/cart/ereader.c | 287 ++++++++++++----------- src/gba/cart/gpio.c | 16 -- src/gba/memory.c | 14 +- src/gba/overrides.c | 3 +- src/platform/qt/CoreController.cpp | 2 +- 9 files changed, 256 insertions(+), 179 deletions(-) create mode 100644 include/mgba/internal/gba/cart/ereader.h diff --git a/include/mgba/gba/interface.h b/include/mgba/gba/interface.h index aedd8895d..ff484bbc8 100644 --- a/include/mgba/gba/interface.h +++ b/include/mgba/gba/interface.h @@ -98,7 +98,7 @@ struct GBASIOBattlechipGate { void GBASIOBattlechipGateCreate(struct GBASIOBattlechipGate*); -void GBAEReaderQueueCard(struct GBA* gba, const void* data, size_t size); +void GBACartEReaderQueueCard(struct GBA* gba, const void* data, size_t size); CXX_GUARD_END diff --git a/include/mgba/internal/gba/cart/ereader.h b/include/mgba/internal/gba/cart/ereader.h new file mode 100644 index 000000000..0024d9ca0 --- /dev/null +++ b/include/mgba/internal/gba/cart/ereader.h @@ -0,0 +1,90 @@ +/* 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 GBA_EREADER_H +#define GBA_EREADER_H + +#include + +CXX_GUARD_START + +struct GBACartridgeHardware; + +#define EREADER_DOTCODE_STRIDE 1420 +#define EREADER_DOTCODE_SIZE (EREADER_DOTCODE_STRIDE * 40) +#define EREADER_CARDS_MAX 16 + +DECL_BITFIELD(EReaderControl0, uint8_t); +DECL_BIT(EReaderControl0, Data, 0); +DECL_BIT(EReaderControl0, Clock, 1); +DECL_BIT(EReaderControl0, Direction, 2); +DECL_BIT(EReaderControl0, LedEnable, 3); +DECL_BIT(EReaderControl0, Scan, 4); +DECL_BIT(EReaderControl0, Phi, 5); +DECL_BIT(EReaderControl0, PowerEnable, 6); +DECL_BITFIELD(EReaderControl1, uint8_t); +DECL_BIT(EReaderControl1, Scanline, 1); +DECL_BIT(EReaderControl1, Unk1, 4); +DECL_BIT(EReaderControl1, Voltage, 5); + +enum EReaderStateMachine { + EREADER_SERIAL_INACTIVE = 0, + EREADER_SERIAL_STARTING, + EREADER_SERIAL_BIT_0, + EREADER_SERIAL_BIT_1, + EREADER_SERIAL_BIT_2, + EREADER_SERIAL_BIT_3, + EREADER_SERIAL_BIT_4, + EREADER_SERIAL_BIT_5, + EREADER_SERIAL_BIT_6, + EREADER_SERIAL_BIT_7, + EREADER_SERIAL_END_BIT, +}; + +enum EReaderCommand { + EREADER_COMMAND_IDLE = 0, // TODO: Verify on hardware + EREADER_COMMAND_WRITE_DATA = 1, + EREADER_COMMAND_SET_INDEX = 0x22, + EREADER_COMMAND_READ_DATA = 0x23, +}; + +struct EReaderCard { + void* data; + size_t size; +}; + +struct GBA; +struct GBACartEReader { + struct GBA* p; + uint16_t data[44]; + uint8_t serial[92]; + uint16_t registerUnk; + uint16_t registerReset; + EReaderControl0 registerControl0; + EReaderControl1 registerControl1; + uint16_t registerLed; + + // TODO: Serialize these + enum EReaderStateMachine state; + enum EReaderCommand command; + uint8_t activeRegister; + uint8_t byte; + int scanX; + int scanY; + uint8_t* dots; + struct EReaderCard cards[EREADER_CARDS_MAX]; +}; + +void GBACartEReaderInit(struct GBACartEReader* ereader); +void GBACartEReaderDeinit(struct GBACartEReader* ereader); +void GBACartEReaderWrite(struct GBACartEReader* ereader, uint32_t address, uint16_t value); +void GBACartEReaderWriteFlash(struct GBACartEReader* ereader, uint32_t address, uint8_t value); +uint16_t GBACartEReaderRead(struct GBACartEReader* ereader, uint32_t address); +uint8_t GBACartEReaderReadFlash(struct GBACartEReader* ereader, uint32_t address); +void GBACartEReaderScan(struct GBACartEReader* ereader, const void* data, size_t size); + +CXX_GUARD_END + +#endif diff --git a/include/mgba/internal/gba/cart/gpio.h b/include/mgba/internal/gba/cart/gpio.h index 93fd359bd..53b610fe3 100644 --- a/include/mgba/internal/gba/cart/gpio.h +++ b/include/mgba/internal/gba/cart/gpio.h @@ -13,7 +13,6 @@ CXX_GUARD_START #include #include #include -#include mLOG_DECLARE_CATEGORY(GBA_HW); @@ -102,24 +101,6 @@ struct GBACartridgeHardware { uint16_t tiltX; uint16_t tiltY; int tiltState; - - uint16_t eReaderData[44]; - uint8_t eReaderSerial[92]; - uint16_t eReaderRegisterUnk; - uint16_t eReaderRegisterReset; - EReaderControl0 eReaderRegisterControl0; - EReaderControl1 eReaderRegisterControl1; - uint16_t eReaderRegisterLed; - - // TODO: Serialize these - enum EReaderStateMachine eReaderState; - enum EReaderCommand eReaderCommand; - uint8_t eReaderActiveRegister; - uint8_t eReaderByte; - int eReaderX; - int eReaderY; - uint8_t* eReaderDots; - struct EReaderCard eReaderCards[EREADER_CARDS_MAX]; }; void GBAHardwareInit(struct GBACartridgeHardware* gpio, uint16_t* gpioBase); diff --git a/include/mgba/internal/gba/memory.h b/include/mgba/internal/gba/memory.h index fac001de4..f7d4e1eb9 100644 --- a/include/mgba/internal/gba/memory.h +++ b/include/mgba/internal/gba/memory.h @@ -15,6 +15,7 @@ CXX_GUARD_START #include #include #include +#include #include #include #include @@ -108,6 +109,7 @@ struct GBAMemory { struct GBASavedata savedata; struct GBAVFameCart vfame; struct GBAMatrix matrix; + struct GBACartEReader ereader; size_t romSize; uint32_t romMask; uint16_t romID; diff --git a/src/gba/cart/ereader.c b/src/gba/cart/ereader.c index d79bd8dbb..450bc4726 100644 --- a/src/gba/cart/ereader.c +++ b/src/gba/cart/ereader.c @@ -12,11 +12,12 @@ #define EREADER_BLOCK_SIZE 40 -static void _eReaderReset(struct GBACartridgeHardware* hw); -static void _eReaderWriteControl0(struct GBACartridgeHardware* hw, uint8_t value); -static void _eReaderWriteControl1(struct GBACartridgeHardware* hw, uint8_t value); -static void _eReaderReadData(struct GBACartridgeHardware* hw); +static void _eReaderReset(struct GBACartEReader* ereader); +static void _eReaderWriteControl0(struct GBACartEReader* ereader, uint8_t value); +static void _eReaderWriteControl1(struct GBACartEReader* ereader, uint8_t value); +static void _eReaderReadData(struct GBACartEReader* ereader); static void _eReaderReedSolomon(const uint8_t* input, uint8_t* output); +static void _eReaderScanCard(struct GBACartEReader* ereader); const int EREADER_NYBBLE_5BIT[16][5] = { { 0, 0, 0, 0, 0 }, @@ -161,30 +162,46 @@ static const uint8_t RS_GG[] = { }; -void GBAHardwareInitEReader(struct GBACartridgeHardware* hw) { - hw->devices |= HW_EREADER; - _eReaderReset(hw); +void GBACartEReaderInit(struct GBACartEReader* ereader) { + ereader->p->memory.hw.devices |= HW_EREADER; + _eReaderReset(ereader); - if (hw->p->memory.savedata.data[0xD000] == 0xFF) { - memset(&hw->p->memory.savedata.data[0xD000], 0, 0x1000); - memcpy(&hw->p->memory.savedata.data[0xD000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE)); + if (ereader->p->memory.savedata.data[0xD000] == 0xFF) { + memset(&ereader->p->memory.savedata.data[0xD000], 0, 0x1000); + memcpy(&ereader->p->memory.savedata.data[0xD000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE)); } - if (hw->p->memory.savedata.data[0xE000] == 0xFF) { - memset(&hw->p->memory.savedata.data[0xE000], 0, 0x1000); - memcpy(&hw->p->memory.savedata.data[0xE000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE)); + if (ereader->p->memory.savedata.data[0xE000] == 0xFF) { + memset(&ereader->p->memory.savedata.data[0xE000], 0, 0x1000); + memcpy(&ereader->p->memory.savedata.data[0xE000], EREADER_CALIBRATION_TEMPLATE, sizeof(EREADER_CALIBRATION_TEMPLATE)); } } -void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) { +void GBACartEReaderDeinit(struct GBACartEReader* ereader) { + if (ereader->dots) { + mappedMemoryFree(ereader->dots, EREADER_DOTCODE_SIZE); + ereader->dots = NULL; + } + int i; + for (i = 0; i < EREADER_CARDS_MAX; ++i) { + if (!ereader->cards[i].data) { + continue; + } + free(ereader->cards[i].data); + ereader->cards[i].data = NULL; + ereader->cards[i].size = 0; + } +} + +void GBACartEReaderWrite(struct GBACartEReader* ereader, uint32_t address, uint16_t value) { address &= 0x700FF; switch (address >> 17) { case 0: - hw->eReaderRegisterUnk = value & 0xF; + ereader->registerUnk = value & 0xF; break; case 1: - hw->eReaderRegisterReset = (value & 0x8A) | 4; + ereader->registerReset = (value & 0x8A) | 4; if (value & 2) { - _eReaderReset(hw); + _eReaderReset(ereader); } break; case 2: @@ -195,54 +212,54 @@ void GBAHardwareEReaderWrite(struct GBACartridgeHardware* hw, uint32_t address, } } -void GBAHardwareEReaderWriteFlash(struct GBACartridgeHardware* hw, uint32_t address, uint8_t value) { +void GBACartEReaderWriteFlash(struct GBACartEReader* ereader, uint32_t address, uint8_t value) { address &= 0xFFFF; switch (address) { case 0xFFB0: - _eReaderWriteControl0(hw, value); + _eReaderWriteControl0(ereader, value); break; case 0xFFB1: - _eReaderWriteControl1(hw, value); + _eReaderWriteControl1(ereader, value); break; case 0xFFB2: - hw->eReaderRegisterLed &= 0xFF00; - hw->eReaderRegisterLed |= value; + ereader->registerLed &= 0xFF00; + ereader->registerLed |= value; break; case 0xFFB3: - hw->eReaderRegisterLed &= 0x00FF; - hw->eReaderRegisterLed |= value << 8; + ereader->registerLed &= 0x00FF; + ereader->registerLed |= value << 8; break; default: mLOG(GBA_HW, STUB, "Unimplemented e-Reader write to flash: %04X:%02X", address, value); } } -uint16_t GBAHardwareEReaderRead(struct GBACartridgeHardware* hw, uint32_t address) { +uint16_t GBACartEReaderRead(struct GBACartEReader* ereader, uint32_t address) { address &= 0x700FF; uint16_t value; switch (address >> 17) { case 0: - return hw->eReaderRegisterUnk; + return ereader->registerUnk; case 1: - return hw->eReaderRegisterReset; + return ereader->registerReset; case 2: if (address > 0x40088) { return 0; } - LOAD_16(value, address & 0xFE, hw->eReaderData); + LOAD_16(value, address & 0xFE, ereader->data); return value; } mLOG(GBA_HW, STUB, "Unimplemented e-Reader read: %05X", address); return 0; } -uint8_t GBAHardwareEReaderReadFlash(struct GBACartridgeHardware* hw, uint32_t address) { +uint8_t GBACartEReaderReadFlash(struct GBACartEReader* ereader, uint32_t address) { address &= 0xFFFF; switch (address) { case 0xFFB0: - return hw->eReaderRegisterControl0; + return ereader->registerControl0; case 0xFFB1: - return hw->eReaderRegisterControl1; + return ereader->registerControl1; default: mLOG(GBA_HW, STUB, "Unimplemented e-Reader read from flash: %04X", address); return 0; @@ -329,12 +346,12 @@ static void _eReaderReedSolomon(const uint8_t* input, uint8_t* output) { } } -void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, size_t size) { - if (!hw->eReaderDots) { - hw->eReaderDots = anonymousMemoryMap(EREADER_DOTCODE_SIZE); +void GBACartEReaderScan(struct GBACartEReader* ereader, const void* data, size_t size) { + if (!ereader->dots) { + ereader->dots = anonymousMemoryMap(EREADER_DOTCODE_SIZE); } - hw->eReaderX = -24; - memset(hw->eReaderDots, 0, EREADER_DOTCODE_SIZE); + ereader->scanX = -24; + memset(ereader->dots, 0, EREADER_DOTCODE_SIZE); uint8_t blockRS[44][0x10]; uint8_t block0[0x30]; @@ -386,7 +403,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s size_t x; for (i = 0; i < 40; ++i) { const uint8_t* line = &cdata[(i + 2) * blocks]; - uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * i + 200]; + uint8_t* origin = &ereader->dots[EREADER_DOTCODE_STRIDE * i + 200]; for (x = 0; x < blocks; ++x) { uint8_t byte = line[x]; if (x == 123) { @@ -406,7 +423,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s } for (i = 0; i < blocks + 1; ++i) { - uint8_t* origin = &hw->eReaderDots[35 * i + 200]; + uint8_t* origin = &ereader->dots[35 * i + 200]; _eReaderAnchor(&origin[EREADER_DOTCODE_STRIDE * 0]); _eReaderAnchor(&origin[EREADER_DOTCODE_STRIDE * 35]); _eReaderAddress(origin, base + i); @@ -461,7 +478,7 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s size_t byteOffset = 0; for (i = 0; i < blocks; ++i) { uint8_t block[1040]; - uint8_t* origin = &hw->eReaderDots[35 * i + 200]; + uint8_t* origin = &ereader->dots[35 * i + 200]; _eReaderAlignment(&origin[EREADER_DOTCODE_STRIDE * 2]); _eReaderAlignment(&origin[EREADER_DOTCODE_STRIDE * 37]); @@ -532,155 +549,132 @@ void GBAHardwareEReaderScan(struct GBACartridgeHardware* hw, const void* data, s } } -void _eReaderReset(struct GBACartridgeHardware* hw) { - memset(hw->eReaderData, 0, sizeof(hw->eReaderData)); - hw->eReaderRegisterUnk = 0; - hw->eReaderRegisterReset = 4; - hw->eReaderRegisterControl0 = 0; - hw->eReaderRegisterControl1 = 0x80; - hw->eReaderRegisterLed = 0; - hw->eReaderState = 0; - hw->eReaderActiveRegister = 0; +void _eReaderReset(struct GBACartEReader* ereader) { + memset(ereader->data, 0, sizeof(ereader->data)); + ereader->registerUnk = 0; + ereader->registerReset = 4; + ereader->registerControl0 = 0; + ereader->registerControl1 = 0x80; + ereader->registerLed = 0; + ereader->state = 0; + ereader->activeRegister = 0; } -void _eReaderWriteControl0(struct GBACartridgeHardware* hw, uint8_t value) { +void _eReaderWriteControl0(struct GBACartEReader* ereader, uint8_t value) { EReaderControl0 control = value & 0x7F; - EReaderControl0 oldControl = hw->eReaderRegisterControl0; - if (hw->eReaderState == EREADER_SERIAL_INACTIVE) { + EReaderControl0 oldControl = ereader->registerControl0; + if (ereader->state == EREADER_SERIAL_INACTIVE) { if (EReaderControl0IsClock(oldControl) && EReaderControl0IsData(oldControl) && !EReaderControl0IsData(control)) { - hw->eReaderState = EREADER_SERIAL_STARTING; + ereader->state = EREADER_SERIAL_STARTING; } } else if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsData(oldControl) && EReaderControl0IsData(control)) { - hw->eReaderState = EREADER_SERIAL_INACTIVE; + ereader->state = EREADER_SERIAL_INACTIVE; - } else if (hw->eReaderState == EREADER_SERIAL_STARTING) { + } else if (ereader->state == EREADER_SERIAL_STARTING) { if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsData(oldControl) && !EReaderControl0IsClock(control)) { - hw->eReaderState = EREADER_SERIAL_BIT_0; - hw->eReaderCommand = EREADER_COMMAND_IDLE; + ereader->state = EREADER_SERIAL_BIT_0; + ereader->command = EREADER_COMMAND_IDLE; } } else if (EReaderControl0IsClock(oldControl) && !EReaderControl0IsClock(control)) { mLOG(GBA_HW, DEBUG, "[e-Reader] Serial falling edge: %c %i", EReaderControl0IsDirection(control) ? '>' : '<', EReaderControl0GetData(control)); // TODO: Improve direction control if (EReaderControl0IsDirection(control)) { - hw->eReaderByte |= EReaderControl0GetData(control) << (7 - (hw->eReaderState - EREADER_SERIAL_BIT_0)); - ++hw->eReaderState; - if (hw->eReaderState == EREADER_SERIAL_END_BIT) { - mLOG(GBA_HW, DEBUG, "[e-Reader] Wrote serial byte: %02x", hw->eReaderByte); - switch (hw->eReaderCommand) { + ereader->byte |= EReaderControl0GetData(control) << (7 - (ereader->state - EREADER_SERIAL_BIT_0)); + ++ereader->state; + if (ereader->state == EREADER_SERIAL_END_BIT) { + mLOG(GBA_HW, DEBUG, "[e-Reader] Wrote serial byte: %02x", ereader->byte); + switch (ereader->command) { case EREADER_COMMAND_IDLE: - hw->eReaderCommand = hw->eReaderByte; + ereader->command = ereader->byte; break; case EREADER_COMMAND_SET_INDEX: - hw->eReaderActiveRegister = hw->eReaderByte; - hw->eReaderCommand = EREADER_COMMAND_WRITE_DATA; + ereader->activeRegister = ereader->byte; + ereader->command = EREADER_COMMAND_WRITE_DATA; break; case EREADER_COMMAND_WRITE_DATA: - switch (hw->eReaderActiveRegister & 0x7F) { + switch (ereader->activeRegister & 0x7F) { case 0: case 0x57: case 0x58: case 0x59: case 0x5A: // Read-only - mLOG(GBA_HW, GAME_ERROR, "Writing to read-only e-Reader serial register: %02X", hw->eReaderActiveRegister); + mLOG(GBA_HW, GAME_ERROR, "Writing to read-only e-Reader serial register: %02X", ereader->activeRegister); break; default: - if ((hw->eReaderActiveRegister & 0x7F) > 0x5A) { - mLOG(GBA_HW, GAME_ERROR, "Writing to non-existent e-Reader serial register: %02X", hw->eReaderActiveRegister); + if ((ereader->activeRegister & 0x7F) > 0x5A) { + mLOG(GBA_HW, GAME_ERROR, "Writing to non-existent e-Reader serial register: %02X", ereader->activeRegister); break; } - hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F] = hw->eReaderByte; + ereader->serial[ereader->activeRegister & 0x7F] = ereader->byte; break; } - ++hw->eReaderActiveRegister; + ++ereader->activeRegister; break; default: - mLOG(GBA_HW, ERROR, "Hit undefined state %02X in e-Reader state machine", hw->eReaderCommand); + mLOG(GBA_HW, ERROR, "Hit undefined state %02X in e-Reader state machine", ereader->command); break; } - hw->eReaderState = EREADER_SERIAL_BIT_0; - hw->eReaderByte = 0; + ereader->state = EREADER_SERIAL_BIT_0; + ereader->byte = 0; } - } else if (hw->eReaderCommand == EREADER_COMMAND_READ_DATA) { - int bit = hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F] >> (7 - (hw->eReaderState - EREADER_SERIAL_BIT_0)); + } else if (ereader->command == EREADER_COMMAND_READ_DATA) { + int bit = ereader->serial[ereader->activeRegister & 0x7F] >> (7 - (ereader->state - EREADER_SERIAL_BIT_0)); control = EReaderControl0SetData(control, bit); - ++hw->eReaderState; - if (hw->eReaderState == EREADER_SERIAL_END_BIT) { - ++hw->eReaderActiveRegister; - mLOG(GBA_HW, DEBUG, "[e-Reader] Read serial byte: %02x", hw->eReaderSerial[hw->eReaderActiveRegister & 0x7F]); + ++ereader->state; + if (ereader->state == EREADER_SERIAL_END_BIT) { + ++ereader->activeRegister; + mLOG(GBA_HW, DEBUG, "[e-Reader] Read serial byte: %02x", ereader->serial[ereader->activeRegister & 0x7F]); } } } else if (!EReaderControl0IsDirection(control)) { // Clear the error bit control = EReaderControl0ClearData(control); } - hw->eReaderRegisterControl0 = control; + ereader->registerControl0 = control; if (!EReaderControl0IsScan(oldControl) && EReaderControl0IsScan(control)) { - if (hw->eReaderX > 1000) { - if (hw->eReaderDots) { - memset(hw->eReaderDots, 0, EREADER_DOTCODE_SIZE); - } - int i; - for (i = 0; i < EREADER_CARDS_MAX; ++i) { - if (!hw->eReaderCards[i].data) { - continue; - } - GBAHardwareEReaderScan(hw, hw->eReaderCards[i].data, hw->eReaderCards[i].size); - free(hw->eReaderCards[i].data); - hw->eReaderCards[i].data = NULL; - hw->eReaderCards[i].size = 0; - break; - } + if (ereader->scanX > 1000) { + _eReaderScanCard(ereader); } - hw->eReaderX = 0; - hw->eReaderY = 0; - } else if (EReaderControl0IsLedEnable(control) && EReaderControl0IsScan(control) && !EReaderControl1IsScanline(hw->eReaderRegisterControl1)) { - _eReaderReadData(hw); + ereader->scanX = 0; + ereader->scanY = 0; + } else if (EReaderControl0IsLedEnable(control) && EReaderControl0IsScan(control) && !EReaderControl1IsScanline(ereader->registerControl1)) { + _eReaderReadData(ereader); } mLOG(GBA_HW, STUB, "Unimplemented e-Reader Control0 write: %02X", value); } -void _eReaderWriteControl1(struct GBACartridgeHardware* hw, uint8_t value) { +void _eReaderWriteControl1(struct GBACartEReader* ereader, uint8_t value) { EReaderControl1 control = (value & 0x32) | 0x80; - hw->eReaderRegisterControl1 = control; - if (EReaderControl0IsScan(hw->eReaderRegisterControl0) && !EReaderControl1IsScanline(control)) { - ++hw->eReaderY; - if (hw->eReaderY == (hw->eReaderSerial[0x15] | (hw->eReaderSerial[0x14] << 8))) { - hw->eReaderY = 0; - if (hw->eReaderX < 3400) { - hw->eReaderX += 210; + ereader->registerControl1 = control; + if (EReaderControl0IsScan(ereader->registerControl0) && !EReaderControl1IsScanline(control)) { + ++ereader->scanY; + if (ereader->scanY == (ereader->serial[0x15] | (ereader->serial[0x14] << 8))) { + ereader->scanY = 0; + if (ereader->scanX < 3400) { + ereader->scanX += 210; } } - _eReaderReadData(hw); + _eReaderReadData(ereader); } mLOG(GBA_HW, STUB, "Unimplemented e-Reader Control1 write: %02X", value); } -void _eReaderReadData(struct GBACartridgeHardware* hw) { - memset(hw->eReaderData, 0, EREADER_BLOCK_SIZE); - if (!hw->eReaderDots) { - int i; - for (i = 0; i < EREADER_CARDS_MAX; ++i) { - if (!hw->eReaderCards[i].data) { - continue; - } - GBAHardwareEReaderScan(hw, hw->eReaderCards[i].data, hw->eReaderCards[i].size); - free(hw->eReaderCards[i].data); - hw->eReaderCards[i].data = NULL; - hw->eReaderCards[i].size = 0; - break; - } +void _eReaderReadData(struct GBACartEReader* ereader) { + memset(ereader->data, 0, EREADER_BLOCK_SIZE); + if (!ereader->dots) { + _eReaderScanCard(ereader); } - if (hw->eReaderDots) { - int y = hw->eReaderY - 10; + if (ereader->dots) { + int y = ereader->scanY - 10; if (y < 0 || y >= 120) { - memset(hw->eReaderData, 0, EREADER_BLOCK_SIZE); + memset(ereader->data, 0, EREADER_BLOCK_SIZE); } else { int i; - uint8_t* origin = &hw->eReaderDots[EREADER_DOTCODE_STRIDE * (y / 3) + 16]; + uint8_t* origin = &ereader->dots[EREADER_DOTCODE_STRIDE * (y / 3) + 16]; for (i = 0; i < 20; ++i) { uint16_t word = 0; - int x = hw->eReaderX + i * 16; + int x = ereader->scanX + i * 16; word |= origin[(x + 0) / 3] << 8; word |= origin[(x + 1) / 3] << 9; word |= origin[(x + 2) / 3] << 10; @@ -697,29 +691,48 @@ void _eReaderReadData(struct GBACartridgeHardware* hw) { word |= origin[(x + 13) / 3] << 5; word |= origin[(x + 14) / 3] << 6; word |= origin[(x + 15) / 3] << 7; - STORE_16(word, (19 - i) << 1, hw->eReaderData); + STORE_16(word, (19 - i) << 1, ereader->data); } } } - hw->eReaderRegisterControl1 = EReaderControl1FillScanline(hw->eReaderRegisterControl1); - if (EReaderControl0IsLedEnable(hw->eReaderRegisterControl0)) { - uint16_t led = hw->eReaderRegisterLed * 2; + ereader->registerControl1 = EReaderControl1FillScanline(ereader->registerControl1); + if (EReaderControl0IsLedEnable(ereader->registerControl0)) { + uint16_t led = ereader->registerLed * 2; if (led > 0x4000) { led = 0x4000; } - GBARaiseIRQ(hw->p, IRQ_GAMEPAK, -led); + GBARaiseIRQ(ereader->p, IRQ_GAMEPAK, -led); } } -void GBAEReaderQueueCard(struct GBA* gba, const void* data, size_t size) { + +void _eReaderScanCard(struct GBACartEReader* ereader) { + if (ereader->dots) { + memset(ereader->dots, 0, EREADER_DOTCODE_SIZE); + } int i; for (i = 0; i < EREADER_CARDS_MAX; ++i) { - if (gba->memory.hw.eReaderCards[i].data) { + if (!ereader->cards[i].data) { continue; } - gba->memory.hw.eReaderCards[i].data = malloc(size); - memcpy(gba->memory.hw.eReaderCards[i].data, data, size); - gba->memory.hw.eReaderCards[i].size = size; + GBACartEReaderScan(ereader, ereader->cards[i].data, ereader->cards[i].size); + free(ereader->cards[i].data); + ereader->cards[i].data = NULL; + ereader->cards[i].size = 0; + break; + } +} + +void GBACartEReaderQueueCard(struct GBA* gba, const void* data, size_t size) { + struct GBACartEReader* ereader = &gba->memory.ereader; + int i; + for (i = 0; i < EREADER_CARDS_MAX; ++i) { + if (ereader->cards[i].data) { + continue; + } + ereader->cards[i].data = malloc(size); + memcpy(ereader->cards[i].data, data, size); + ereader->cards[i].size = size; return; } } diff --git a/src/gba/cart/gpio.c b/src/gba/cart/gpio.c index 92196b243..c3d9536d4 100644 --- a/src/gba/cart/gpio.c +++ b/src/gba/cart/gpio.c @@ -46,8 +46,6 @@ static const int RTC_BYTES[8] = { void GBAHardwareInit(struct GBACartridgeHardware* hw, uint16_t* base) { hw->gpioBase = base; - hw->eReaderDots = NULL; - memset(hw->eReaderCards, 0, sizeof(hw->eReaderCards)); GBAHardwareClear(hw); } @@ -56,20 +54,6 @@ void GBAHardwareClear(struct GBACartridgeHardware* hw) { hw->readWrite = GPIO_WRITE_ONLY; hw->pinState = 0; hw->direction = 0; - - if (hw->eReaderDots) { - mappedMemoryFree(hw->eReaderDots, EREADER_DOTCODE_SIZE); - hw->eReaderDots = NULL; - } - int i; - for (i = 0; i < EREADER_CARDS_MAX; ++i) { - if (!hw->eReaderCards[i].data) { - continue; - } - free(hw->eReaderCards[i].data); - hw->eReaderCards[i].data = NULL; - hw->eReaderCards[i].size = 0; - } } void GBAHardwareGPIOWrite(struct GBACartridgeHardware* hw, uint32_t address, uint16_t value) { diff --git a/src/gba/memory.c b/src/gba/memory.c index 05cec7c67..f650881b1 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -94,6 +94,10 @@ void GBAMemoryInit(struct GBA* gba) { GBADMAInit(gba); GBAVFameInit(&gba->memory.vfame); + + gba->memory.ereader.p = gba; + gba->memory.ereader.dots = NULL; + memset(gba->memory.ereader.cards, 0, sizeof(gba->memory.ereader.cards)); } void GBAMemoryDeinit(struct GBA* gba) { @@ -107,6 +111,8 @@ void GBAMemoryDeinit(struct GBA* gba) { if (gba->memory.agbPrintBufferBackup) { mappedMemoryFree(gba->memory.agbPrintBufferBackup, SIZE_AGB_PRINT); } + + GBACartEReaderDeinit(&gba->memory.ereader); } void GBAMemoryReset(struct GBA* gba) { @@ -588,7 +594,7 @@ uint32_t GBALoad16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { if (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512) { value = GBASavedataReadEEPROM(&memory->savedata); } else if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) { - value = GBAHardwareEReaderRead(&memory->hw, address); + value = GBACartEReaderRead(&memory->ereader, address); } else if ((address & (SIZE_CART0 - 1)) < memory->romSize) { LOAD_16(value, address & (SIZE_CART0 - 2), memory->rom); } else if (memory->mirroring && (address & memory->romMask) < memory->romSize) { @@ -704,7 +710,7 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { break; } if (memory->hw.devices & HW_EREADER && (address & 0xE00FF80) >= 0xE00FF80) { - value = GBAHardwareEReaderReadFlash(&memory->hw, address); + value = GBACartEReaderReadFlash(&memory->ereader, address); } else if (memory->savedata.type == SAVEDATA_SRAM) { value = memory->savedata.data[address & (SIZE_CART_SRAM - 1)]; } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) { @@ -965,7 +971,7 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle break; case REGION_CART2_EX: if ((address & 0x0DFC0000) >= 0x0DF80000 && memory->hw.devices & HW_EREADER) { - GBAHardwareEReaderWrite(&memory->hw, address, value); + GBACartEReaderWrite(&memory->ereader, address, value); break; } else if (memory->savedata.type == SAVEDATA_AUTODETECT) { mLOG(GBA_MEM, INFO, "Detected EEPROM savegame"); @@ -1052,7 +1058,7 @@ void GBAStore8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo } } if (memory->hw.devices & HW_EREADER && (address & 0xE00FF80) >= 0xE00FF80) { - GBAHardwareEReaderWriteFlash(&memory->hw, address, value); + GBACartEReaderWriteFlash(&memory->ereader, address, value); } else if (memory->savedata.type == SAVEDATA_FLASH512 || memory->savedata.type == SAVEDATA_FLASH1M) { GBASavedataWriteFlash(&memory->savedata, address, value); } else if (memory->savedata.type == SAVEDATA_SRAM) { diff --git a/src/gba/overrides.c b/src/gba/overrides.c index 86446fbab..630662d31 100644 --- a/src/gba/overrides.c +++ b/src/gba/overrides.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -347,7 +348,7 @@ void GBAOverrideApply(struct GBA* gba, const struct GBACartridgeOverride* overri } if (override->hardware & HW_EREADER) { - GBAHardwareInitEReader(&gba->memory.hw); + GBACartEReaderInit(&gba->memory.ereader); } if (override->hardware & HW_GB_PLAYER_DETECTION) { diff --git a/src/platform/qt/CoreController.cpp b/src/platform/qt/CoreController.cpp index 81b7b3ad5..514aa84ab 100644 --- a/src/platform/qt/CoreController.cpp +++ b/src/platform/qt/CoreController.cpp @@ -812,7 +812,7 @@ void CoreController::scanCard(const QString& path) { mCoreThreadRunFunction(&m_threadContext, [](mCoreThread* thread) { CoreController* controller = static_cast(thread->userData); - GBAEReaderQueueCard(static_cast(thread->core->board), controller->m_eReaderData.constData(), controller->m_eReaderData.size()); + GBACartEReaderQueueCard(static_cast(thread->core->board), controller->m_eReaderData.constData(), controller->m_eReaderData.size()); }); #endif } From bda0095721e4ecb9e3beaf6b6c45aff101128f5a Mon Sep 17 00:00:00 2001 From: Bentley Racune Date: Mon, 29 Mar 2021 08:05:22 +0000 Subject: [PATCH 04/10] Qt: Update translation (German) Currently translated at 100.0% (1056 of 1056 strings) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/de/ --- src/platform/qt/ts/mgba-de.ts | 165 +++++++++++++++++----------------- 1 file changed, 80 insertions(+), 85 deletions(-) diff --git a/src/platform/qt/ts/mgba-de.ts b/src/platform/qt/ts/mgba-de.ts index b68d4553d..70138df98 100644 --- a/src/platform/qt/ts/mgba-de.ts +++ b/src/platform/qt/ts/mgba-de.ts @@ -33,7 +33,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> - Branch: <tt>{gitBranch}</tt><br/>Revision: <tt>{gitCommit}</tt> + Zweig: <tt>{gitBranch}</tt><br/>Änderung: <tt>{gitCommit}</tt> @@ -498,7 +498,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Fatal - Fatal + Tödlich @@ -526,7 +526,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Maps - Maps + Karten @@ -752,7 +752,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Signed Integer: - Signed Integer: + Ganzzahl mit Vorzeichen: @@ -792,7 +792,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Unsigned Integer: - Unsigned Integer: + Ganzzahl ohne Vorzeichen: @@ -825,7 +825,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Transform - Transform + Verwandeln @@ -890,7 +890,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Mosaic - Mosaic + Mosaik @@ -905,7 +905,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Tile - + Kachel @@ -1535,7 +1535,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Swap green components - + Grüne Komponenten tauschen @@ -1665,7 +1665,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Fractional part - + Bruchteil @@ -1685,7 +1685,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Integer part (low) - + Ganzzahl-Anteil (tief) @@ -1693,7 +1693,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Integer part (high) - + Ganzzahl-Anteil (hoch) @@ -1963,19 +1963,19 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Sweep shifts - + Schwung-Verschiebungen Sweep subtract - + Schwung subtrahieren Sweep time (in 1/128s) - + Schwungzeit (in 1/128s) @@ -1995,7 +1995,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Duty cycle - + Auslastungsgrad @@ -2005,7 +2005,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Envelope step time - + Hüllkurve-Schrittzeit @@ -2061,7 +2061,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Double-size wave table - + Doppelte Größe Wave-Table @@ -2125,7 +2125,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Register stages - + Register-Stufen @@ -2143,7 +2143,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Shifter frequency - + Shifter-Frequenz @@ -2211,12 +2211,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Loud channel A - + Lautkanal A Loud channel B - + Lautkanal B @@ -2310,7 +2310,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Bias - + Vorspannung @@ -2391,7 +2391,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Sample - Sample + Abtastwert @@ -2553,7 +2553,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Start timing - + Zeitpunkt des Starts @@ -2620,7 +2620,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Audio FIFO - Audio FIFO + Audio-FIFO @@ -2916,7 +2916,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. PHI terminal - + PHI-Terminal @@ -2927,17 +2927,17 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. 4.19MHz - 4,19 MHz + 4,19 MHz 8.38MHz - 8,38 MHz + 8,38 MHz 16.78MHz - 16,78 MHz + 16,78 MHz @@ -2992,7 +2992,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Transfer active - + Übertragung aktiv @@ -3008,65 +3008,65 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. LCD STAT - + LCD STAT Timer - + Timer Serial - + Serial Joypad - + Gamepad Volume right - + Lautstärke rechts Output right - + Ausgabe rechts Volume left - + Lautstärke links Output left - + Ausgabe links Background enable/priority - + Hintergrund aktivieren/Priorität Enable sprites - + Sprites aktivieren Double-height sprites - + Doppelte Höhe Sprites Background tile map - + Hintergrundkachelkarte @@ -3083,7 +3083,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Background tile data - + Hintergrundkacheldaten @@ -3098,12 +3098,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Enable window - + Fenster aktivieren Window tile map - + Fensterkachelkarte @@ -3118,7 +3118,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. 0: HBlank - HBlank + 0: HBlank @@ -3128,7 +3128,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. 2: OAM scan - 2: OAM scan + 2: OAM-Überprüfung @@ -3138,75 +3138,75 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. In LYC - + In LYC Enable HBlank (mode 0) IRQ - + HBlank aktivieren (Modus 0) IRQ Enable VBlank (mode 1) IRQ - + VBlank aktivieren (Modus 1) IRQ Enable OAM (mode 2) IRQ - + OAM aktivieren (Modus 2) IRQ Enable LYC IRQ - + LYC aktivieren IRQ Current Y coordinate - + Aktuelle Y-Koordinate Comparison Y coordinate - + Vergleich Y-Koordinate Start upper byte - + Oberes Byte starten Color 0 shade - + Farbe 0 Farbton Color 1 shade - + Farbe 1 Farbton Color 2 shade - + Farbe 2 Farbton Color 3 shade - + Farbe 3 Farbton Prepare to switch speed - + Zu Geschwindigkeit wechseln vorbereiten @@ -3221,22 +3221,22 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Length - + Länge Timing - + Timing Write bit - + Bit schreiben Read bit - + Bit lesen @@ -3248,7 +3248,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Current index - + Aktueller Index @@ -3271,17 +3271,17 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Sprite ordering - + Sprite-Anordnung OAM order - + OAM-Anordnung x coordinate sorting - + X-Koordinatensortierung @@ -4036,7 +4036,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Patches (*.ips *.ups *.bps) - Patches (*.ips *.ups *.bps) + Korrekturen (*.ips *.ups *.bps) @@ -4904,12 +4904,12 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. little endian - little endian + little-endian big endian - big endian + big-endian @@ -5246,8 +5246,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Force integer scaling - Erzwinge pixelgenaue Skalierung -(Integer scaling) + Erzwinge pixelgenaue Skalierung @@ -5308,8 +5307,7 @@ Game Boy Advance ist eine eingetragene Marke von Nintendo Co., Ltd. Enable Game Boy Player features by default - Game Boy Player-Features -standardmäßig aktivieren + Game Boy Player-Features standardmäßig aktivieren @@ -5354,8 +5352,7 @@ standardmäßig aktivieren Show filename instead of ROM name in title bar - Dateinamen statt ROM-Namen in der -Titelleiste anzeigen + Dateinamen statt ROM-Namen in der Titelleiste anzeigen @@ -5490,8 +5487,7 @@ Titelleiste anzeigen Preload entire ROM into memory - ROM-Datei vollständig -in Arbeitsspeicher vorladen + ROM-Datei vollständig in Arbeitsspeicher vorladen @@ -5509,8 +5505,7 @@ in Arbeitsspeicher vorladen Use BIOS file if found - BIOS-Datei verwenden, -wenn vorhanden + BIOS-Datei verwenden, wenn vorhanden @@ -5642,12 +5637,12 @@ wenn vorhanden Screenshots - Screenshots + Bildschirmfotos Patches - Patches + Korrekturen @@ -5716,7 +5711,7 @@ wenn vorhanden Tiles - Tiles + Kacheln From 8ea7d9b3b5eb3606eb5ed6e351cc143af2bad1a1 Mon Sep 17 00:00:00 2001 From: Bentley Racune Date: Mon, 29 Mar 2021 08:18:21 +0000 Subject: [PATCH 05/10] Qt: Update translation (Spanish) Currently translated at 100.0% (1056 of 1056 strings) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/es/ --- src/platform/qt/ts/mgba-es.ts | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 8528c234f..38c187e69 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -1862,27 +1862,27 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. BG 0 target 1 - BG 0 target 1 + BG 0 objetivo 1 BG 1 target 1 - BG 1 target 1 + BG 1 objetivo 1 BG 2 target 1 - BG 2 target 1 + BG 2 objetivo 1 BG 3 target 1 - BG 3 target 1 + BG 3 objetivo 1 OBJ target 1 - OBJ target 1 + OBJ objetivo 1 @@ -1917,27 +1917,27 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. BG 0 target 2 - BG 0 target 2 + BG 0 objetivo 2 BG 1 target 2 - BG 1 target 2 + BG 1 objetivo 2 BG 2 target 2 - BG 2 target 2 + BG 2 objetivo 2 BG 3 target 2 - BG 3 target 2 + BG 3 objetivo 2 OBJ target 2 - OBJ target 2 + OBJ objetivo 2 @@ -1947,12 +1947,12 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Blend A (target 1) - Mezcla A (target 1) + Mezcla A (objetivo 1) Blend B (target 2) - Mezcla B (target 2) + Mezcla B (objetivo 2) @@ -2044,7 +2044,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Timed - Timed + Cronometrado @@ -2620,7 +2620,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Audio FIFO - Audio FIFO + FIFO de audio @@ -2835,7 +2835,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. Keypad - Keypad + Teclado numérico @@ -2916,7 +2916,7 @@ Game Boy Advance es una marca registrada de Nintendo Co., Ltd. PHI terminal - PHI terminal + Terminal PHI From 1c5e0a2a9f2c34033243ce6e1b83e18bcfa1b1e0 Mon Sep 17 00:00:00 2001 From: Liukun Zhao Date: Tue, 30 Mar 2021 05:22:17 +0000 Subject: [PATCH 06/10] Qt: Update translation (Chinese (Simplified)) Currently translated at 88.7% (937 of 1056 strings) Translation: mGBA/Qt Translate-URL: https://hosted.weblate.org/projects/mgba/mgba-qt/zh_Hans/ --- src/platform/qt/ts/mgba-zh_CN.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 5c58cae3e..1fd1f0bd9 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -221,37 +221,37 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Connect to Dolphin - + 连接 Dolphin Local computer - + 本地电脑 IP address - + IP 地址 Connect - + 连接 Disconnect - + 断开连接 Close - + 关闭 Reset on connect - + 连接时重置 @@ -2952,27 +2952,27 @@ Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标 Right/A - + 右/A Left/B - + 左/B Up/Select - + 上/选择 Down/Start - + 下/开始 Active D-pad - + 活跃的方向键 From af212925e7a57e27ef3e417919c7d537ee4119ca Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 3 Apr 2021 16:15:11 -0700 Subject: [PATCH 07/10] mGUI: Fix build --- src/feature/gui/gui-runner.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/feature/gui/gui-runner.h b/src/feature/gui/gui-runner.h index 6b5c87619..20762d58b 100644 --- a/src/feature/gui/gui-runner.h +++ b/src/feature/gui/gui-runner.h @@ -12,7 +12,7 @@ CXX_GUARD_START #include #include "feature/gui/remap.h" -#include +#include #include #include #include From afd970423e49ae3224a0d27d2a1b4d85c3fc5f7f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 8 Apr 2021 18:41:53 -0700 Subject: [PATCH 08/10] Qt: Fix crash when switching from high-resolution OpenGL renderer to software --- CHANGES | 1 + src/platform/qt/DisplayGL.cpp | 7 ++++--- src/platform/qt/DisplayGL.h | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index d8de62398..387618daa 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Other fixes: - GBA e-Reader: Fix bitmap short strip scanning - GBA Video: Fix mode 5 frame 1 caching (fixes mgba.io/i/2075) - GBA Video: Don't attempt to copy invalid registers when switching renderer + - Qt: Fix crash when switching from high-resolution OpenGL renderer to software Misc: - Core: Truncate preloading ROMs that slightly exceed max size (fixes mgba.io/i/2093) - GBA: Default-enable VBA bug compat for Ruby and Emerald ROM hacks diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 2838992f9..c30cba9f5 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -368,6 +368,10 @@ void PainterGL::resizeContext() { m_interrupter.resume(); QSize size = m_context->screenDimensions(); + if (m_dims == size) { + return; + } + dequeueAll(); m_backend->setDimensions(m_backend, size.width(), size.height()); } @@ -560,9 +564,6 @@ void PainterGL::dequeueAll() { m_free.append(buffer); } } - if (buffer) { - m_backend->postFrame(m_backend, buffer); - } if (m_buffer) { m_free.append(m_buffer); m_buffer = nullptr; diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index a9ec10945..111f0cc88 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -142,7 +142,7 @@ private: QList m_free; QQueue m_queue; QAtomicInt m_lagging = 0; - uint32_t* m_buffer; + uint32_t* m_buffer = nullptr; QPainter m_painter; QMutex m_mutex; QWindow* m_surface; @@ -158,6 +158,7 @@ private: VideoShader m_shader{}; VideoBackend* m_backend = nullptr; QSize m_size; + QSize m_dims; MessagePainter* m_messagePainter = nullptr; QElapsedTimer m_delayTimer; std::shared_ptr m_videoProxy; From 207c64874a3f96085d372bb5df7b7d395880c6e2 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 6 Apr 2021 21:38:25 -0700 Subject: [PATCH 09/10] Util: Add bits of a convolution API --- include/mgba-util/convolve.h | 32 ++++++++ src/util/CMakeLists.txt | 1 + src/util/convolve.c | 138 +++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+) create mode 100644 include/mgba-util/convolve.h create mode 100644 src/util/convolve.c diff --git a/include/mgba-util/convolve.h b/include/mgba-util/convolve.h new file mode 100644 index 000000000..cf7aa52af --- /dev/null +++ b/include/mgba-util/convolve.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2013-2021 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 CONVOLVE_H +#define CONVOLVE_H + +#include + +CXX_GUARD_START + +struct ConvolutionKernel { + float* kernel; + size_t* dims; + size_t rank; +}; + +void ConvolutionKernelCreate(struct ConvolutionKernel* kernel, size_t rank, size_t* dims); +void ConvolutionKernelDestroy(struct ConvolutionKernel* kernel); + +void ConvolutionKernelFillRadial(struct ConvolutionKernel* kernel, bool normalize); +void ConvolutionKernelFillCircle(struct ConvolutionKernel* kernel, bool normalize); + +// TODO: Make image container struct? +void Convolve1DPad0PackedS32(const int32_t* restrict src, int32_t* restrict dst, size_t length, const struct ConvolutionKernel* restrict kernel); + +void Convolve2DClampPacked8(const uint8_t* restrict src, uint8_t* restrict dst, size_t width, size_t height, size_t stride, const struct ConvolutionKernel* restrict kernel); + +CXX_GUARD_END + +#endif diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index c9e074389..dd3dc8cda 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -2,6 +2,7 @@ include(ExportDirectory) set(SOURCE_FILES circle-buffer.c configuration.c + convolve.c crc32.c elf-read.c export.c diff --git a/src/util/convolve.c b/src/util/convolve.c new file mode 100644 index 000000000..358707cb3 --- /dev/null +++ b/src/util/convolve.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2013-2021 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 + +void ConvolutionKernelCreate(struct ConvolutionKernel* kernel, size_t rank, size_t* dims) { + kernel->rank = rank; + kernel->dims = malloc(sizeof(kernel->dims[0]) * rank); + size_t ksize = 1; + size_t i; + for (i = 0; i < rank; ++i) { + kernel->dims[i] = dims[i]; + ksize *= dims[i]; + } + kernel->kernel = calloc(ksize, sizeof(float)); +} + +void ConvolutionKernelDestroy(struct ConvolutionKernel* kernel) { + free(kernel->kernel); + free(kernel->dims); + kernel->kernel = NULL; + kernel->dims = NULL; + kernel->rank = 0; +} + +void ConvolutionKernelFillRadial(struct ConvolutionKernel* kernel, bool normalize) { + if (kernel->rank != 2) { + return; + } + float support; + if (normalize) { + support = 12.f / (M_PI * (kernel->dims[0] - 1) * (kernel->dims[1] - 1)); + } else { + support = 1.f; + } + float wr = (kernel->dims[0] - 1) / 2.f; + float hr = (kernel->dims[1] - 1) / 2.f; + float* elem = kernel->kernel; + size_t y; + for (y = 0; y < kernel->dims[1]; ++y) { + size_t x; + for (x = 0; x < kernel->dims[0]; ++x) { + float r = (1.f - hypotf((x - wr) / wr, (y - hr) / hr)) * support; + *elem = fmaxf(0, r); + ++elem; + } + } +} + +void ConvolutionKernelFillCircle(struct ConvolutionKernel* kernel, bool normalize) { + if (kernel->rank != 2) { + return; + } + float support; + if (normalize) { + support = 4.f / (M_PI * (kernel->dims[0] - 1) * (kernel->dims[1] - 1)); + } else { + support = 1.f; + } + float wr = (kernel->dims[0] - 1) / 2.f; + float hr = (kernel->dims[1] - 1) / 2.f; + float* elem = kernel->kernel; + size_t y; + for (y = 0; y < kernel->dims[1]; ++y) { + size_t x; + for (x = 0; x < kernel->dims[0]; ++x) { + float r = hypotf((x - wr) / wr, (y - hr) / hr); + *elem = r <= 1.f ? support : 0.f; + ++elem; + } + } +} + +void Convolve1DPad0PackedS32(const int32_t* restrict src, int32_t* restrict dst, size_t length, const struct ConvolutionKernel* restrict kernel) { + if (kernel->rank != 1) { + return; + } + size_t kx2 = kernel->dims[0] / 2; + size_t x; + for (x = 0; x < length; ++x) { + float sum = 0.f; + size_t kx; + for (kx = 0; kx < kernel->dims[0]; ++kx) { + if (x + kx <= kx2) { + continue; + } + size_t cx = x + kx - kx2; + if (cx >= length) { + continue; + } + sum += src[cx] * kernel->kernel[kx]; + } + *dst = sum; + ++dst; + } +} + +void Convolve2DClampPacked8(const uint8_t* restrict src, uint8_t* restrict dst, size_t width, size_t height, size_t stride, const struct ConvolutionKernel* restrict kernel) { + if (kernel->rank != 2) { + return; + } + size_t kx2 = kernel->dims[0] / 2; + size_t ky2 = kernel->dims[1] / 2; + size_t y; + for (y = 0; y < height; ++y) { + uint8_t* orow = &dst[y * stride]; + size_t x; + for (x = 0; x < width; ++x) { + float sum = 0.f; + size_t ky; + for (ky = 0; ky < kernel->dims[1]; ++ky) { + size_t cy = 0; + if (y + ky > ky2) { + cy = y + ky - ky2; + } + if (cy >= height) { + cy = height - 1; + } + const uint8_t* irow = &src[cy * stride]; + size_t kx; + for (kx = 0; kx < kernel->dims[0]; ++kx) { + size_t cx = 0; + if (x + kx > kx2) { + cx = x + kx - kx2; + } + if (cx >= width) { + cx = width - 1; + } + sum += irow[cx] * kernel->kernel[ky * kernel->dims[0] + kx]; + } + } + *orow = sum; + ++orow; + } + } +} From adfc3c4ab23e7f0c442e893361460b14cf5b908b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 9 Apr 2021 02:22:49 -0700 Subject: [PATCH 10/10] FFmpeg: Add image scaling function --- CMakeLists.txt | 2 +- include/mgba/core/interface.h | 1 + src/feature/ffmpeg/ffmpeg-common.h | 50 ++++++++++++++++++++++++++++++ src/feature/ffmpeg/ffmpeg-scale.c | 36 +++++++++++++++++++++ src/feature/ffmpeg/ffmpeg-scale.h | 21 +++++++++++++ 5 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/feature/ffmpeg/ffmpeg-scale.c create mode 100644 src/feature/ffmpeg/ffmpeg-scale.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 76fb3c5b9..3e88968bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -556,7 +556,7 @@ if(USE_FFMPEG) endif() include_directories(AFTER ${FFMPEG_INCLUDE_DIRS} ${LIBAVCODEC_INCLUDE_DIRS} ${LIBAVFILTER_INCLUDE_DIRS} ${LIBAVFORMAT_INCLUDE_DIRS} ${LIBAVRESAMPLE_INCLUDE_DIRS} ${LIBAVUTIL_INCLUDE_DIRS} ${LIBSWRESAMPLE_INCLUDE_DIRS} ${LIBSWSCALE_INCLUDE_DIRS}) link_directories(${FFMPEG_LIBRARY_DIRS} ${LIBAVCODEC_LIBRARY_DIRS} ${LIBAVFILTER_LIBRARY_DIRS} ${LIBAVFORMAT_LIBRARY_DIRS} ${LIBAVRESAMPLE_LIBRARY_DIRS} ${LIBAVUTIL_LIBRARY_DIRS} ${LIBSWRESAMPLE_LIBRARY_DIRS} ${LIBSWSCALE_LIBRARY_DIRS}) - list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-decoder.c") + list(APPEND FEATURE_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-encoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-decoder.c" "${CMAKE_CURRENT_SOURCE_DIR}/src/feature/ffmpeg/ffmpeg-scale.c") list(APPEND DEPENDENCY_LIB ${FFMPEG_LIBRARIES} ${LIBAVCODEC_LIBRARIES} ${LIBAVFILTER_LIBRARIES} ${LIBAVFORMAT_LIBRARIES} ${LIBAVRESAMPLE_LIBRARIES} ${LIBAVUTIL_LIBRARIES} ${LIBSWSCALE_LIBRARIES} ${LIBSWRESAMPLE_LIBRARIES}) if(WIN32 AND NOT DEFINED VCPKG_TARGET_TRIPLET) list(APPEND DEPENDENCY_LIB bcrypt) diff --git a/include/mgba/core/interface.h b/include/mgba/core/interface.h index ca42bca7b..177483597 100644 --- a/include/mgba/core/interface.h +++ b/include/mgba/core/interface.h @@ -164,6 +164,7 @@ enum mColorFormat { mCOLOR_BGRA5 = 0x08000, mCOLOR_RGB8 = 0x10000, mCOLOR_BGR8 = 0x20000, + mCOLOR_L8 = 0x40000, mCOLOR_ANY = -1 }; diff --git a/src/feature/ffmpeg/ffmpeg-common.h b/src/feature/ffmpeg/ffmpeg-common.h index d006c83ce..0f94cfbeb 100644 --- a/src/feature/ffmpeg/ffmpeg-common.h +++ b/src/feature/ffmpeg/ffmpeg-common.h @@ -10,6 +10,8 @@ CXX_GUARD_START +#include + #include #include @@ -32,6 +34,54 @@ CXX_GUARD_START #define FFMPEG_USE_PACKET_UNREF #endif +static inline enum AVPixelFormat mColorFormatToFFmpegPixFmt(enum mColorFormat format) { + switch (format) { +#ifndef USE_LIBAV + case mCOLOR_XRGB8: + return AV_PIX_FMT_0RGB; + case mCOLOR_XBGR8: + return AV_PIX_FMT_0BGR; + case mCOLOR_RGBX8: + return AV_PIX_FMT_RGB0; + case mCOLOR_BGRX8: + return AV_PIX_FMT_BGR0; +#else + case mCOLOR_XRGB8: + return AV_PIX_FMT_ARGB; + case mCOLOR_XBGR8: + return AV_PIX_FMT_ABGR; + case mCOLOR_RGBX8: + return AV_PIX_FMT_RGBA; + case mCOLOR_BGRX8: + return AV_PIX_FMT_BGRA; +#endif + case mCOLOR_ARGB8: + return AV_PIX_FMT_ARGB; + case mCOLOR_ABGR8: + return AV_PIX_FMT_ABGR; + case mCOLOR_RGBA8: + return AV_PIX_FMT_RGBA; + case mCOLOR_BGRA8: + return AV_PIX_FMT_BGRA; + case mCOLOR_RGB5: + return AV_PIX_FMT_RGB555; + case mCOLOR_BGR5: + return AV_PIX_FMT_BGR555; + case mCOLOR_RGB565: + return AV_PIX_FMT_RGB565; + case mCOLOR_BGR565: + return AV_PIX_FMT_BGR565; + case mCOLOR_RGB8: + return AV_PIX_FMT_RGB24; + case mCOLOR_BGR8: + return AV_PIX_FMT_BGR24; + case mCOLOR_L8: + return AV_PIX_FMT_GRAY8; + default: + return AV_PIX_FMT_NONE; + } +} + CXX_GUARD_END #endif diff --git a/src/feature/ffmpeg/ffmpeg-scale.c b/src/feature/ffmpeg/ffmpeg-scale.c new file mode 100644 index 000000000..a28600e2f --- /dev/null +++ b/src/feature/ffmpeg/ffmpeg-scale.c @@ -0,0 +1,36 @@ +/* Copyright (c) 2013-2021 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 "ffmpeg-scale.h" + +#include + +static const int _qualityToFlags[] = { + SWS_POINT, + SWS_FAST_BILINEAR, + SWS_BILINEAR, + SWS_BICUBIC, + SWS_LANCZOS, + SWS_SINC, +}; + +void FFmpegScale(const void* input, int iwidth, int iheight, unsigned istride, + void* output, int owidth, int oheight, unsigned ostride, + enum mColorFormat format, int quality) { + enum AVPixelFormat pixFormat = mColorFormatToFFmpegPixFmt(format); + int flags; + if (quality < 0) { + quality = 0; + } else if ((unsigned) quality >= sizeof(_qualityToFlags) / sizeof(_qualityToFlags[0])) { + quality = sizeof(_qualityToFlags) / sizeof(_qualityToFlags[0]) - 1; + } + flags = _qualityToFlags[quality]; + + struct SwsContext* scaleContext = sws_getContext(iwidth, iheight, pixFormat, + owidth, oheight, pixFormat, + flags, 0, 0, 0); + sws_scale(scaleContext, (const uint8_t* const*) &input, (const int*) &istride, 0, iheight, (uint8_t* const*) &output, (const int*) &ostride); + sws_freeContext(scaleContext); +} diff --git a/src/feature/ffmpeg/ffmpeg-scale.h b/src/feature/ffmpeg/ffmpeg-scale.h new file mode 100644 index 000000000..e447708df --- /dev/null +++ b/src/feature/ffmpeg/ffmpeg-scale.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2013-2021 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 FFMPEG_SCALE +#define FFMPEG_SCALE + +#include + +CXX_GUARD_START + +#include "feature/ffmpeg/ffmpeg-common.h" + +void FFmpegScale(const void* input, int iwidth, int iheight, unsigned istride, + void* output, int owidth, int oheight, unsigned ostride, + enum mColorFormat format, int quality); + +CXX_GUARD_END + +#endif