aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/qt_sdl/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/qt_sdl/main.cpp')
-rw-r--r--src/frontend/qt_sdl/main.cpp595
1 files changed, 338 insertions, 257 deletions
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index 88704b6..cd0ea52 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -37,17 +37,20 @@
#include <QMimeData>
#include <QVector>
#ifndef _WIN32
+#include <QGuiApplication>
#include <QSocketNotifier>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>
+#ifndef APPLE
+#include <qpa/qplatformnativeinterface.h>
+#endif
#endif
#include <SDL2/SDL.h>
-#ifdef OGLRENDERER_ENABLED
#include "OpenGLSupport.h"
-#endif
+#include "duckstation/gl/context.h"
#include "main.h"
#include "Input.h"
@@ -369,51 +372,121 @@ EmuThread::EmuThread(QObject* parent) : QThread(parent)
connect(this, SIGNAL(windowFullscreenToggle()), mainWindow, SLOT(onFullscreenToggled()));
connect(this, SIGNAL(swapScreensToggle()), mainWindow->actScreenSwap, SLOT(trigger()));
- if (mainWindow->hasOGL) initOpenGL();
+ static_cast<ScreenPanelGL*>(mainWindow->panel)->transferLayout(this);
}
-void EmuThread::initOpenGL()
+void EmuThread::updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix)
{
- QOpenGLContext* windowctx = mainWindow->getOGLContext();
- QSurfaceFormat format = windowctx->format();
-
- format.setSwapInterval(0);
+ screenSettingsLock.lock();
- oglSurface = new QOffscreenSurface();
- oglSurface->setFormat(format);
- oglSurface->create();
- if (!oglSurface->isValid())
+ if (lastScreenWidth != windowInfo.surface_width || lastScreenHeight != windowInfo.surface_height)
{
- // TODO handle this!
- printf("oglSurface shat itself :(\n");
- delete oglSurface;
- return;
+ if (oglContext)
+ oglContext->ResizeSurface(windowInfo.surface_width, windowInfo.surface_height);
+ lastScreenWidth = windowInfo.surface_width;
+ lastScreenHeight = windowInfo.surface_height;
}
- oglContext = new QOpenGLContext();
- oglContext->setFormat(oglSurface->format());
- oglContext->setShareContext(windowctx);
- if (!oglContext->create())
+ this->filter = filter;
+ this->windowInfo = windowInfo;
+ this->numScreens = numScreens;
+ memcpy(this->screenKind, screenKind, sizeof(int)*numScreens);
+ memcpy(this->screenMatrix, screenMatrix, sizeof(float)*numScreens*6);
+
+ screenSettingsLock.unlock();
+}
+
+void EmuThread::initOpenGL()
+{
+ GL::Context* windowctx = mainWindow->getOGLContext();
+
+ oglContext = windowctx;
+ oglContext->MakeCurrent();
+
+ OpenGL::BuildShaderProgram(kScreenVS, kScreenFS, screenShaderProgram, "ScreenShader");
+ GLuint pid = screenShaderProgram[2];
+ glBindAttribLocation(pid, 0, "vPosition");
+ glBindAttribLocation(pid, 1, "vTexcoord");
+ glBindFragDataLocation(pid, 0, "oColor");
+
+ OpenGL::LinkShaderProgram(screenShaderProgram);
+
+ glUseProgram(pid);
+ glUniform1i(glGetUniformLocation(pid, "ScreenTex"), 0);
+
+ screenShaderScreenSizeULoc = glGetUniformLocation(pid, "uScreenSize");
+ screenShaderTransformULoc = glGetUniformLocation(pid, "uTransform");
+
+ // to prevent bleeding between both parts of the screen
+ // with bilinear filtering enabled
+ const int paddedHeight = 192*2+2;
+ const float padPixels = 1.f / paddedHeight;
+
+ const float vertices[] =
{
- // TODO handle this!
- printf("oglContext shat itself :(\n");
- delete oglContext;
- delete oglSurface;
- return;
- }
+ 0.f, 0.f, 0.f, 0.f,
+ 0.f, 192.f, 0.f, 0.5f - padPixels,
+ 256.f, 192.f, 1.f, 0.5f - padPixels,
+ 0.f, 0.f, 0.f, 0.f,
+ 256.f, 192.f, 1.f, 0.5f - padPixels,
+ 256.f, 0.f, 1.f, 0.f,
+
+ 0.f, 0.f, 0.f, 0.5f + padPixels,
+ 0.f, 192.f, 0.f, 1.f,
+ 256.f, 192.f, 1.f, 1.f,
+ 0.f, 0.f, 0.f, 0.5f + padPixels,
+ 256.f, 192.f, 1.f, 1.f,
+ 256.f, 0.f, 1.f, 0.5f + padPixels
+ };
+
+ glGenBuffers(1, &screenVertexBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+
+ glGenVertexArrays(1, &screenVertexArray);
+ glBindVertexArray(screenVertexArray);
+ glEnableVertexAttribArray(0); // position
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
+ glEnableVertexAttribArray(1); // texcoord
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
+
+ glGenTextures(1, &screenTexture);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, screenTexture);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ 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_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ // fill the padding
+ u8 zeroData[256*4*4];
+ memset(zeroData, 0, sizeof(zeroData));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
- oglContext->moveToThread(this);
+ OSD::Init(true);
+
+ oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
}
void EmuThread::deinitOpenGL()
{
- delete oglContext;
- delete oglSurface;
+ glDeleteTextures(1, &screenTexture);
+
+ glDeleteVertexArrays(1, &screenVertexArray);
+ glDeleteBuffers(1, &screenVertexBuffer);
+
+ OpenGL::DeleteShaderProgram(screenShaderProgram);
+
+ OSD::DeInit();
+
+ oglContext->DoneCurrent();
+ oglContext = nullptr;
+
+ lastScreenWidth = lastScreenHeight = -1;
}
void EmuThread::run()
{
- bool hasOGL = mainWindow->hasOGL;
u32 mainScreenPos[3];
NDS::Init();
@@ -428,14 +501,12 @@ void EmuThread::run()
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
-#ifdef OGLRENDERER_ENABLED
- if (hasOGL)
+ if (mainWindow->hasOGL)
{
- oglContext->makeCurrent(oglSurface);
+ initOpenGL();
videoRenderer = Config::_3DRenderer;
}
else
-#endif
{
videoRenderer = 0;
}
@@ -498,25 +569,24 @@ void EmuThread::run()
if (EmuRunning == 3) EmuRunning = 2;
// update render settings if needed
- if (videoSettingsDirty)
+ // HACK:
+ // once the fast forward hotkey is released, we need to update vsync
+ // to the old setting again
+ if (videoSettingsDirty || Input::HotkeyReleased(HK_FastForward))
{
- if (hasOGL != mainWindow->hasOGL)
+ if (oglContext)
{
- hasOGL = mainWindow->hasOGL;
-#ifdef OGLRENDERER_ENABLED
- if (hasOGL)
- {
- oglContext->makeCurrent(oglSurface);
- videoRenderer = Config::_3DRenderer;
- }
- else
-#endif
- {
- videoRenderer = 0;
- }
+ oglContext->SetSwapInterval(Config::ScreenVSync ? Config::ScreenVSyncInterval : 0);
+ videoRenderer = Config::_3DRenderer;
}
+#ifdef OGLRENDERER_ENABLED
else
- videoRenderer = hasOGL ? Config::_3DRenderer : 0;
+#endif
+ {
+ videoRenderer = 0;
+ }
+
+ videoRenderer = oglContext ? Config::_3DRenderer : 0;
videoSettingsDirty = false;
@@ -570,15 +640,6 @@ void EmuThread::run()
}
}
-#ifdef OGLRENDERER_ENABLED
- if (videoRenderer == 1)
- {
- FrontBufferLock.lock();
- if (FrontBufferReverseSyncs[FrontBuffer ^ 1])
- glWaitSync(FrontBufferReverseSyncs[FrontBuffer ^ 1], 0, GL_TIMEOUT_IGNORED);
- FrontBufferLock.unlock();
- }
-#endif
// emulate
u32 nlines = NDS::RunFrame();
@@ -589,21 +650,17 @@ void EmuThread::run()
if (ROMManager::GBASave)
ROMManager::GBASave->CheckFlush();
- FrontBufferLock.lock();
- FrontBuffer = GPU::FrontBuffer;
-#ifdef OGLRENDERER_ENABLED
- if (videoRenderer == 1)
+ if (!oglContext)
{
- if (FrontBufferSyncs[FrontBuffer])
- glDeleteSync(FrontBufferSyncs[FrontBuffer]);
- FrontBufferSyncs[FrontBuffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- // this is hacky but this is the easiest way to call
- // this function without dealling with a ton of
- // macro mess
- epoxy_glFlush();
+ FrontBufferLock.lock();
+ FrontBuffer = GPU::FrontBuffer;
+ FrontBufferLock.unlock();
+ }
+ else
+ {
+ FrontBuffer = GPU::FrontBuffer;
+ drawScreenGL();
}
-#endif
- FrontBufferLock.unlock();
#ifdef MELONCAP
MelonCap::Update();
@@ -612,7 +669,7 @@ void EmuThread::run()
if (EmuRunning == 0) break;
winUpdateCount++;
- if (winUpdateCount >= winUpdateFreq)
+ if (winUpdateCount >= winUpdateFreq && !oglContext)
{
emit windowUpdate();
winUpdateCount = 0;
@@ -620,6 +677,11 @@ void EmuThread::run()
bool fastforward = Input::HotkeyDown(HK_FastForward);
+ if (fastforward && oglContext && Config::ScreenVSync)
+ {
+ oglContext->SetSwapInterval(0);
+ }
+
if (Config::AudioSync && !fastforward && audioDevice)
{
SDL_LockMutex(audioSyncLock);
@@ -700,6 +762,21 @@ void EmuThread::run()
changeWindowTitle(melontitle);
SDL_Delay(75);
+
+ if (oglContext)
+ drawScreenGL();
+
+ int contextRequest = ContextRequest;
+ if (contextRequest == 1)
+ {
+ initOpenGL();
+ ContextRequest = 0;
+ }
+ else if (contextRequest == 2)
+ {
+ deinitOpenGL();
+ ContextRequest = 0;
+ }
}
}
@@ -708,12 +785,6 @@ void EmuThread::run()
GPU::DeInitRenderer();
NDS::DeInit();
//Platform::LAN_DeInit();
-
- if (hasOGL)
- {
- oglContext->doneCurrent();
- deinitOpenGL();
- }
}
void EmuThread::changeWindowTitle(char* title)
@@ -733,6 +804,18 @@ void EmuThread::emuRun()
micOpen();
}
+void EmuThread::initContext()
+{
+ ContextRequest = 1;
+ while (ContextRequest != 0);
+}
+
+void EmuThread::deinitContext()
+{
+ ContextRequest = 2;
+ while (ContextRequest != 0);
+}
+
void EmuThread::emuPause()
{
EmuPause++;
@@ -784,6 +867,72 @@ bool EmuThread::emuIsActive()
return (RunningSomething == 1);
}
+void EmuThread::drawScreenGL()
+{
+ int w = windowInfo.surface_width;
+ int h = windowInfo.surface_height;
+ float factor = windowInfo.surface_scale;
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(false);
+ glDisable(GL_BLEND);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glViewport(0, 0, w, h);
+
+ glUseProgram(screenShaderProgram[2]);
+ glUniform2f(screenShaderScreenSizeULoc, w / factor, h / factor);
+
+ int frontbuf = FrontBuffer;
+ glActiveTexture(GL_TEXTURE0);
+
+#ifdef OGLRENDERER_ENABLED
+ if (GPU::Renderer != 0)
+ {
+ // hardware-accelerated render
+ GPU::CurGLCompositor->BindOutputTexture(frontbuf);
+ }
+ else
+#endif
+ {
+ // regular render
+ glBindTexture(GL_TEXTURE_2D, screenTexture);
+
+ if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
+ {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
+ GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
+ }
+ }
+
+ screenSettingsLock.lock();
+
+ GLint filter = this->filter ? GL_LINEAR : GL_NEAREST;
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+
+ glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
+ glBindVertexArray(screenVertexArray);
+
+ for (int i = 0; i < numScreens; i++)
+ {
+ glUniformMatrix2x3fv(screenShaderTransformULoc, 1, GL_TRUE, screenMatrix[i]);
+ glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3);
+ }
+
+ screenSettingsLock.unlock();
+
+ OSD::Update();
+ OSD::DrawGL(w, h);
+
+ oglContext->SwapBuffers();
+}
+
ScreenHandler::ScreenHandler(QWidget* widget)
{
widget->setMouseTracking(true);
@@ -1001,12 +1150,12 @@ ScreenPanelNative::ScreenPanelNative(QWidget* parent) : QWidget(parent), ScreenH
screenTrans[0].reset();
screenTrans[1].reset();
- OSD::Init(nullptr);
+ OSD::Init(false);
}
ScreenPanelNative::~ScreenPanelNative()
{
- OSD::DeInit(nullptr);
+ OSD::DeInit();
}
void ScreenPanelNative::setupScreenLayout()
@@ -1057,7 +1206,7 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
}
}
- OSD::Update(nullptr);
+ OSD::Update();
OSD::DrawNative(painter);
}
@@ -1105,188 +1254,115 @@ void ScreenPanelNative::onScreenLayoutChanged()
}
-ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QOpenGLWidget(parent), ScreenHandler(this)
-{}
-
-ScreenPanelGL::~ScreenPanelGL()
+ScreenPanelGL::ScreenPanelGL(QWidget* parent) : QWidget(parent), ScreenHandler(this)
{
- makeCurrent();
-
- OSD::DeInit(this);
-
- glDeleteTextures(1, &screenTexture);
+ setAutoFillBackground(false);
+ setAttribute(Qt::WA_NativeWindow, true);
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ setAttribute(Qt::WA_KeyCompression, false);
+ setFocusPolicy(Qt::StrongFocus);
+ setMinimumSize(screenGetMinSize());
+}
- glDeleteVertexArrays(1, &screenVertexArray);
- glDeleteBuffers(1, &screenVertexBuffer);
+ScreenPanelGL::~ScreenPanelGL()
+{}
- delete screenShader;
+bool ScreenPanelGL::createContext()
+{
+ std::optional<WindowInfo> windowInfo = getWindowInfo();
+ std::array<GL::Context::Version, 2> versionsToTry = {
+ GL::Context::Version{GL::Context::Profile::Core, 4, 3},
+ GL::Context::Version{GL::Context::Profile::Core, 3, 2}};
+ if (windowInfo.has_value())
+ {
+ glContext = GL::Context::Create(*getWindowInfo(), versionsToTry);
+ glContext->DoneCurrent();
+ }
- doneCurrent();
+ return glContext != nullptr;
}
-void ScreenPanelGL::setupScreenLayout()
+qreal ScreenPanelGL::devicePixelRatioFromScreen() const
{
- int w = width();
- int h = height();
+ const QScreen* screen_for_ratio = window()->windowHandle()->screen();
+ if (!screen_for_ratio)
+ screen_for_ratio = QGuiApplication::primaryScreen();
- screenSetupLayout(w, h);
+ return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
}
-void ScreenPanelGL::initializeGL()
+int ScreenPanelGL::scaledWindowWidth() const
{
- initializeOpenGLFunctions();
-
- const GLubyte* renderer = glGetString(GL_RENDERER); // get renderer string
- const GLubyte* version = glGetString(GL_VERSION); // version as a string
- printf("OpenGL: renderer: %s\n", renderer);
- printf("OpenGL: version: %s\n", version);
-
- glClearColor(0, 0, 0, 1);
-
- screenShader = new QOpenGLShaderProgram(this);
- screenShader->addShaderFromSourceCode(QOpenGLShader::Vertex, kScreenVS);
- screenShader->addShaderFromSourceCode(QOpenGLShader::Fragment, kScreenFS);
-
- GLuint pid = screenShader->programId();
- glBindAttribLocation(pid, 0, "vPosition");
- glBindAttribLocation(pid, 1, "vTexcoord");
- glBindFragDataLocation(pid, 0, "oColor");
-
- screenShader->link();
+ return std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioFromScreen())), 1);
+}
- screenShader->bind();
- screenShader->setUniformValue("ScreenTex", (GLint)0);
- screenShader->release();
+int ScreenPanelGL::scaledWindowHeight() const
+{
+ return std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen())), 1);
+}
- // to prevent bleeding between both parts of the screen
- // with bilinear filtering enabled
- const int paddedHeight = 192*2+2;
- const float padPixels = 1.f / paddedHeight;
+std::optional<WindowInfo> ScreenPanelGL::getWindowInfo()
+{
+ WindowInfo wi;
- const float vertices[] =
+ // Windows and Apple are easy here since there's no display connection.
+ #if defined(_WIN32)
+ wi.type = WindowInfo::Type::Win32;
+ wi.window_handle = reinterpret_cast<void*>(winId());
+ #elif defined(__APPLE__)
+ wi.type = WindowInfo::Type::MacOS;
+ wi.window_handle = reinterpret_cast<void*>(winId());
+ #else
+ QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
+ const QString platform_name = QGuiApplication::platformName();
+ if (platform_name == QStringLiteral("xcb"))
{
- 0.f, 0.f, 0.f, 0.f,
- 0.f, 192.f, 0.f, 0.5f - padPixels,
- 256.f, 192.f, 1.f, 0.5f - padPixels,
- 0.f, 0.f, 0.f, 0.f,
- 256.f, 192.f, 1.f, 0.5f - padPixels,
- 256.f, 0.f, 1.f, 0.f,
+ wi.type = WindowInfo::Type::X11;
+ wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
+ wi.window_handle = reinterpret_cast<void*>(winId());
+ }
+ else if (platform_name == QStringLiteral("wayland"))
+ {
+ wi.type = WindowInfo::Type::Wayland;
+ wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
+ wi.window_handle = pni->nativeResourceForWindow("surface", windowHandle());
+ }
+ else
+ {
+ qCritical() << "Unknown PNI platform " << platform_name;
+ return std::nullopt;
+ }
+ #endif
- 0.f, 0.f, 0.f, 0.5f + padPixels,
- 0.f, 192.f, 0.f, 1.f,
- 256.f, 192.f, 1.f, 1.f,
- 0.f, 0.f, 0.f, 0.5f + padPixels,
- 256.f, 192.f, 1.f, 1.f,
- 256.f, 0.f, 1.f, 0.5f + padPixels
- };
+ wi.surface_width = static_cast<u32>(scaledWindowWidth());
+ wi.surface_height = static_cast<u32>(scaledWindowHeight());
+ wi.surface_scale = static_cast<float>(devicePixelRatioFromScreen());
- glGenBuffers(1, &screenVertexBuffer);
- glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+ return wi;
+}
- glGenVertexArrays(1, &screenVertexArray);
- glBindVertexArray(screenVertexArray);
- glEnableVertexAttribArray(0); // position
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(0));
- glEnableVertexAttribArray(1); // texcoord
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4*4, (void*)(2*4));
- glGenTextures(1, &screenTexture);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, screenTexture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- 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_RGBA, 256, paddedHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- // fill the padding
- u8 zeroData[256*4*4];
- memset(zeroData, 0, sizeof(zeroData));
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256, 2, GL_RGBA, GL_UNSIGNED_BYTE, zeroData);
-
- OSD::Init(this);
+QPaintEngine* ScreenPanelGL::paintEngine() const
+{
+ return nullptr;
}
-void ScreenPanelGL::paintGL()
+void ScreenPanelGL::setupScreenLayout()
{
int w = width();
int h = height();
- float factor = devicePixelRatioF();
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- glViewport(0, 0, w*factor, h*factor);
+ screenSetupLayout(w, h);
if (emuThread)
- {
- screenShader->bind();
-
- screenShader->setUniformValue("uScreenSize", (float)w, (float)h);
- screenShader->setUniformValue("uScaleFactor", factor);
-
- emuThread->FrontBufferLock.lock();
- int frontbuf = emuThread->FrontBuffer;
- glActiveTexture(GL_TEXTURE0);
-
- #ifdef OGLRENDERER_ENABLED
- if (GPU::Renderer != 0)
- {
- if (emuThread->FrontBufferSyncs[emuThread->FrontBuffer])
- glWaitSync(emuThread->FrontBufferSyncs[emuThread->FrontBuffer], 0, GL_TIMEOUT_IGNORED);
- // hardware-accelerated render
- GPU::CurGLCompositor->BindOutputTexture(frontbuf);
- }
- else
- #endif
- {
- // regular render
- glBindTexture(GL_TEXTURE_2D, screenTexture);
-
- if (GPU::Framebuffer[frontbuf][0] && GPU::Framebuffer[frontbuf][1])
- {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
- GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][0]);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
- GL_UNSIGNED_BYTE, GPU::Framebuffer[frontbuf][1]);
- }
- }
-
- GLint filter = Config::ScreenFilter ? GL_LINEAR : GL_NEAREST;
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
-
- glBindBuffer(GL_ARRAY_BUFFER, screenVertexBuffer);
- glBindVertexArray(screenVertexArray);
-
- GLint transloc = screenShader->uniformLocation("uTransform");
-
- for (int i = 0; i < numScreens; i++)
- {
- glUniformMatrix2x3fv(transloc, 1, GL_TRUE, screenMatrix[i]);
- glDrawArrays(GL_TRIANGLES, screenKind[i] == 0 ? 0 : 2*3, 2*3);
- }
-
- screenShader->release();
-
- if (emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer])
- glDeleteSync(emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer]);
- emuThread->FrontBufferReverseSyncs[emuThread->FrontBuffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- emuThread->FrontBufferLock.unlock();
- }
-
- OSD::Update(this);
- OSD::DrawGL(this, w*factor, h*factor);
+ transferLayout(emuThread);
}
void ScreenPanelGL::resizeEvent(QResizeEvent* event)
{
setupScreenLayout();
- QOpenGLWidget::resizeEvent(event);
-}
-
-void ScreenPanelGL::resizeGL(int w, int h)
-{
+ QWidget::resizeEvent(event);
}
void ScreenPanelGL::mousePressEvent(QMouseEvent* event)
@@ -1321,6 +1397,13 @@ bool ScreenPanelGL::event(QEvent* event)
return QWidget::event(event);
}
+void ScreenPanelGL::transferLayout(EmuThread* thread)
+{
+ std::optional<WindowInfo> windowInfo = getWindowInfo();
+ if (windowInfo.has_value())
+ thread->updateScreenSettings(Config::ScreenFilter, *windowInfo, numScreens, screenKind, &screenMatrix[0][0]);
+}
+
void ScreenPanelGL::onScreenLayoutChanged()
{
setMinimumSize(screenGetMinSize());
@@ -1817,6 +1900,18 @@ MainWindow::~MainWindow()
{
}
+void MainWindow::closeEvent(QCloseEvent* event)
+{
+ if (hasOGL)
+ {
+ // we intentionally don't unpause here
+ emuThread->emuPause();
+ emuThread->deinitContext();
+ }
+
+ QMainWindow::closeEvent(event);
+}
+
void MainWindow::createScreenPanel()
{
hasOGL = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
@@ -1829,17 +1924,7 @@ void MainWindow::createScreenPanel()
panel = panelGL;
panelWidget = panelGL;
- if (!panelGL->isValid())
- hasOGL = false;
- else
- {
- QSurfaceFormat fmt = panelGL->format();
- if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 2))
- hasOGL = false;
- }
-
- if (!hasOGL)
- delete panelGL;
+ panelGL->createContext();
}
if (!hasOGL)
@@ -1855,12 +1940,12 @@ void MainWindow::createScreenPanel()
emit screenLayoutChange();
}
-QOpenGLContext* MainWindow::getOGLContext()
+GL::Context* MainWindow::getOGLContext()
{
if (!hasOGL) return nullptr;
- QOpenGLWidget* glpanel = dynamic_cast<QOpenGLWidget*>(panel);
- return glpanel->context();
+ ScreenPanelGL* glpanel = static_cast<ScreenPanelGL*>(panel);
+ return glpanel->getContext();
}
void MainWindow::resizeEvent(QResizeEvent* event)
@@ -3002,13 +3087,14 @@ void MainWindow::onChangeIntegerScaling(bool checked)
void MainWindow::onChangeScreenFiltering(bool checked)
{
Config::ScreenFilter = checked?1:0;
+
+ emit screenLayoutChange();
}
void MainWindow::onChangeShowOSD(bool checked)
{
Config::ShowOSD = checked?1:0;
}
-
void MainWindow::onChangeLimitFramerate(bool checked)
{
Config::LimitFPS = checked?1:0;
@@ -3088,19 +3174,20 @@ void MainWindow::onUpdateVideoSettings(bool glchange)
if (glchange)
{
emuThread->emuPause();
+ if (hasOGL) emuThread->deinitContext();
- if (hasOGL)
- emuThread->deinitOpenGL();
delete panel;
createScreenPanel();
connect(emuThread, SIGNAL(windowUpdate()), panelWidget, SLOT(repaint()));
- if (hasOGL) emuThread->initOpenGL();
}
videoSettingsDirty = true;
if (glchange)
+ {
+ if (hasOGL) emuThread->initContext();
emuThread->emuUnpause();
+ }
}
@@ -3137,6 +3224,8 @@ int main(int argc, char** argv)
{
srand(time(nullptr));
+ qputenv("QT_SCALE_FACTOR", "1");
+
printf("melonDS " MELONDS_VERSION "\n");
printf(MELONDS_URL "\n");
@@ -3191,14 +3280,6 @@ int main(int argc, char** argv)
SANITIZE(Config::ScreenAspectBot, 0, 4);
#undef SANITIZE
- QSurfaceFormat format;
- format.setDepthBufferSize(24);
- format.setStencilBufferSize(8);
- format.setVersion(3, 2);
- format.setProfile(QSurfaceFormat::CoreProfile);
- format.setSwapInterval(0);
- QSurfaceFormat::setDefaultFormat(format);
-
audioMuted = false;
audioSync = SDL_CreateCond();
audioSyncLock = SDL_CreateMutex();