diff --git a/CHANGES b/CHANGES index 9f4fdcde0..6d5d163c8 100644 --- a/CHANGES +++ b/CHANGES @@ -44,12 +44,19 @@ Features: - New unlicensed GB mappers: NT (older types 1 and 2), Li Cheng, GGB-81 - Debugger: Add range watchpoints Emulation fixes: + - GB Audio: Fix channels 1/2 not playing when resetting volume (fixes mgba.io/i/2614) + - GB Audio: Fix channel 3 volume being changed between samples (fixes mgba.io/i/1896) + - GB Audio: Fix up boot sequence + - GB Audio: Fix updating channels other than 2 when writing NR5x + - GB Memory: Actually, HDMAs should start when LCD is off (fixes mgba.io/i/2662) - GB Serialize: Don't write BGP/OBP when loading SCGB state (fixes mgba.io/i/2694) - GB SIO: Further fix bidirectional transfer starting - GBA: Fix resetting key IRQ state (fixes mgba.io/i/2716) - GBA Video: Ignore disabled backgrounds as OBJ blend target (fixes mgba.io/i/2489) - GBA Video: Disable BG target 1 blending when OBJ blending (fixes mgba.io/i/2722) Other fixes: + - GBA: Fix forceskip BIOS logic for multiboot ROMs (fixes mgba.io/i/2753) + - GBA Cheats: Fix issues detecting unencrypted cheats (fixes mgba.io/i/2724) - Qt: Manually split filename to avoid overzealous splitting (fixes mgba.io/i/2681) - Qt: Expand criteria for tag branch names (fixes mgba.io/i/2679) - Qt: Fix scanning specific e-Reader dotcodes (fixes mgba.io/i/2693) diff --git a/src/gb/audio.c b/src/gb/audio.c index 0b6a03ecb..8bce46e07 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -269,6 +269,29 @@ void GBAudioWriteNR31(struct GBAudio* audio, uint8_t value) { void GBAudioWriteNR32(struct GBAudio* audio, uint8_t value) { GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x4); audio->ch3.volume = GBAudioRegisterBankVolumeGetVolumeGB(value); + + audio->ch3.sample = audio->ch3.wavedata8[audio->ch3.window >> 1]; + if (!(audio->ch3.window & 1)) { + audio->ch3.sample >>= 4; + } + audio->ch3.sample &= 0xF; + int volume; + switch (audio->ch3.volume) { + case 0: + volume = 4; + break; + case 1: + volume = 0; + break; + case 2: + volume = 1; + break; + default: + case 3: + volume = 2; + break; + } + audio->ch3.sample >>= volume; } void GBAudioWriteNR33(struct GBAudio* audio, uint8_t value) { @@ -377,13 +400,13 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { } void GBAudioWriteNR50(struct GBAudio* audio, uint8_t value) { - GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x2); + GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0xF); audio->volumeRight = GBRegisterNR50GetVolumeRight(value); audio->volumeLeft = GBRegisterNR50GetVolumeLeft(value); } void GBAudioWriteNR51(struct GBAudio* audio, uint8_t value) { - GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0x2); + GBAudioRun(audio, mTimingCurrentTime(audio->timing), 0xF); audio->ch1Right = GBRegisterNR51GetCh1Right(value); audio->ch2Right = GBRegisterNR51GetCh2Right(value); audio->ch3Right = GBRegisterNR51GetCh3Right(value); @@ -480,7 +503,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { GBAudioSample(audio, timestamp); } - if (audio->playingCh1 && (channels & 0x1)) { + if (audio->playingCh1 && (channels & 0x1) && audio->ch1.envelope.dead != 2) { int period = 4 * (2048 - audio->ch1.control.frequency) * audio->timingFactor; int32_t diff = timestamp - audio->ch1.lastUpdate; if (diff >= period) { @@ -490,7 +513,7 @@ void GBAudioRun(struct GBAudio* audio, int32_t timestamp, int channels) { _updateSquareSample(&audio->ch1); } } - if (audio->playingCh2 && (channels & 0x2)) { + if (audio->playingCh2 && (channels & 0x2) && audio->ch2.envelope.dead != 2) { int period = 4 * (2048 - audio->ch2.control.frequency) * audio->timingFactor; int32_t diff = timestamp - audio->ch2.lastUpdate; if (diff >= period) { @@ -863,7 +886,7 @@ bool _writeEnvelope(struct GBAudioEnvelope* envelope, uint8_t value, enum GBAudi envelope->currentVolume &= 0xF; } _updateEnvelopeDead(envelope); - return (envelope->initialVolume || envelope->direction) && envelope->dead != 2; + return envelope->initialVolume || envelope->direction; } static void _updateSquareSample(struct GBAudioSquareChannel* ch) { diff --git a/src/gb/gb.c b/src/gb/gb.c index dc3a37191..a3a870f28 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -596,13 +596,13 @@ void GBReset(struct SM83Core* cpu) { GBVideoReset(&gb->video); GBTimerReset(&gb->timer); GBIOReset(gb); + GBAudioReset(&gb->audio); if (!gb->biosVf && gb->memory.rom) { GBSkipBIOS(gb); } else { mTimingSchedule(&gb->timing, &gb->timer.event, 0); } - GBAudioReset(&gb->audio); GBSIOReset(&gb->sio); cpu->memory.setActiveRegion(cpu, cpu->pc); @@ -744,6 +744,25 @@ void GBSkipBIOS(struct GB* gb) { GBUnmapBIOS(gb); } + GBIOWrite(gb, GB_REG_NR52, 0xF1); + GBIOWrite(gb, GB_REG_NR14, 0x3F); + GBIOWrite(gb, GB_REG_NR10, 0x80); + GBIOWrite(gb, GB_REG_NR11, 0xBF); + GBIOWrite(gb, GB_REG_NR12, 0xF3); + GBIOWrite(gb, GB_REG_NR13, 0xF3); + GBIOWrite(gb, GB_REG_NR24, 0x3F); + GBIOWrite(gb, GB_REG_NR21, 0x3F); + GBIOWrite(gb, GB_REG_NR22, 0x00); + GBIOWrite(gb, GB_REG_NR34, 0x3F); + GBIOWrite(gb, GB_REG_NR30, 0x7F); + GBIOWrite(gb, GB_REG_NR31, 0xFF); + GBIOWrite(gb, GB_REG_NR32, 0x9F); + GBIOWrite(gb, GB_REG_NR44, 0x3F); + GBIOWrite(gb, GB_REG_NR41, 0xFF); + GBIOWrite(gb, GB_REG_NR42, 0x00); + GBIOWrite(gb, GB_REG_NR43, 0x00); + GBIOWrite(gb, GB_REG_NR50, 0x77); + GBIOWrite(gb, GB_REG_NR51, 0xF3); GBIOWrite(gb, GB_REG_LCDC, 0x91); gb->memory.io[GB_REG_BANK] = 0x1; GBVideoSkipBIOS(&gb->video); diff --git a/src/gb/io.c b/src/gb/io.c index 06a7927cd..ba4473550 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -162,36 +162,7 @@ void GBIOReset(struct GB* gb) { GBIOWrite(gb, GB_REG_TMA, 0); GBIOWrite(gb, GB_REG_TAC, 0); GBIOWrite(gb, GB_REG_IF, 1); - gb->audio.playingCh1 = false; - gb->audio.playingCh2 = false; - gb->audio.playingCh3 = false; - gb->audio.playingCh4 = false; - GBIOWrite(gb, GB_REG_NR52, 0xF1); - GBIOWrite(gb, GB_REG_NR14, 0x3F); - GBIOWrite(gb, GB_REG_NR10, 0x80); - GBIOWrite(gb, GB_REG_NR11, 0xBF); - GBIOWrite(gb, GB_REG_NR12, 0xF3); - GBIOWrite(gb, GB_REG_NR13, 0xF3); - GBIOWrite(gb, GB_REG_NR24, 0x3F); - GBIOWrite(gb, GB_REG_NR21, 0x3F); - GBIOWrite(gb, GB_REG_NR22, 0x00); - GBIOWrite(gb, GB_REG_NR34, 0x3F); - GBIOWrite(gb, GB_REG_NR30, 0x7F); - GBIOWrite(gb, GB_REG_NR31, 0xFF); - GBIOWrite(gb, GB_REG_NR32, 0x9F); - GBIOWrite(gb, GB_REG_NR44, 0x3F); - GBIOWrite(gb, GB_REG_NR41, 0xFF); - GBIOWrite(gb, GB_REG_NR42, 0x00); - GBIOWrite(gb, GB_REG_NR43, 0x00); - GBIOWrite(gb, GB_REG_NR50, 0x77); - GBIOWrite(gb, GB_REG_NR51, 0xF3); - if (!gb->biosVf) { - GBIOWrite(gb, GB_REG_LCDC, 0x91); - gb->memory.io[GB_REG_BANK] = 1; - } else { - GBIOWrite(gb, GB_REG_LCDC, 0x00); - gb->memory.io[GB_REG_BANK] = 0xFF; - } + GBIOWrite(gb, GB_REG_LCDC, 0x00); GBIOWrite(gb, GB_REG_SCY, 0x00); GBIOWrite(gb, GB_REG_SCX, 0x00); GBIOWrite(gb, GB_REG_LYC, 0x00); @@ -203,6 +174,7 @@ void GBIOReset(struct GB* gb) { } GBIOWrite(gb, GB_REG_WY, 0x00); GBIOWrite(gb, GB_REG_WX, 0x00); + gb->memory.io[GB_REG_BANK] = 0xFF; if (gb->model & GB_MODEL_CGB) { GBIOWrite(gb, GB_REG_KEY0, 0); GBIOWrite(gb, GB_REG_JOYP, 0xFF); diff --git a/src/gb/memory.c b/src/gb/memory.c index 50b9b7d6f..5c4d97876 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -558,7 +558,7 @@ uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { gb->memory.hdmaDest |= 0x8000; bool wasHdma = gb->memory.isHdma; gb->memory.isHdma = value & 0x80; - if ((!wasHdma && !gb->memory.isHdma) || (GBRegisterLCDCIsEnable(gb->memory.io[GB_REG_LCDC]) && gb->video.mode == 0)) { + if ((!wasHdma && !gb->memory.isHdma) || gb->video.mode == 0) { if (gb->memory.isHdma) { gb->memory.hdmaRemaining = 0x10; } else { @@ -566,8 +566,6 @@ uint8_t GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) { } gb->cpuBlocked = true; mTimingSchedule(&gb->timing, &gb->memory.hdmaEvent, 0); - } else if (gb->memory.isHdma && !GBRegisterLCDCIsEnable(gb->memory.io[GB_REG_LCDC])) { - return 0x80 | ((value + 1) & 0x7F); } return value & 0x7F; } diff --git a/src/gba/cheats.c b/src/gba/cheats.c index ec92bc3c2..08848077b 100644 --- a/src/gba/cheats.c +++ b/src/gba/cheats.c @@ -126,13 +126,13 @@ static bool GBACheatAddAutodetect(struct GBACheatSet* set, uint32_t op1, uint32_ GBACheatSetGameSharkVersion(set, GBA_GS_PARV3); } - rgsaP = GBACheatGameSharkProbability(op1, op1); + rgsaP = GBACheatGameSharkProbability(op1, op2); if (rgsaP > maxProbability) { maxProbability = rgsaP; GBACheatSetGameSharkVersion(set, GBA_GS_GSAV1_RAW); } - rparP = GBACheatProActionReplayProbability(op1, op1); + rparP = GBACheatProActionReplayProbability(op1, op2); if (rparP > maxProbability) { maxProbability = rparP; GBACheatSetGameSharkVersion(set, GBA_GS_PARV3_RAW); diff --git a/src/gba/core.c b/src/gba/core.c index 40269b8bf..73c9b6385 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -711,8 +711,8 @@ static void _GBACoreReset(struct mCore* core) { #endif ARMReset(core->cpu); - bool forceSkip = gba->romVf && GBAIsMB(gba->romVf); - if (!(forceSkip || core->opts.skipBios) && (gba->romVf || gba->memory.rom) && gba->pristineRomSize >= 0xA0 && gba->biosVf) { + bool forceSkip = gba->mbVf || core->opts.skipBios; + if (!forceSkip && (gba->romVf || gba->memory.rom) && gba->pristineRomSize >= 0xA0 && gba->biosVf) { uint32_t crc = doCrc32(&gba->memory.rom[1], 0x9C); if (crc != LOGO_CRC32) { mLOG(STATUS, WARN, "Invalid logo, skipping BIOS"); @@ -720,7 +720,7 @@ static void _GBACoreReset(struct mCore* core) { } } - if (forceSkip || (core->opts.skipBios && (gba->romVf || gba->memory.rom))) { + if (forceSkip) { GBASkipBIOS(core->board); } diff --git a/src/gba/dma.c b/src/gba/dma.c index 14b9fb777..60a8eb056 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -244,7 +244,6 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { struct GBAMemory* memory = &gba->memory; struct ARMCore* cpu = gba->cpu; uint32_t width = 2 << GBADMARegisterGetWidth(info->reg); - int32_t wordsRemaining = info->nextCount; uint32_t source = info->nextSource; uint32_t dest = info->nextDest; uint32_t sourceRegion = source >> BASE_OFFSET; @@ -252,6 +251,8 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { int32_t cycles = 2; gba->cpuBlocked = true; + gba->performingDMA = 1 | (number << 1); + if (info->count == info->nextCount) { if (width == 4) { cycles += memory->waitstatesNonseq32[sourceRegion] + memory->waitstatesNonseq32[destRegion]; @@ -267,12 +268,10 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } info->when += cycles; - gba->performingDMA = 1 | (number << 1); if (width == 4) { if (source) { memory->dmaTransferRegister = cpu->memory.load32(cpu, source, 0); } - gba->bus = memory->dmaTransferRegister; cpu->memory.store32(cpu, dest, memory->dmaTransferRegister, 0); } else { if (sourceRegion == REGION_CART2_EX && (memory->savedata.type == SAVEDATA_EEPROM || memory->savedata.type == SAVEDATA_EEPROM512)) { @@ -288,14 +287,13 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { GBASavedataInitEEPROM(&memory->savedata); } if (memory->savedata.type == SAVEDATA_EEPROM512 || memory->savedata.type == SAVEDATA_EEPROM) { - GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, wordsRemaining); + GBASavedataWriteEEPROM(&memory->savedata, memory->dmaTransferRegister, info->nextCount); } } else { cpu->memory.store16(cpu, dest, memory->dmaTransferRegister, 0); - } - gba->bus = memory->dmaTransferRegister; } + gba->bus = memory->dmaTransferRegister; int sourceOffset; if (info->nextSource >= BASE_CART0 && info->nextSource < BASE_CART_SRAM && GBADMARegisterGetSrcControl(info->reg) < 3) { @@ -305,15 +303,12 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width; if (source) { - source += sourceOffset; + info->nextSource += sourceOffset; } - dest += destOffset; - --wordsRemaining; - gba->performingDMA = 0; + info->nextDest += destOffset; + --info->nextCount; - info->nextCount = wordsRemaining; - info->nextSource = source; - info->nextDest = dest; + gba->performingDMA = 0; int i; for (i = 0; i < 4; ++i) { @@ -324,7 +319,7 @@ void GBADMAService(struct GBA* gba, int number, struct GBADMA* info) { } } - if (!wordsRemaining) { + if (!info->nextCount) { info->nextCount |= 0x80000000; if (sourceRegion < REGION_CART0 || destRegion < REGION_CART0) { info->when += 2; diff --git a/src/gba/gba.c b/src/gba/gba.c index d3f0d9ee3..37408bf6c 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -275,8 +275,10 @@ void GBASkipBIOS(struct GBA* gba) { if (cpu->gprs[ARM_PC] == BASE_RESET + WORD_SIZE_ARM) { if (gba->memory.rom) { cpu->gprs[ARM_PC] = BASE_CART0; - } else { + } else if (gba->memory.wram[0x30]) { cpu->gprs[ARM_PC] = BASE_WORKING_RAM + 0xC0; + } else { + cpu->gprs[ARM_PC] = BASE_WORKING_RAM; } gba->video.vcount = 0x7E; gba->memory.io[REG_VCOUNT >> 1] = 0x7E; diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 3c374bb97..e203debe8 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -664,10 +664,12 @@ static const char* const _finalize = " if (((topFlags.y & 13) == 5 || topFlags.w > 0) && (bottomFlags.y & 2) == 2) {\n" " topPixel.rgb *= float(topFlags.z) / 16.;\n" " topPixel.rgb += bottomPixel.rgb * float(windowFlags.y) / 16.;\n" - " } else if ((topFlags.y & 13) == 9) {\n" - " topPixel.rgb += (1. - topPixel.rgb) * float(windowFlags.z) / 16.;\n" - " } else if ((topFlags.y & 13) == 13) {\n" - " topPixel.rgb -= topPixel.rgb * float(windowFlags.z) / 16.;\n" + " } else if (topFlags.w == 0) { \n" + " if ((topFlags.y & 13) == 9) {\n" + " topPixel.rgb += (1. - topPixel.rgb) * float(windowFlags.z) / 16.;\n" + " } else if ((topFlags.y & 13) == 13) {\n" + " topPixel.rgb -= topPixel.rgb * float(windowFlags.z) / 16.;\n" + " }\n" " }\n" " color = topPixel;\n" "}"; diff --git a/src/platform/libretro/libretro.c b/src/platform/libretro/libretro.c index 7132ccffe..7d6cbee83 100644 --- a/src/platform/libretro/libretro.c +++ b/src/platform/libretro/libretro.c @@ -618,6 +618,39 @@ void retro_run(void) { core->desiredVideoDimensions(core, &width, &height); videoCallback(outputBuffer, width, height, BYTES_PER_PIXEL * 256); +#ifdef M_CORE_GBA + if (core->platform(core) == mPLATFORM_GBA) { + blip_t *audioChannelLeft = core->getAudioChannel(core, 0); + blip_t *audioChannelRight = core->getAudioChannel(core, 1); + int samplesAvail = blip_samples_avail(audioChannelLeft); + if (samplesAvail > 0) { + /* Update 'running average' of number of + * samples per frame. + * Note that this is not a true running + * average, but just a leaky-integrator/ + * exponential moving average, used because + * it is simple and fast (i.e. requires no + * window of samples). */ + audioSamplesPerFrameAvg = (SAMPLES_PER_FRAME_MOVING_AVG_ALPHA * (float)samplesAvail) + + ((1.0f - SAMPLES_PER_FRAME_MOVING_AVG_ALPHA) * audioSamplesPerFrameAvg); + size_t samplesToRead = (size_t)(audioSamplesPerFrameAvg); + /* Resize audio output buffer, if required */ + if (audioSampleBufferSize < (samplesToRead * 2)) { + audioSampleBufferSize = (samplesToRead * 2); + audioSampleBuffer = realloc(audioSampleBuffer, audioSampleBufferSize * sizeof(int16_t)); + } + int produced = blip_read_samples(audioChannelLeft, audioSampleBuffer, samplesToRead, true); + blip_read_samples(audioChannelRight, audioSampleBuffer + 1, samplesToRead, true); + if (produced > 0) { + if (audioLowPassEnabled) { + _audioLowPassFilter(audioSampleBuffer, produced); + } + audioCallback(audioSampleBuffer, (size_t)produced); + } + } + } +#endif + if (rumbleCallback) { if (rumbleUp) { rumbleCallback(0, RETRO_RUMBLE_STRONG, rumbleUp * 0xFFFF / (rumbleUp + rumbleDown)); diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index 847f45dbb..738bb27c4 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -121,6 +121,7 @@ set(SOURCE_FILES MessagePainter.cpp MultiplayerController.cpp ObjView.cpp + OpenGLBug.cpp OverrideView.cpp PaletteView.cpp PlacementControl.cpp diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index a0d2f8c3b..0493045a4 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -44,6 +44,8 @@ using QOpenGLFunctions_Baseline = QOpenGLFunctions_3_2_Core; #define OVERHEAD_NSEC 300000 #endif +#include "OpenGLBug.h" + using namespace QGBA; QHash DisplayGL::s_supports; @@ -428,10 +430,10 @@ void DisplayGL::setVideoProxy(std::shared_ptr proxy) { void DisplayGL::setupProxyThread() { m_proxyContext->moveToThread(&m_proxyThread); + m_proxySurface.create(); connect(&m_proxyThread, &QThread::started, m_proxyContext.get(), [this]() { m_proxyContext->setShareContext(m_painter->shareContext()); m_proxyContext->create(); - m_proxySurface.create(); m_proxyContext->makeCurrent(&m_proxySurface); #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); @@ -579,6 +581,7 @@ void PainterGL::create() { m_backend->filter = false; m_backend->lockAspectRatio = false; m_backend->interframeBlending = false; + m_gl->doneCurrent(); emit created(); } @@ -863,17 +866,23 @@ void PainterGL::dequeueAll(bool keep) { m_free.append(buffer); } } - m_queueTex.clear(); - m_freeTex.clear(); - for (auto tex : m_bridgeTexes) { - m_freeTex.enqueue(tex); - } - m_bridgeTexIn = m_freeTex.dequeue(); - m_bridgeTexOut = std::numeric_limits::max(); if (m_buffer && !keep) { m_free.append(m_buffer); m_buffer = nullptr; } + + m_queueTex.clear(); + m_freeTex.clear(); + for (auto tex : m_bridgeTexes) { + if (keep && tex == m_bridgeTexIn) { + continue; + } + m_freeTex.enqueue(tex); + } + if (!keep) { + m_bridgeTexIn = m_freeTex.dequeue(); + m_bridgeTexOut = std::numeric_limits::max(); + } } void PainterGL::setVideoProxy(std::shared_ptr proxy) { @@ -889,12 +898,20 @@ void PainterGL::setShaders(struct VDir* dir) { return; } #if defined(BUILD_GLES2) || defined(BUILD_GLES3) + if (!m_started) { + makeCurrent(); + } + if (m_shader.passes) { mGLES2ShaderDetach(reinterpret_cast(m_backend)); mGLES2ShaderFree(&m_shader); } mGLES2ShaderLoad(&m_shader, dir); mGLES2ShaderAttach(reinterpret_cast(m_backend), static_cast(m_shader.passes), m_shader.nPasses); + + if (!m_started) { + m_gl->doneCurrent(); + } #endif } @@ -903,10 +920,18 @@ void PainterGL::clearShaders() { return; } #if defined(BUILD_GLES2) || defined(BUILD_GLES3) + if (!m_started) { + makeCurrent(); + } + if (m_shader.passes) { mGLES2ShaderDetach(reinterpret_cast(m_backend)); mGLES2ShaderFree(&m_shader); } + + if (!m_started) { + m_gl->doneCurrent(); + } #endif } @@ -939,7 +964,17 @@ QOpenGLContext* PainterGL::shareContext() { void PainterGL::updateFramebufferHandle() { QOpenGLFunctions_Baseline* fn = m_gl->versionFunctions(); - fn->glFinish(); + // TODO: Figure out why glFlush doesn't work here on Intel/Windows + if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) { + fn->glFinish(); + } else { + fn->glFlush(); + } + + CoreController::Interrupter interrupter(m_context); + if (!m_context->hardwareAccelerated()) { + return; + } enqueue(m_bridgeTexIn); m_context->setFramebufferHandle(m_bridgeTexIn); } diff --git a/src/platform/qt/ForwarderController.cpp b/src/platform/qt/ForwarderController.cpp index fe0530a73..56e202019 100644 --- a/src/platform/qt/ForwarderController.cpp +++ b/src/platform/qt/ForwarderController.cpp @@ -180,6 +180,9 @@ void ForwarderController::downloadBuild(const QUrl& url) { connectReply(reply, BASE, &ForwarderController::gotBuild); connect(reply, &QNetworkReply::readyRead, this, [this, reply]() { + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 != 2) { + return; + } QByteArray data = reply->readAll(); m_sourceFile.write(data); }); @@ -236,8 +239,13 @@ void ForwarderController::connectReply(QNetworkReply* reply, Download download, emit buildFailed(); }); - connect(reply, &QNetworkReply::finished, this, [this, reply, next]() { - (this->*next)(reply); + connect(reply, &QNetworkReply::finished, this, [this, reply, download, next]() { + if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() / 100 == 3) { + QNetworkReply* newReply = GBAApp::app()->httpGet(reply->header(QNetworkRequest::LocationHeader).toString()); + connectReply(newReply, download, next); + } else { + (this->*next)(reply); + } }); connect(reply, &QNetworkReply::downloadProgress, this, [this, download](qint64 bytesReceived, qint64 bytesTotal) { emit downloadProgress(download, bytesReceived, bytesTotal); diff --git a/src/platform/qt/GBAApp.cpp b/src/platform/qt/GBAApp.cpp index 1e3c6a894..30287262a 100644 --- a/src/platform/qt/GBAApp.cpp +++ b/src/platform/qt/GBAApp.cpp @@ -82,7 +82,9 @@ GBAApp::GBAApp(int& argc, char* argv[], ConfigController* config) m_configController->updateOption("useDiscordPresence"); #endif +#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)) m_netman.setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy); +#endif cleanupAfterUpdate(); diff --git a/src/platform/qt/OpenGLBug.cpp b/src/platform/qt/OpenGLBug.cpp new file mode 100644 index 000000000..e00310c56 --- /dev/null +++ b/src/platform/qt/OpenGLBug.cpp @@ -0,0 +1,34 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "OpenGLBug.h" + +#include +#include + +namespace QGBA { + +bool glContextHasBug(OpenGLBug bug) { + QOpenGLContext* context = QOpenGLContext::currentContext(); + if (!context) { + abort(); + } + QOpenGLFunctions* fn = context->functions(); + QString vendor(reinterpret_cast(fn->glGetString(GL_VENDOR))); + QString renderer(reinterpret_cast(fn->glGetString(GL_RENDERER))); + + switch (bug) { + case OpenGLBug::CROSS_THREAD_FLUSH: +#ifndef Q_OS_WIN + return false; +#else + return vendor == "Intel"; +#endif + default: + return false; + } +} + +} diff --git a/src/platform/qt/OpenGLBug.h b/src/platform/qt/OpenGLBug.h new file mode 100644 index 000000000..fda0ed555 --- /dev/null +++ b/src/platform/qt/OpenGLBug.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#pragma once + +namespace QGBA { + +enum class OpenGLBug { + // mgba.io/i/2761 + CROSS_THREAD_FLUSH +}; + +bool glContextHasBug(OpenGLBug); + +} diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index bfcc408a6..5f5a2b09e 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1111,6 +1111,8 @@ void Window::changeRenderer() { if (!m_controller) { return; } + + CoreController::Interrupter interrupter(m_controller); if (m_config->getOption("hwaccelVideo").toInt() && m_display->supportsShaders() && m_controller->supportsFeature(CoreController::Feature::OPENGL)) { std::shared_ptr proxy = m_display->videoProxy(); if (!proxy) {