From f44846cb9a0818af13830a34c0deee830b4451d4 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Sun, 19 Jan 2020 19:15:36 -0800 Subject: [PATCH] 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) {