From 9a0da39848a540ef3909f0051160843f093dfd83 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2020 16:28:02 -0800 Subject: [PATCH 01/20] GBA Video: Fix OpenGL fragment data binding --- CHANGES | 1 + src/gba/renderers/gl.c | 51 +++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/CHANGES b/CHANGES index cb24f5ed0..57e84048a 100644 --- a/CHANGES +++ b/CHANGES @@ -101,6 +101,7 @@ Other fixes: - 3DS: Fix screen darkening (fixes mgba.io/i/1562) - Core: Fix uninitialized memory issues with graphics caches - Core: Return null for out of bounds cached tile VRAM querying + - GBA Video: Fix OpenGL fragment data binding - Debugger: Fix tracing skipping instructions (fixes mgba.io/i/1614) - OpenGL: Only invalidate texture if dimensions change (fixes mgba.io/i/1612) - Qt: Fix fast forward mute being reset (fixes mgba.io/i/1574) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 7bc564648..18a689ee3 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -696,7 +696,7 @@ void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer) { renderer->scale = 1; } -static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShader* shader, const char** shaderBuffer, int shaderBufferLines, GLuint vs, const struct GBAVideoGLUniform* uniforms, char* log) { +static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVideoGLShader* shader, const char** shaderBuffer, int shaderBufferLines, GLuint vs, const struct GBAVideoGLUniform* uniforms, const char* const* outFrags, char* log) { GLuint program = glCreateProgram(); shader->program = program; @@ -709,16 +709,20 @@ static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVide if (log[0]) { mLOG(GBA_VIDEO, ERROR, "Fragment shader compilation failure: %s", log); } + size_t i; +#ifndef BUILD_GLES3 + for (i = 0; outFrags[i]; ++i) { + glBindFragDataLocation(program, i, outFrags[i]); + } +#else + UNUSED(outFrags); +#endif glLinkProgram(program); glGetProgramInfoLog(program, 2048, 0, log); if (log[0]) { mLOG(GBA_VIDEO, ERROR, "Program link failure: %s", log); } glDeleteShader(fs); -#ifndef BUILD_GLES3 - glBindFragDataLocation(program, 0, "color"); - glBindFragDataLocation(program, 1, "flags"); -#endif glGenVertexArrays(1, &shader->vao); glBindVertexArray(shader->vao); @@ -727,7 +731,6 @@ static void _compileShader(struct GBAVideoGLRenderer* glRenderer, struct GBAVide glEnableVertexAttribArray(positionLocation); glVertexAttribPointer(positionLocation, 2, GL_INT, GL_FALSE, 0, NULL); - size_t i; for (i = 0; uniforms[i].name; ++i) { shader->uniforms[uniforms[i].type] = glGetUniformLocation(program, uniforms[i].name); } @@ -838,56 +841,52 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { mLOG(GBA_VIDEO, ERROR, "Vertex shader compilation failure: %s", log); } + const char* const noWindow[] = {"color", "flags", NULL}; + const char* const window[] = {"color", "flags", "window", NULL}; + const char* const onlyWindow[] = {"window", NULL}; + const char* const onlyColor[] = {"color", NULL}; + shaderBuffer[1] = _renderMode0; shaderBuffer[2] = _renderTile16; - _compileShader(glRenderer, &glRenderer->bgShader[0], shaderBuffer, 3, vs, _uniformsMode0, log); + _compileShader(glRenderer, &glRenderer->bgShader[0], shaderBuffer, 3, vs, _uniformsMode0, noWindow, log); shaderBuffer[2] = _renderTile256; - _compileShader(glRenderer, &glRenderer->bgShader[1], shaderBuffer, 3, vs, _uniformsMode0, log); + _compileShader(glRenderer, &glRenderer->bgShader[1], shaderBuffer, 3, vs, _uniformsMode0, noWindow, log); shaderBuffer[1] = _renderMode2; shaderBuffer[2] = _interpolate; shaderBuffer[3] = _fetchTileOverflow; - _compileShader(glRenderer, &glRenderer->bgShader[2], shaderBuffer, 4, vs, _uniformsMode2, log); + _compileShader(glRenderer, &glRenderer->bgShader[2], shaderBuffer, 4, vs, _uniformsMode2, noWindow, log); shaderBuffer[3] = _fetchTileNoOverflow; - _compileShader(glRenderer, &glRenderer->bgShader[3], shaderBuffer, 4, vs, _uniformsMode2, log); + _compileShader(glRenderer, &glRenderer->bgShader[3], shaderBuffer, 4, vs, _uniformsMode2, noWindow, log); shaderBuffer[1] = _renderMode4; shaderBuffer[2] = _interpolate; - _compileShader(glRenderer, &glRenderer->bgShader[4], shaderBuffer, 3, vs, _uniformsMode4, log); + _compileShader(glRenderer, &glRenderer->bgShader[4], shaderBuffer, 3, vs, _uniformsMode4, noWindow, log); shaderBuffer[1] = _renderMode35; shaderBuffer[2] = _interpolate; - _compileShader(glRenderer, &glRenderer->bgShader[5], shaderBuffer, 3, vs, _uniformsMode35, log); + _compileShader(glRenderer, &glRenderer->bgShader[5], shaderBuffer, 3, vs, _uniformsMode35, noWindow, log); shaderBuffer[1] = _renderObj; shaderBuffer[2] = _renderTile16; - _compileShader(glRenderer, &glRenderer->objShader[0], shaderBuffer, 3, vs, _uniformsObj, log); -#ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->objShader[0].program, 2, "window"); -#endif + _compileShader(glRenderer, &glRenderer->objShader[0], shaderBuffer, 3, vs, _uniformsObj, window, log); shaderBuffer[2] = _renderTile256; - _compileShader(glRenderer, &glRenderer->objShader[1], shaderBuffer, 3, vs, _uniformsObj, log); -#ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->objShader[1].program, 2, "window"); -#endif + _compileShader(glRenderer, &glRenderer->objShader[1], shaderBuffer, 3, vs, _uniformsObj, window, log); shaderBuffer[1] = _renderObjPriority; - _compileShader(glRenderer, &glRenderer->objShader[2], shaderBuffer, 2, vs, _uniformsObjPriority, log); + _compileShader(glRenderer, &glRenderer->objShader[2], shaderBuffer, 2, vs, _uniformsObjPriority, noWindow, log); shaderBuffer[1] = _renderWindow; - _compileShader(glRenderer, &glRenderer->windowShader, shaderBuffer, 2, vs, _uniformsWindow, log); -#ifndef BUILD_GLES3 - glBindFragDataLocation(glRenderer->windowShader.program, 0, "window"); -#endif + _compileShader(glRenderer, &glRenderer->windowShader, shaderBuffer, 2, vs, _uniformsWindow, onlyWindow, log); shaderBuffer[1] = _finalize; - _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, log); + _compileShader(glRenderer, &glRenderer->finalizeShader, shaderBuffer, 2, vs, _uniformsFinalize, onlyColor, log); glBindVertexArray(0); glDeleteShader(vs); From f44846cb9a0818af13830a34c0deee830b4451d4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2020 19:15:36 -0800 Subject: [PATCH 02/20] GBA Video: Changing OpenGL scaling no longer requires restart --- CHANGES | 1 + include/mgba/internal/gba/renderers/gl.h | 1 + src/gba/core.c | 14 ++++++ src/gba/renderers/gl.c | 54 ++++++++++++++++-------- src/platform/qt/Display.h | 1 + src/platform/qt/DisplayGL.cpp | 13 +++++- src/platform/qt/DisplayGL.h | 1 + src/platform/qt/SettingsView.cpp | 2 +- src/platform/qt/Window.cpp | 7 +++ 9 files changed, 75 insertions(+), 19 deletions(-) diff --git a/CHANGES b/CHANGES index 57e84048a..396c882a5 100644 --- a/CHANGES +++ b/CHANGES @@ -121,6 +121,7 @@ Misc: - GBA: Trim non-movie ROMs to 32 MiB if applicable - GBA Audio: Redo channel 4 batching for GBA only - GBA I/O: Stop logging several harmless invalid register reads + - GBA Video: Changing OpenGL scaling no longer requires restart - Debugger: Separate aliases from main commands - Debugger: Print break-/watchpoint ID when breaking in CLI - Debugger: Minor interface cleanup diff --git a/include/mgba/internal/gba/renderers/gl.h b/include/mgba/internal/gba/renderers/gl.h index b0fab6e7c..7d30a3e1d 100644 --- a/include/mgba/internal/gba/renderers/gl.h +++ b/include/mgba/internal/gba/renderers/gl.h @@ -196,6 +196,7 @@ struct GBAVideoGLRenderer { }; void GBAVideoGLRendererCreate(struct GBAVideoGLRenderer* renderer); +void GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer* renderer, int scale); #endif diff --git a/src/gba/core.c b/src/gba/core.c index 8f3e64a57..3c1ba6dd2 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -347,6 +347,20 @@ static void _GBACoreReloadConfigOption(struct mCore* core, const char* option, c } return; } +#if defined(BUILD_GLES2) || defined(BUILD_GLES3) + struct GBACore* gbacore = (struct GBACore*) core; + if (strcmp("videoScale", option) == 0) { + if (config != &core->config) { + mCoreConfigCopyValue(&core->config, config, "videoScale"); + } + if (gbacore->glRenderer.outputTex != (unsigned) -1 && mCoreConfigGetIntValue(&core->config, "hwaccelVideo", &fakeBool) && fakeBool) { + int scale; + mCoreConfigGetIntValue(config, "videoScale", &scale); + GBAVideoGLRendererSetScale(&gbacore->glRenderer, scale); + } + return; + } +#endif } static void _GBACoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 18a689ee3..5b73f7c2c 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -755,19 +755,7 @@ static void _initFramebufferTexture(GLuint tex, GLenum format, GLenum attachment _initFramebufferTextureEx(tex, format, format, GL_UNSIGNED_BYTE, attachment, scale); } -void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { - struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; - glRenderer->temporaryBuffer = NULL; - - glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); - glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers); - - glGenTextures(1, &glRenderer->vramTex); - glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); - +static void _initFramebuffers(struct GBAVideoGLRenderer* glRenderer) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OBJ]); _initFramebufferTexture(glRenderer->layers[GBA_GL_TEX_OBJ_COLOR], GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); _initFramebufferTextureEx(glRenderer->layers[GBA_GL_TEX_OBJ_FLAGS], GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT1, glRenderer->scale); @@ -784,7 +772,28 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glBindFramebuffer(GL_FRAMEBUFFER, glRenderer->fbo[GBA_GL_FBO_OUTPUT]); _initFramebufferTexture(glRenderer->outputTex, GL_RGB, GL_COLOR_ATTACHMENT0, glRenderer->scale); + int i; + for (i = 0; i < 4; ++i) { + struct GBAVideoGLBackground* bg = &glRenderer->bg[i]; + glBindFramebuffer(GL_FRAMEBUFFER, bg->fbo); + _initFramebufferTexture(bg->tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); + _initFramebufferTextureEx(bg->flags, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT1, glRenderer->scale); + } glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { + struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->temporaryBuffer = NULL; + + glGenFramebuffers(GBA_GL_FBO_MAX, glRenderer->fbo); + glGenTextures(GBA_GL_TEX_MAX, glRenderer->layers); + + glGenTextures(1, &glRenderer->vramTex); + glBindTexture(GL_TEXTURE_2D, glRenderer->vramTex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 256, 192, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 0); glGenBuffers(1, &glRenderer->vbo); glBindBuffer(GL_ARRAY_BUFFER, glRenderer->vbo); @@ -817,11 +826,9 @@ void GBAVideoGLRendererInit(struct GBAVideoRenderer* renderer) { glGenFramebuffers(1, &bg->fbo); glGenTextures(1, &bg->tex); glGenTextures(1, &bg->flags); - glBindFramebuffer(GL_FRAMEBUFFER, bg->fbo); - _initFramebufferTexture(bg->tex, GL_RGBA, GL_COLOR_ATTACHMENT0, glRenderer->scale); - _initFramebufferTextureEx(bg->flags, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, GL_COLOR_ATTACHMENT1, glRenderer->scale); } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + + _initFramebuffers(glRenderer); char log[2048]; const GLchar* shaderBuffer[4]; @@ -1851,4 +1858,17 @@ void GBAVideoGLRendererDrawWindow(struct GBAVideoGLRenderer* renderer, int y) { glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } +void GBAVideoGLRendererSetScale(struct GBAVideoGLRenderer* renderer, int scale) { + if (scale == renderer->scale) { + return; + } + if (renderer->temporaryBuffer) { + mappedMemoryFree(renderer->temporaryBuffer, GBA_VIDEO_HORIZONTAL_PIXELS * GBA_VIDEO_VERTICAL_PIXELS * renderer->scale * renderer->scale * BYTES_PER_PIXEL); + renderer->temporaryBuffer = NULL; + } + renderer->scale = scale; + _initFramebuffers(renderer); + renderer->paletteDirty = true; +} + #endif diff --git a/src/platform/qt/Display.h b/src/platform/qt/Display.h index ce2a5cffc..e739358c1 100644 --- a/src/platform/qt/Display.h +++ b/src/platform/qt/Display.h @@ -51,6 +51,7 @@ public: virtual bool supportsShaders() const = 0; virtual VideoShader* shaders() = 0; virtual int framebufferHandle() { return -1; } + virtual void setVideoScale(int scale) {} virtual void setVideoProxy(std::shared_ptr proxy) { m_videoProxy = proxy; } std::shared_ptr videoProxy() { return m_videoProxy; } diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index db1f2e42d..9de39ae86 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -218,7 +218,6 @@ void DisplayGL::clearShaders() { QMetaObject::invokeMethod(m_painter, "clearShaders"); } - void DisplayGL::resizeContext() { if (m_drawThread) { m_isDrawing = false; @@ -227,6 +226,15 @@ void DisplayGL::resizeContext() { } } +void DisplayGL::setVideoScale(int scale) { + if (m_drawThread) { + m_isDrawing = false; + CoreController::Interrupter interrupter(m_context); + mCoreConfigSetIntValue(&m_context->thread()->core->config, "videoScale", scale); + QMetaObject::invokeMethod(m_painter, "resizeContext", Qt::BlockingQueuedConnection); + } +} + void DisplayGL::resizeEvent(QResizeEvent* event) { Display::resizeEvent(event); resizePainter(); @@ -348,6 +356,9 @@ void PainterGL::resizeContext() { return; } + mCore* core = m_context->thread()->core; + core->reloadConfigOption(core, "videoScale", NULL); + QSize size = m_context->screenDimensions(); m_backend->setDimensions(m_backend, size.width(), size.height()); } diff --git a/src/platform/qt/DisplayGL.h b/src/platform/qt/DisplayGL.h index 3eb5d8eeb..1ef943a95 100644 --- a/src/platform/qt/DisplayGL.h +++ b/src/platform/qt/DisplayGL.h @@ -62,6 +62,7 @@ public slots: void setShaders(struct VDir*) override; void clearShaders() override; void resizeContext() override; + void setVideoScale(int scale) override; protected: virtual void paintEvent(QPaintEvent*) override { forceDraw(); } diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index ed425a1e2..cd751c797 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -494,7 +494,7 @@ void SettingsView::updateConfig() { int videoScale = m_controller->getOption("videoScale", 1).toInt(); int hwaccelVideo = m_controller->getOption("hwaccelVideo").toInt(); - if (videoScale != m_ui.videoScale->value() || hwaccelVideo != m_ui.hwaccelVideo->currentIndex()) { + if (hwaccelVideo != m_ui.hwaccelVideo->currentIndex()) { emit videoRendererChanged(); } saveSetting("videoScale", m_ui.videoScale); diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 0a97e1f32..aa1d387d0 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -1617,6 +1617,13 @@ void Window::setupMenu(QMenuBar* menubar) { } }, this); + ConfigOption* videoScale = m_config->addOption("videoScale"); + videoScale->connect([this](const QVariant& value) { + if (m_display) { + m_display->setVideoScale(value.toInt()); + } + }, this); + m_actions.addHiddenAction(tr("Exit fullscreen"), "exitFullScreen", this, &Window::exitFullScreen, "frame", QKeySequence("Esc")); m_actions.addHeldAction(tr("GameShark Button (held)"), "holdGSButton", [this](bool held) { From 97e2cf08ab727dd7a6f47ebd0fe2ba70b8eeb8b5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2020 22:17:38 -0800 Subject: [PATCH 03/20] Vita: Avoid uncached memcpy --- src/platform/psp2/main.c | 2 +- src/platform/psp2/psp2-context.c | 33 ++++++++++++++++++-------------- src/platform/psp2/psp2-context.h | 1 + 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/platform/psp2/main.c b/src/platform/psp2/main.c index 8451515ea..6a96a7456 100644 --- a/src/platform/psp2/main.c +++ b/src/platform/psp2/main.c @@ -152,7 +152,7 @@ int main() { .teardown = mPSP2Teardown, .gameLoaded = mPSP2LoadROM, .gameUnloaded = mPSP2UnloadROM, - .prepareForFrame = NULL, + .prepareForFrame = mPSP2Swap, .drawFrame = mPSP2Draw, .drawScreenshot = mPSP2DrawScreenshot, .paused = mPSP2Paused, diff --git a/src/platform/psp2/psp2-context.c b/src/platform/psp2/psp2-context.c index 7e96f24fb..b777ec938 100644 --- a/src/platform/psp2/psp2-context.c +++ b/src/platform/psp2/psp2-context.c @@ -51,8 +51,8 @@ static enum ScreenMode { } screenMode; static void* outputBuffer; -static vita2d_texture* tex; -static vita2d_texture* oldTex; +static int currentTex; +static vita2d_texture* tex[4]; static vita2d_texture* screenshot; static Thread audioThread; static bool interframeBlending = false; @@ -324,12 +324,14 @@ void mPSP2Setup(struct mGUIRunner* runner) { unsigned width, height; runner->core->desiredVideoDimensions(runner->core, &width, &height); - tex = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); - oldTex = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + tex[0] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + tex[1] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + tex[2] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + tex[3] = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); + currentTex = 0; screenshot = vita2d_create_empty_texture_format(256, toPow2(height), SCE_GXM_TEXTURE_FORMAT_X8U8U8U8_1BGR); - outputBuffer = anonymousMemoryMap(256 * toPow2(height) * 4); - runner->core->setVideoBuffer(runner->core, outputBuffer, 256); + runner->core->setVideoBuffer(runner->core, vita2d_texture_get_datap(tex[currentTex]), 256); runner->core->setAudioBufferSize(runner->core, PSP2_SAMPLES); rotation.d.sample = _sampleRotation; @@ -490,8 +492,10 @@ void mPSP2Unpaused(struct mGUIRunner* runner) { void mPSP2Teardown(struct mGUIRunner* runner) { UNUSED(runner); CircleBufferDeinit(&rumble.history); - vita2d_free_texture(tex); - vita2d_free_texture(oldTex); + vita2d_free_texture(tex[0]); + vita2d_free_texture(tex[1]); + vita2d_free_texture(tex[2]); + vita2d_free_texture(tex[3]); vita2d_free_texture(screenshot); mappedMemoryFree(outputBuffer, 256 * 256 * 4); frameLimiter = true; @@ -583,17 +587,18 @@ void _drawTex(vita2d_texture* t, unsigned width, unsigned height, bool faded, bo tint); } +void mPSP2Swap(struct mGUIRunner* runner) { + currentTex = (currentTex + 1) & 3; + runner->core->setVideoBuffer(runner->core, vita2d_texture_get_datap(tex[currentTex]), 256); +} + void mPSP2Draw(struct mGUIRunner* runner, bool faded) { unsigned width, height; runner->core->desiredVideoDimensions(runner->core, &width, &height); - void* texpixels = vita2d_texture_get_datap(tex); if (interframeBlending) { - void* oldTexpixels = vita2d_texture_get_datap(oldTex); - memcpy(oldTexpixels, texpixels, 256 * height * 4); - _drawTex(oldTex, width, height, faded, false); + _drawTex(tex[(currentTex - 1) & 3], width, height, faded, false); } - memcpy(texpixels, outputBuffer, 256 * height * 4); - _drawTex(tex, width, height, faded, interframeBlending); + _drawTex(tex[currentTex], width, height, faded, interframeBlending); } void mPSP2DrawScreenshot(struct mGUIRunner* runner, const uint32_t* pixels, unsigned width, unsigned height, bool faded) { diff --git a/src/platform/psp2/psp2-context.h b/src/platform/psp2/psp2-context.h index 389f9f534..2c9a47e09 100644 --- a/src/platform/psp2/psp2-context.h +++ b/src/platform/psp2/psp2-context.h @@ -20,6 +20,7 @@ void mPSP2UnloadROM(struct mGUIRunner* runner); void mPSP2PrepareForFrame(struct mGUIRunner* runner); void mPSP2Paused(struct mGUIRunner* runner); void mPSP2Unpaused(struct mGUIRunner* runner); +void mPSP2Swap(struct mGUIRunner* runner); void mPSP2Draw(struct mGUIRunner* runner, bool faded); void mPSP2DrawScreenshot(struct mGUIRunner* runner, const color_t* pixels, unsigned width, unsigned height, bool faded); void mPSP2IncrementScreenMode(struct mGUIRunner* runner); From 84bddfad69bb0760d2c5734ac6a74c17f56da87b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 20 Jan 2020 18:09:26 -0800 Subject: [PATCH 04/20] GBA Video: Fix mosaic in modes 1-5 in OpenGL (fixes #1620) --- CHANGES | 1 + src/gba/renderers/gl.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 396c882a5..04108c128 100644 --- a/CHANGES +++ b/CHANGES @@ -102,6 +102,7 @@ Other fixes: - Core: Fix uninitialized memory issues with graphics caches - Core: Return null for out of bounds cached tile VRAM querying - GBA Video: Fix OpenGL fragment data binding + - GBA Video: Fix mosaic in modes 1-5 in OpenGL (fixes mgba.io/i/1620) - Debugger: Fix tracing skipping instructions (fixes mgba.io/i/1614) - OpenGL: Only invalidate texture if dimensions change (fixes mgba.io/i/1612) - Qt: Fix fast forward mute being reset (fixes mgba.io/i/1574) diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 5b73f7c2c..3c433e81f 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -268,10 +268,10 @@ static const char* const _renderMode2 = " ivec2 offset[4];\n" " vec2 incoord = texCoord;\n" " if (mosaic.x > 1) {\n" - " incoord.x = float(int(incoord.x) % mosaic.x);\n" + " incoord.x = floor(incoord.x - float(int(incoord.x) % mosaic.x));\n" " }\n" " if (mosaic.y > 1) {\n" - " incoord.y = float(int(incoord.y) % mosaic.y);\n" + " incoord.y = floor(incoord.y - float(int(incoord.y) % mosaic.y));\n" " }\n" " loadAffine(int(incoord.y), mat, offset);\n" " float y = fract(incoord.y);\n" @@ -321,10 +321,10 @@ static const char* const _renderMode35 = " ivec2 offset[4];\n" " vec2 incoord = texCoord;\n" " if (mosaic.x > 1) {\n" - " incoord.x = float(int(incoord.x) % mosaic.x);\n" + " incoord.x = floor(incoord.x - float(int(incoord.x) % mosaic.x));\n" " }\n" " if (mosaic.y > 1) {\n" - " incoord.y = float(int(incoord.y) % mosaic.y);\n" + " incoord.y = floor(incoord.y - float(int(incoord.y) % mosaic.y));\n" " }\n" " loadAffine(int(incoord.y), mat, offset);\n" " float y = fract(incoord.y);\n" @@ -386,10 +386,10 @@ static const char* const _renderMode4 = " ivec2 offset[4];\n" " vec2 incoord = texCoord;\n" " if (mosaic.x > 1) {\n" - " incoord.x = float(int(incoord.x) % mosaic.x);\n" + " incoord.x = floor(incoord.x - float(int(incoord.x) % mosaic.x));\n" " }\n" " if (mosaic.y > 1) {\n" - " incoord.y = float(int(incoord.y) % mosaic.y);\n" + " incoord.y = floor(incoord.y - float(int(incoord.y) % mosaic.y));\n" " }\n" " loadAffine(int(incoord.y), mat, offset);\n" " float y = fract(incoord.y);\n" From e53df9759e84207b8a26bb22a674f740cd605129 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 20 Jan 2020 18:11:13 -0800 Subject: [PATCH 05/20] Qt: Fix crash double-clicking menus in shortcut settings (fixes #1627) --- CHANGES | 1 + src/platform/qt/ShortcutView.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 04108c128..32c24ac18 100644 --- a/CHANGES +++ b/CHANGES @@ -114,6 +114,7 @@ Other fixes: - Qt: Fix sprite view using wrong base address (fixes mgba.io/i/1603) - Qt: Fix inability to clear default keybindings - Qt: Release held actions if they get rebound + - Qt: Fix crash double-clicking menus in shortcut settings (fixes mgba.io/i/1627) - Vita: Fix analog controls (fixes mgba.io/i/1554) - Wii: Fix game fast-forwarding after slowing down - Wii: Improve audio buffering (fixes mgba.io/i/1617) diff --git a/src/platform/qt/ShortcutView.cpp b/src/platform/qt/ShortcutView.cpp index 5f2c42065..78b600906 100644 --- a/src/platform/qt/ShortcutView.cpp +++ b/src/platform/qt/ShortcutView.cpp @@ -61,7 +61,7 @@ void ShortcutView::load(const QModelIndex& index) { } QString name = m_model->name(index); const Shortcut* item = m_controller->shortcut(name); - if (!item->action()) { + if (!item || !item->action()) { return; } int shortcut = item->shortcut(); From 6ae02d05536568c6139b201c72db41a126451235 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Mon, 20 Jan 2020 18:21:37 -0800 Subject: [PATCH 06/20] Qt: Fix record A/V window not updating resolution (fixes #1626) --- CHANGES | 1 + src/platform/qt/VideoView.cpp | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 32c24ac18..7ed6423b0 100644 --- a/CHANGES +++ b/CHANGES @@ -115,6 +115,7 @@ Other fixes: - Qt: Fix inability to clear default keybindings - Qt: Release held actions if they get rebound - Qt: Fix crash double-clicking menus in shortcut settings (fixes mgba.io/i/1627) + - Qt: Fix record A/V window not updating resolution (fixes mgba.io/i/1626) - Vita: Fix analog controls (fixes mgba.io/i/1554) - Wii: Fix game fast-forwarding after slowing down - Wii: Improve audio buffering (fixes mgba.io/i/1617) diff --git a/src/platform/qt/VideoView.cpp b/src/platform/qt/VideoView.cpp index 42d00f587..94557900c 100644 --- a/src/platform/qt/VideoView.cpp +++ b/src/platform/qt/VideoView.cpp @@ -197,11 +197,15 @@ VideoView::~VideoView() { } void VideoView::setController(std::shared_ptr controller) { - connect(controller.get(), &CoreController::stopping, this, &VideoView::stopRecording); - connect(this, &VideoView::recordingStarted, controller.get(), &CoreController::setAVStream); - connect(this, &VideoView::recordingStopped, controller.get(), &CoreController::clearAVStream, Qt::DirectConnection); + CoreController* controllerPtr = controller.get(); + connect(controllerPtr, &CoreController::frameAvailable, this, [this, controllerPtr]() { + setNativeResolution(controllerPtr->screenDimensions()); + }); + connect(controllerPtr, &CoreController::stopping, this, &VideoView::stopRecording); + connect(this, &VideoView::recordingStarted, controllerPtr, &CoreController::setAVStream); + connect(this, &VideoView::recordingStopped, controllerPtr, &CoreController::clearAVStream, Qt::DirectConnection); - setNativeResolution(controller->screenDimensions()); + setNativeResolution(controllerPtr->screenDimensions()); } void VideoView::startRecording() { @@ -225,6 +229,9 @@ void VideoView::stopRecording() { } void VideoView::setNativeResolution(const QSize& dims) { + if (dims.width() == m_nativeWidth && dims.height() == m_nativeHeight) { + return; + } m_nativeWidth = dims.width(); m_nativeHeight = dims.height(); m_ui.presetNative->setText(tr("Native (%0x%1)").arg(m_nativeWidth).arg(m_nativeHeight)); From 471c75ff262f382d58c9315a31b7c572df50cde6 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 Jan 2020 18:03:10 -0800 Subject: [PATCH 07/20] Qt: Update copyright date --- src/platform/qt/AboutScreen.ui | 2 +- src/platform/qt/ts/mgba-de.ts | 4 ++-- src/platform/qt/ts/mgba-es.ts | 4 ++-- src/platform/qt/ts/mgba-fr.ts | 4 ++-- src/platform/qt/ts/mgba-it.ts | 4 ++-- src/platform/qt/ts/mgba-ko.ts | 4 ++-- src/platform/qt/ts/mgba-tr.ts | 4 ++-- src/platform/qt/ts/mgba-zh_CN.ts | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/platform/qt/AboutScreen.ui b/src/platform/qt/AboutScreen.ui index c6f166e57..1b403088a 100644 --- a/src/platform/qt/AboutScreen.ui +++ b/src/platform/qt/AboutScreen.ui @@ -83,7 +83,7 @@ - © 2013 – 2019 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. diff --git a/src/platform/qt/ts/mgba-de.ts b/src/platform/qt/ts/mgba-de.ts index 88c112707..eac15422f 100644 --- a/src/platform/qt/ts/mgba-de.ts +++ b/src/platform/qt/ts/mgba-de.ts @@ -25,9 +25,9 @@ - © 2013 – 2019 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 – 2019 Jeffrey Pfau, lizenziert unter der Mozilla Public License, Version 2.0 + © 2013 – 2020 Jeffrey Pfau, lizenziert unter der Mozilla Public License, Version 2.0 Game Boy Advance ist ein eingetragenes Warenzeichen von Nintendo Co., Ltd. diff --git a/src/platform/qt/ts/mgba-es.ts b/src/platform/qt/ts/mgba-es.ts index 6df49af91..f02368962 100644 --- a/src/platform/qt/ts/mgba-es.ts +++ b/src/platform/qt/ts/mgba-es.ts @@ -30,9 +30,9 @@ - © 2013 – 2019 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 – 2019 Jeffrey Pfau, licenciado bajo la Mozilla Public License, versión 2.0 + © 2013 – 2020 Jeffrey Pfau, licenciado bajo la Mozilla Public License, versión 2.0 Game Boy Advance es una marca registrada de Nintendo Co., Ltd. diff --git a/src/platform/qt/ts/mgba-fr.ts b/src/platform/qt/ts/mgba-fr.ts index e3f541e38..c32559ddf 100644 --- a/src/platform/qt/ts/mgba-fr.ts +++ b/src/platform/qt/ts/mgba-fr.ts @@ -30,9 +30,9 @@ - © 2013 – 2018 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 – 2018 Jeffrey Pfau, est autorisé sous la license Publique de Mozilla, version 2.0 + © 2013 – 2020 Jeffrey Pfau, est autorisé sous la license Publique de Mozilla, version 2.0 Game Boy Advance est une marque de fabrique enregistré par Nintendo Co., Ltd. diff --git a/src/platform/qt/ts/mgba-it.ts b/src/platform/qt/ts/mgba-it.ts index 6b08a7f60..bc97c8978 100644 --- a/src/platform/qt/ts/mgba-it.ts +++ b/src/platform/qt/ts/mgba-it.ts @@ -24,9 +24,9 @@ {projectName} desidera ringraziare i seguenti sponsor di Patreon: - © 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 - 2016 Jeffrey Pfau, sotto licenza Mozilla Public License, versione 2.0 + © 2013 - 2020 Jeffrey Pfau, sotto licenza Mozilla Public License, versione 2.0 Game Boy Advance è un marchio registrato di Nintendo Co., Ltd. diff --git a/src/platform/qt/ts/mgba-ko.ts b/src/platform/qt/ts/mgba-ko.ts index 2eeb9313f..b8ce6b12c 100644 --- a/src/platform/qt/ts/mgba-ko.ts +++ b/src/platform/qt/ts/mgba-ko.ts @@ -24,9 +24,9 @@ {projectName}은 Patreon의 다음 고객에게 감사드립니다: - © 2013 – 2016 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 - 2016 Jeffrey Pfau, 모질라 공식 라이센스 버전 2.0에 따라 사용 허가되었습니다. + © 2013 - 2020 Jeffrey Pfau, 모질라 공식 라이센스 버전 2.0에 따라 사용 허가되었습니다. Game Boy Advance는 Nintendo Co., Ltd.의 등록 상표입니다. diff --git a/src/platform/qt/ts/mgba-tr.ts b/src/platform/qt/ts/mgba-tr.ts index af7604d05..7a160ba7c 100644 --- a/src/platform/qt/ts/mgba-tr.ts +++ b/src/platform/qt/ts/mgba-tr.ts @@ -30,9 +30,9 @@ - © 2013 – 2019 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 - 2019 Mozilla Public License, 2.0 sürümünde lisanslı Jeffrey Pfau + © 2013 - 2020 Mozilla Public License, 2.0 sürümünde lisanslı Jeffrey Pfau Game Boy Advance, Nintendo Co., Ltd.'nin tescilli ticari markasıdır. diff --git a/src/platform/qt/ts/mgba-zh_CN.ts b/src/platform/qt/ts/mgba-zh_CN.ts index 32cf34542..c922c39e8 100644 --- a/src/platform/qt/ts/mgba-zh_CN.ts +++ b/src/platform/qt/ts/mgba-zh_CN.ts @@ -30,9 +30,9 @@ - © 2013 – 2019 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 + © 2013 – 2020 Jeffrey Pfau, licensed under the Mozilla Public License, version 2.0 Game Boy Advance is a registered trademark of Nintendo Co., Ltd. - © 2013 – 2019 Jeffrey Pfau,基于 Mozilla 公共许可证(版本 2.0)授权 + © 2013 – 2020 Jeffrey Pfau,基于 Mozilla 公共许可证(版本 2.0)授权 Game Boy Advance 是任天堂有限公司(Nintendo Co., Ltd.)的注册商标。 From 2368391f33da9da072524c59646c8d0e2c885525 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 Jan 2020 18:17:11 -0800 Subject: [PATCH 08/20] CHANGES: Update for 0.8.0 --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 7ed6423b0..7aac48d61 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -0.8.0: (Future) +0.8.0: (2020-01-21) Features: - Improved logging configuration - One-Player BattleChip/Progress/Beast Link Gate support From 7fb5d7006e215a8bab770fb05bc7022a01bef48b Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 21 Jan 2020 18:59:00 -0800 Subject: [PATCH 09/20] CMake: Update version number --- version.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.cmake b/version.cmake index de381293f..7c750a47d 100644 --- a/version.cmake +++ b/version.cmake @@ -2,9 +2,9 @@ if(NOT PROJECT_NAME) set(PROJECT_NAME "mGBA") endif() set(LIB_VERSION_MAJOR 0) -set(LIB_VERSION_MINOR 8) +set(LIB_VERSION_MINOR 9) set(LIB_VERSION_PATCH 0) -set(LIB_VERSION_ABI 0.8) +set(LIB_VERSION_ABI 0.9) set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) set(SUMMARY "${PROJECT_NAME} Game Boy Advance Emulator") From d044c05f30cd6c7591c5ec03b310253fdc06d7d1 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 22 Jan 2020 18:19:43 -0800 Subject: [PATCH 10/20] Qt: Only dynamically reset video scale if a game is running --- CHANGES | 4 ++++ src/platform/qt/DisplayGL.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 7aac48d61..f78fd6a24 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +0.9.0: (Future) +Other fixes: + - Qt: Only dynamically reset video scale if a game is running + 0.8.0: (2020-01-21) Features: - Improved logging configuration diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 9de39ae86..3cb5bb8c9 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -356,8 +356,10 @@ void PainterGL::resizeContext() { return; } - mCore* core = m_context->thread()->core; - core->reloadConfigOption(core, "videoScale", NULL); + if (m_started) { + mCore* core = m_context->thread()->core; + core->reloadConfigOption(core, "videoScale", NULL); + } QSize size = m_context->screenDimensions(); m_backend->setDimensions(m_backend, size.width(), size.height()); From 541715008bea659104a1705caa69a7bfd3f36637 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Wed, 22 Jan 2020 18:22:25 -0800 Subject: [PATCH 11/20] Qt: Fix race condition with proxied video events --- CHANGES | 1 + src/feature/thread-proxy.c | 1 + src/platform/qt/VideoProxy.cpp | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index f78fd6a24..6c06fad42 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ 0.9.0: (Future) Other fixes: - Qt: Only dynamically reset video scale if a game is running + - Qt: Fix race condition with proxied video events 0.8.0: (2020-01-21) Features: diff --git a/src/feature/thread-proxy.c b/src/feature/thread-proxy.c index 29a3161e7..ba1785c46 100644 --- a/src/feature/thread-proxy.c +++ b/src/feature/thread-proxy.c @@ -138,6 +138,7 @@ static void _postEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event MutexLock(&proxyRenderer->mutex); proxyRenderer->event = event; ConditionWake(&proxyRenderer->toThreadCond); + ConditionWait(&proxyRenderer->fromThreadCond, &proxyRenderer->mutex); MutexUnlock(&proxyRenderer->mutex); } diff --git a/src/platform/qt/VideoProxy.cpp b/src/platform/qt/VideoProxy.cpp index 431de4d26..8a89ea533 100644 --- a/src/platform/qt/VideoProxy.cpp +++ b/src/platform/qt/VideoProxy.cpp @@ -7,6 +7,8 @@ #include "CoreController.h" +#include + using namespace QGBA; VideoProxy::VideoProxy() { @@ -81,11 +83,22 @@ bool VideoProxy::readData(void* data, size_t length, bool block) { } void VideoProxy::postEvent(enum mVideoLoggerEvent event) { - emit eventPosted(event); + if (QThread::currentThread() == thread()) { + // We're on the main thread + emit eventPosted(event); + } else { + m_mutex.lock(); + emit eventPosted(event); + m_fromThreadCond.wait(&m_mutex, 1); + m_mutex.unlock(); + } } void VideoProxy::handleEvent(int event) { + m_mutex.lock(); m_logger.d.handleEvent(&m_logger.d, static_cast(event)); + m_fromThreadCond.wakeAll(); + m_mutex.unlock(); } void VideoProxy::lock() { From 8b9cd78d0f1451cec0cc560dfa17c27ca06420a0 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 23 Jan 2020 18:25:29 -0800 Subject: [PATCH 12/20] GBA Memory: Misaligned SRAM writes are ignored --- CHANGES | 2 ++ src/gba/memory.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 6c06fad42..e565468c4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,6 @@ 0.9.0: (Future) +Emulation fixes: + - GBA Memory: Misaligned SRAM writes are ignored Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events diff --git a/src/gba/memory.c b/src/gba/memory.c index 091bfa1e1..d2ba5a419 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -772,12 +772,12 @@ uint32_t GBALoad8(struct ARMCore* cpu, uint32_t address, int* cycleCounter) { #define STORE_SRAM \ if (address & 0x3) { \ mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store32: 0x%08X", address); \ - value = 0; \ - } \ - GBAStore8(cpu, address & ~0x3, value, cycleCounter); \ - GBAStore8(cpu, (address & ~0x3) | 1, value, cycleCounter); \ - GBAStore8(cpu, (address & ~0x3) | 2, value, cycleCounter); \ - GBAStore8(cpu, (address & ~0x3) | 3, value, cycleCounter); + } else { \ + GBAStore8(cpu, address, value, cycleCounter); \ + GBAStore8(cpu, address | 1, value, cycleCounter); \ + GBAStore8(cpu, address | 2, value, cycleCounter); \ + GBAStore8(cpu, address | 3, value, cycleCounter); \ + } #define STORE_BAD \ mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store32: 0x%08X", address); @@ -923,8 +923,12 @@ void GBAStore16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle break; case REGION_CART_SRAM: case REGION_CART_SRAM_MIRROR: - GBAStore8(cpu, (address & ~0x1), value, cycleCounter); - GBAStore8(cpu, (address & ~0x1) | 1, value, cycleCounter); + if (address & 1) { + mLOG(GBA_MEM, GAME_ERROR, "Unaligned SRAM Store16: 0x%08X", address); + break; + } + GBAStore8(cpu, address, value, cycleCounter); + GBAStore8(cpu, address | 1, value, cycleCounter); break; default: mLOG(GBA_MEM, GAME_ERROR, "Bad memory Store16: 0x%08X", address); From 27882fbded835ca52b6b128da57b12e23cf715ba Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 01:46:15 -0800 Subject: [PATCH 13/20] ARM: Fix ALU reading PC after shifting --- CHANGES | 1 + src/arm/isa-arm.c | 47 ++++++++++++++++++++++------------------------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/CHANGES b/CHANGES index e565468c4..1cb136064 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ 0.9.0: (Future) Emulation fixes: + - ARM: Fix ALU reading PC after shifting - GBA Memory: Misaligned SRAM writes are ignored Other fixes: - Qt: Only dynamically reset video scale if a game is running diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index c88345f90..e0231652e 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -302,7 +302,10 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { DEFINE_INSTRUCTION_ARM(NAME, \ int rd = (opcode >> 12) & 0xF; \ int rn = (opcode >> 16) & 0xF; \ - UNUSED(rn); \ + int32_t n = cpu->gprs[rn]; \ + if (UNLIKELY(rn == ARM_PC && (opcode & 0x02000010) == 0x00000010)) { \ + n += WORD_SIZE_ARM; \ + } \ SHIFTER(cpu, opcode); \ BODY; \ S_BODY; \ @@ -465,58 +468,52 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { // Begin ALU definitions DEFINE_ALU_INSTRUCTION_ARM(ADD, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n + cpu->shifterOperand;) DEFINE_ALU_INSTRUCTION_ARM(ADC, ARM_ADDITION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n + cpu->shifterOperand + cpu->cpsr.c;) -DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n & cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(BIC, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] & ~cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(BIC, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n & ~cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMN, ARM_ADDITION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] + cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMN, ARM_ADDITION_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n + cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMP, ARM_SUBTRACTION_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] - cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(CMP, ARM_SUBTRACTION_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n - cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] ^ cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(EOR, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n ^ cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(MOV, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), +DEFINE_ALU_INSTRUCTION_ARM(MOV, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), cpu->gprs[rd] = cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(MVN, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), +DEFINE_ALU_INSTRUCTION_ARM(MVN, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), cpu->gprs[rd] = ~cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_ARM(ORR, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), - cpu->gprs[rd] = cpu->gprs[rn] | cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_ARM(ORR, ARM_NEUTRAL_S(n, cpu->shifterOperand, cpu->gprs[rd]), + cpu->gprs[rd] = n | cpu->shifterOperand;) DEFINE_ALU_INSTRUCTION_ARM(RSB, ARM_SUBTRACTION_S(cpu->shifterOperand, n, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = cpu->shifterOperand - n;) DEFINE_ALU_INSTRUCTION_ARM(RSC, ARM_SUBTRACTION_CARRY_S(cpu->shifterOperand, n, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = cpu->shifterOperand - n - !cpu->cpsr.c;) DEFINE_ALU_INSTRUCTION_ARM(SBC, ARM_SUBTRACTION_CARRY_S(n, cpu->shifterOperand, cpu->gprs[rd], !cpu->cpsr.c), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n - cpu->shifterOperand - !cpu->cpsr.c;) DEFINE_ALU_INSTRUCTION_ARM(SUB, ARM_SUBTRACTION_S(n, cpu->shifterOperand, cpu->gprs[rd]), - int32_t n = cpu->gprs[rn]; cpu->gprs[rd] = n - cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TEQ, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] ^ cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TEQ, ARM_NEUTRAL_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n ^ cpu->shifterOperand;) -DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TST, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, aluOut), - int32_t aluOut = cpu->gprs[rn] & cpu->shifterOperand;) +DEFINE_ALU_INSTRUCTION_S_ONLY_ARM(TST, ARM_NEUTRAL_S(n, cpu->shifterOperand, aluOut), + int32_t aluOut = n & cpu->shifterOperand;) // End ALU definitions From ab2a8c1e62c94c4b7c14af06a9e4647d982459f3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 01:46:56 -0800 Subject: [PATCH 14/20] ARM: Fix STR storing PC after address calculation --- CHANGES | 1 + src/arm/isa-arm.c | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 1cb136064..ea70ad6dc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ 0.9.0: (Future) Emulation fixes: - ARM: Fix ALU reading PC after shifting + - ARM: Fix STR storing PC after address calculation - GBA Memory: Misaligned SRAM writes are ignored Other fixes: - Qt: Only dynamically reset video scale if a game is running diff --git a/src/arm/isa-arm.c b/src/arm/isa-arm.c index e0231652e..7201f6160 100644 --- a/src/arm/isa-arm.c +++ b/src/arm/isa-arm.c @@ -376,6 +376,10 @@ ATTRIBUTE_NOINLINE static void _neutralS(struct ARMCore* cpu, int32_t d) { uint32_t address; \ int rn = (opcode >> 16) & 0xF; \ int rd = (opcode >> 12) & 0xF; \ + int32_t d = cpu->gprs[rd]; \ + if (UNLIKELY(rd == ARM_PC)) { \ + d += WORD_SIZE_ARM; \ + } \ int rm = opcode & 0xF; \ UNUSED(rm); \ address = ADDRESS; \ @@ -559,9 +563,9 @@ DEFINE_LOAD_STORE_INSTRUCTION_ARM(LDRB, LOAD, cpu->gprs[rd] = cpu->memory.load8( DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRH, LOAD, cpu->gprs[rd] = cpu->memory.load16(cpu, address, ¤tCycles); ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSB, LOAD, cpu->gprs[rd] = ARM_SXT_8(cpu->memory.load8(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(LDRSH, LOAD, cpu->gprs[rd] = address & 1 ? ARM_SXT_8(cpu->memory.load16(cpu, address, ¤tCycles)) : ARM_SXT_16(cpu->memory.load16(cpu, address, ¤tCycles)); ARM_LOAD_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, STORE, cpu->memory.store32(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, STORE, cpu->memory.store8(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) -DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, STORE, cpu->memory.store16(cpu, address, cpu->gprs[rd], ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(STR, STORE, cpu->memory.store32(cpu, address, d, ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_INSTRUCTION_ARM(STRB, STORE, cpu->memory.store8(cpu, address, d, ¤tCycles); ARM_STORE_POST_BODY;) +DEFINE_LOAD_STORE_MODE_3_INSTRUCTION_ARM(STRH, STORE, cpu->memory.store16(cpu, address, d, ¤tCycles); ARM_STORE_POST_BODY;) DEFINE_LOAD_STORE_T_INSTRUCTION_ARM(LDRBT, LOAD, enum PrivilegeMode priv = cpu->privilegeMode; From 38613e1c78bbf840fb78abfe9f6d71a6a549d712 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 18:03:47 -0800 Subject: [PATCH 15/20] GBA Serialize: Fix serializing DMA transfer register --- CHANGES | 1 + src/gba/io.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index ea70ad6dc..461be0d06 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation - GBA Memory: Misaligned SRAM writes are ignored + - GBA Serialize: Fix serializing DMA transfer register Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events diff --git a/src/gba/io.c b/src/gba/io.c index 2b74dd99b..01333ba37 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -950,7 +950,7 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { STORE_32(gba->memory.dma[i].when, 0, &state->dma[i].when); } - state->dmaTransferRegister = gba->memory.dmaTransferRegister; + STORE_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister); GBAHardwareSerialize(&gba->memory.hw, state); } @@ -993,7 +993,9 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { } } GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); - gba->memory.dmaTransferRegister = state->dmaTransferRegister; + + LOAD_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister); + GBADMAUpdate(gba); GBAHardwareDeserialize(&gba->memory.hw, state); } From 93633ea60524ac2983e747e13656b896544299cf Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 18:06:23 -0800 Subject: [PATCH 16/20] GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301, fixes mgba.io/i/1320) --- CHANGES | 1 + include/mgba/internal/gba/gba.h | 1 + include/mgba/internal/gba/serialize.h | 3 ++- src/gba/dma.c | 1 + src/gba/gba.c | 1 + src/gba/io.c | 2 ++ src/gba/memory.c | 2 +- 7 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 461be0d06..2436c339e 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,7 @@ Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation + - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA Memory: Misaligned SRAM writes are ignored - GBA Serialize: Fix serializing DMA transfer register Other fixes: diff --git a/include/mgba/internal/gba/gba.h b/include/mgba/internal/gba/gba.h index fffd46936..141892b64 100644 --- a/include/mgba/internal/gba/gba.h +++ b/include/mgba/internal/gba/gba.h @@ -109,6 +109,7 @@ struct GBA { bool haltPending; bool cpuBlocked; bool earlyExit; + uint32_t dmaPC; int idleDetectionStep; int idleDetectionFailures; int32_t cachedRegisters[16]; diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index 3d2e0e69c..9e8bddd54 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -300,8 +300,9 @@ struct GBASerializedState { } hw; uint32_t dmaTransferRegister; + uint32_t dmaBlockPC; - uint32_t reservedHardware[5]; + uint32_t reservedHardware[4]; struct { uint8_t type; diff --git a/src/gba/dma.c b/src/gba/dma.c index 2c112716f..543ac95e0 100644 --- a/src/gba/dma.c +++ b/src/gba/dma.c @@ -219,6 +219,7 @@ void GBADMAUpdate(struct GBA* gba) { } if (memory->activeDMA >= 0) { + gba->dmaPC = gba->cpu->gprs[ARM_PC]; mTimingDeschedule(&gba->timing, &memory->dmaEvent); mTimingSchedule(&gba->timing, &memory->dmaEvent, memory->dma[memory->activeDMA].when - currentTime); } else { diff --git a/src/gba/gba.c b/src/gba/gba.c index 7c00151ec..a2ea187fc 100644 --- a/src/gba/gba.c +++ b/src/gba/gba.c @@ -203,6 +203,7 @@ void GBAReset(struct ARMCore* cpu) { gba->cpuBlocked = false; gba->earlyExit = false; + gba->dmaPC = 0; if (gba->yankedRomSize) { gba->memory.romSize = gba->yankedRomSize; gba->memory.romMask = toPow2(gba->memory.romSize) - 1; diff --git a/src/gba/io.c b/src/gba/io.c index 01333ba37..3f4d09b48 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -951,6 +951,7 @@ void GBAIOSerialize(struct GBA* gba, struct GBASerializedState* state) { } STORE_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister); + STORE_32(gba->dmaPC, 0, &state->dmaBlockPC); GBAHardwareSerialize(&gba->memory.hw, state); } @@ -995,6 +996,7 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); LOAD_32(gba->memory.dmaTransferRegister, 0, &state->dmaTransferRegister); + LOAD_32(gba->dmaPC, 0, &state->dmaBlockPC); GBADMAUpdate(gba); GBAHardwareDeserialize(&gba->memory.hw, state); diff --git a/src/gba/memory.c b/src/gba/memory.c index d2ba5a419..197eb39fd 100644 --- a/src/gba/memory.c +++ b/src/gba/memory.c @@ -337,7 +337,7 @@ static void GBASetActiveRegion(struct ARMCore* cpu, uint32_t address) { } #define LOAD_BAD \ - if (gba->performingDMA) { \ + if (gba->performingDMA || cpu->gprs[ARM_PC] - gba->dmaPC == (gba->cpu->executionMode == MODE_THUMB ? WORD_SIZE_THUMB : WORD_SIZE_ARM)) { \ value = gba->bus; \ } else { \ value = cpu->prefetch[1]; \ From 1285aa2749e7cf4984829aa34a7f708220b6eb24 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 21:51:15 -0800 Subject: [PATCH 17/20] GBA Serialize: Fix audio serialization for desynced FIFOs --- CHANGES | 1 + include/mgba/internal/gba/serialize.h | 13 ++++++++----- src/gba/audio.c | 15 ++++++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 2436c339e..b35ed20ae 100644 --- a/CHANGES +++ b/CHANGES @@ -5,6 +5,7 @@ Emulation fixes: - GBA DMA: Linger last DMA on bus (fixes mgba.io/i/301 and mgba.io/i/1320) - GBA Memory: Misaligned SRAM writes are ignored - GBA Serialize: Fix serializing DMA transfer register + - GBA Serialize: Fix audio serialization for desynced FIFOs Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events diff --git a/include/mgba/internal/gba/serialize.h b/include/mgba/internal/gba/serialize.h index 9e8bddd54..de682dc4f 100644 --- a/include/mgba/internal/gba/serialize.h +++ b/include/mgba/internal/gba/serialize.h @@ -66,9 +66,10 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * 0x0018C - 0x001AB: Audio FIFO 1 * 0x001AC - 0x001CB: Audio FIFO 2 * 0x001CC - 0x001DF: Audio miscellaneous state - * | 0x001CC - 0x001D3: Reserved + * | 0x001CC - 0x001CF: FIFO 1 size + * | 0x001D0 - 0x001D3: Reserved * | 0x001D4 - 0x001D7: Next sample - * | 0x001D8 - 0x001DB: FIFO size + * | 0x001D8 - 0x001DB: FIFO 2 size * | TODO: Fix this, they're in big-endian order, but field is little-endian * | 0x001DC - 0x001DC: Channel 1 envelope state * | bits 0 - 3: Current volume @@ -170,7 +171,8 @@ mLOG_DECLARE_CATEGORY(GBA_STATE); * | bits 9 - 23: Reserved * 0x002C4 - 0x002C7: Game Boy Player next event * 0x002C8 - 0x002CB: Current DMA transfer word - * 0x002CC - 0x002DF: Reserved (leave zero) + * 0x002CC - 0x002CF: Last DMA transfer PC + * 0x002D0 - 0x002DF: Reserved (leave zero) * 0x002E0 - 0x002EF: Savedata state * | 0x002E0 - 0x002E0: Savedata type * | 0x002E1 - 0x002E1: Savedata command (see savedata.h) @@ -256,9 +258,10 @@ struct GBASerializedState { struct GBSerializedPSGState psg; uint8_t fifoA[32]; uint8_t fifoB[32]; - int32_t reserved[2]; + uint32_t fifoSizeA; + int32_t reserved; int32_t nextSample; - uint32_t fifoSize; + uint32_t fifoSizeB; GBSerializedAudioFlags flags; } audio; diff --git a/src/gba/audio.c b/src/gba/audio.c index d2650d6e8..23b5a475e 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -348,7 +348,9 @@ void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* CircleBufferDump(&audio->chA.fifo, state->audio.fifoA, sizeof(state->audio.fifoA)); CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB)); uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo); - STORE_32(fifoSize, 0, &state->audio.fifoSize); + STORE_32(fifoSize, 0, &state->audio.fifoSizeA); + fifoSize = CircleBufferSize(&audio->chB.fifo); + STORE_32(fifoSize, 0, &state->audio.fifoSizeB); STORE_32(audio->sampleEvent.when - mTimingCurrentTime(&audio->p->timing), 0, &state->audio.nextSample); } @@ -358,13 +360,20 @@ void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState CircleBufferClear(&audio->chA.fifo); CircleBufferClear(&audio->chB.fifo); uint32_t fifoSize; - LOAD_32(fifoSize, 0, &state->audio.fifoSize); - if (state->audio.fifoSize > CircleBufferCapacity(&audio->chA.fifo)) { + LOAD_32(fifoSize, 0, &state->audio.fifoSizeA); + if (fifoSize > CircleBufferCapacity(&audio->chA.fifo)) { fifoSize = CircleBufferCapacity(&audio->chA.fifo); } size_t i; for (i = 0; i < fifoSize; ++i) { CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]); + } + + LOAD_32(fifoSize, 0, &state->audio.fifoSizeB); + if (fifoSize > CircleBufferCapacity(&audio->chB.fifo)) { + fifoSize = CircleBufferCapacity(&audio->chB.fifo); + } + for (i = 0; i < fifoSize; ++i) { CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]); } From b169f4b29c5c671343e747f1892c5a7107e40d89 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Jan 2020 22:16:02 -0800 Subject: [PATCH 18/20] GBA Serialize: Fix audio DMA timing deserialization --- CHANGES | 1 + src/gba/io.c | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index b35ed20ae..d0de64deb 100644 --- a/CHANGES +++ b/CHANGES @@ -6,6 +6,7 @@ Emulation fixes: - GBA Memory: Misaligned SRAM writes are ignored - GBA Serialize: Fix serializing DMA transfer register - GBA Serialize: Fix audio serialization for desynced FIFOs + - GBA Serialize: Fix audio DMA timing deserialization Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events diff --git a/src/gba/io.c b/src/gba/io.c index 3f4d09b48..530f9cda2 100644 --- a/src/gba/io.c +++ b/src/gba/io.c @@ -989,9 +989,6 @@ void GBAIODeserialize(struct GBA* gba, const struct GBASerializedState* state) { LOAD_32(gba->memory.dma[i].nextDest, 0, &state->dma[i].nextDest); LOAD_32(gba->memory.dma[i].nextCount, 0, &state->dma[i].nextCount); LOAD_32(gba->memory.dma[i].when, 0, &state->dma[i].when); - if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != GBA_DMA_TIMING_NOW) { - GBADMASchedule(gba, i, &gba->memory.dma[i]); - } } GBAAudioWriteSOUNDCNT_X(&gba->audio, gba->memory.io[REG_SOUNDCNT_X >> 1]); From cde4e1adee349cb162b12301c861de0a3460e7fb Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 25 Jan 2020 14:06:01 -0800 Subject: [PATCH 19/20] GBA Video: Fix OAM not invalidating after reset (fixes #1630) --- CHANGES | 1 + src/gba/renderers/gl.c | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index d0de64deb..42d615038 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,7 @@ Emulation fixes: - GBA Serialize: Fix serializing DMA transfer register - GBA Serialize: Fix audio serialization for desynced FIFOs - GBA Serialize: Fix audio DMA timing deserialization + - GBA Video: Fix OAM not invalidating after reset (fixes mgba.io/i/1630) Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events diff --git a/src/gba/renderers/gl.c b/src/gba/renderers/gl.c index 3c433e81f..2c3da02e0 100644 --- a/src/gba/renderers/gl.c +++ b/src/gba/renderers/gl.c @@ -931,6 +931,7 @@ void GBAVideoGLRendererDeinit(struct GBAVideoRenderer* renderer) { void GBAVideoGLRendererReset(struct GBAVideoRenderer* renderer) { struct GBAVideoGLRenderer* glRenderer = (struct GBAVideoGLRenderer*) renderer; + glRenderer->oamDirty = true; glRenderer->paletteDirty = true; glRenderer->vramDirty = 0xFFFFFF; glRenderer->firstAffine = -1; From 045099507497291f0d18b4d09fca5c50feb0e9e5 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sat, 25 Jan 2020 15:10:15 -0800 Subject: [PATCH 20/20] Qt: Force OpenGL paint engine creation thread (fixes #1642) --- CHANGES | 1 + src/platform/qt/DisplayGL.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/CHANGES b/CHANGES index 42d615038..03559412f 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,7 @@ Emulation fixes: Other fixes: - Qt: Only dynamically reset video scale if a game is running - Qt: Fix race condition with proxied video events + - Qt: Force OpenGL paint engine creation thread (fixes mgba.io/i/1642) 0.8.0: (2020-01-21) Features: diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index 3cb5bb8c9..c14f4e674 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -271,6 +271,15 @@ PainterGL::PainterGL(QWindow* surface, QOpenGLContext* parent, int forceVersion) m_gl->makeCurrent(m_surface); m_window = new QOpenGLPaintDevice; + { + // XXX: Qt creates TLS for OpenGL objects in the local thread + // We need to prevent that thread from being the painter thread + // Qt also caches the engine object on the device if a different + // engine is active, so let's make a temporary one + QOpenGLPaintDevice* fakeDevice = new QOpenGLPaintDevice; + QPainter fakePainter(fakeDevice); + m_window->paintEngine(); + } #if defined(_WIN32) && defined(USE_EPOXY) epoxy_handle_external_wglMakeCurrent(); #endif