aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/qt_sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/qt_sdl')
-rw-r--r--src/frontend/qt_sdl/CMakeLists.txt56
-rw-r--r--src/frontend/qt_sdl/OSD.cpp126
-rw-r--r--src/frontend/qt_sdl/OSD.h8
-rw-r--r--src/frontend/qt_sdl/VideoSettingsDialog.cpp37
-rw-r--r--src/frontend/qt_sdl/VideoSettingsDialog.h3
-rw-r--r--src/frontend/qt_sdl/main.cpp595
-rw-r--r--src/frontend/qt_sdl/main.h74
-rw-r--r--src/frontend/qt_sdl/main_shaders.h5
8 files changed, 533 insertions, 371 deletions
diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt
index a8d6e4b..bfa58bf 100644
--- a/src/frontend/qt_sdl/CMakeLists.txt
+++ b/src/frontend/qt_sdl/CMakeLists.txt
@@ -45,8 +45,11 @@ set(SOURCES_QT_SDL
../FrontendUtil.h
../mic_blow.h
+ ../glad/glad.c
+ ../duckstation/gl/context.cpp
+
${CMAKE_SOURCE_DIR}/res/melon.qrc
- )
+)
if (APPLE)
option(USE_QT6 "Build using Qt 6 instead of 5" ON)
@@ -71,12 +74,13 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
+find_package(Threads REQUIRED)
+find_package(PkgConfig REQUIRED)
+
if (BUILD_STATIC)
list(APPEND PKG_CONFIG_EXECUTABLE "--static")
endif()
-find_package(Threads REQUIRED)
-find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
pkg_check_modules(Slirp REQUIRED IMPORTED_TARGET slirp)
pkg_check_modules(LibArchive REQUIRED IMPORTED_TARGET libarchive)
@@ -87,6 +91,47 @@ add_compile_definitions(ARCHIVE_SUPPORT_ENABLED)
add_executable(melonDS ${SOURCES_QT_SDL})
+if (WIN32)
+ target_link_libraries(melonDS PUBLIC opengl32)
+
+ target_sources(melonDS PRIVATE
+ ../duckstation/gl/context_wgl.cpp
+
+ ../glad/glad_wgl.c
+ )
+elseif (APPLE)
+ if (NOT USE_QT6)
+ find_library(COCOA_LIB Cocoa)
+ target_link_libraries(melonDS PRIVATE ${COCOA_LIB})
+ endif()
+ target_sources(melonDS PRIVATE
+ ../duckstation/gl/context_agl.mm
+ )
+else()
+ # we only need ECM for Wayland
+ # so we only require it from here
+ find_package(ECM REQUIRED NO_MODULE)
+ list(APPEND CMAKE_MODULE_PATH "${ECM_MODULE_PATH}")
+
+ find_package(X11 REQUIRED)
+ find_package(EGL REQUIRED)
+ find_package(Wayland REQUIRED Client)
+
+ target_sources(melonDS PRIVATE
+ ../duckstation/gl/context_egl.cpp
+ ../duckstation/gl/context_egl_x11.cpp
+ ../duckstation/gl/context_glx.cpp
+ ../duckstation/gl/context_egl_wayland.cpp
+ ../duckstation/gl/x11_window.cpp
+
+ ../glad/glad_egl.c
+ ../glad/glad_glx.c
+ )
+ target_link_libraries(melonDS PRIVATE "${X11_LIBRARIES}" "${EGL_LIBRARIES}")
+ target_include_directories(melonDS PRIVATE "${X11_INCLUDE_DIR}")
+endif()
+
+
if (BUILD_STATIC)
qt_import_plugins(melonDS INCLUDE Qt::QSvgPlugin)
target_link_options(melonDS PRIVATE -static)
@@ -95,6 +140,11 @@ endif()
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..")
+if (USE_QT6)
+ target_include_directories(melonDS PUBLIC ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
+else()
+ target_include_directories(melonDS PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
+endif()
target_link_libraries(melonDS PRIVATE core)
target_link_libraries(melonDS PRIVATE PkgConfig::SDL2 PkgConfig::Slirp PkgConfig::LibArchive)
target_link_libraries(melonDS PRIVATE ${QT_LINK_LIBS} ${CMAKE_DL_LIBS})
diff --git a/src/frontend/qt_sdl/OSD.cpp b/src/frontend/qt_sdl/OSD.cpp
index 6f060a9..d3becc1 100644
--- a/src/frontend/qt_sdl/OSD.cpp
+++ b/src/frontend/qt_sdl/OSD.cpp
@@ -23,6 +23,7 @@
#include "../types.h"
#include "main.h"
+#include "OpenGLSupport.h"
#include <QPainter>
#include "OSD.h"
@@ -52,42 +53,37 @@ struct Item
bool GLTextureLoaded;
GLuint GLTexture;
-
};
std::deque<Item> ItemQueue;
-QOpenGLShaderProgram* Shader;
+GLuint Shader[3];
GLint uScreenSize, uOSDPos, uOSDSize;
GLfloat uScaleFactor;
GLuint OSDVertexArray;
GLuint OSDVertexBuffer;
-volatile bool Rendering;
+QMutex Rendering;
-bool Init(QOpenGLFunctions_3_2_Core* f)
+bool Init(bool openGL)
{
- if (f)
+ if (openGL)
{
- Shader = new QOpenGLShaderProgram();
- Shader->addShaderFromSourceCode(QOpenGLShader::Vertex, kScreenVS_OSD);
- Shader->addShaderFromSourceCode(QOpenGLShader::Fragment, kScreenFS_OSD);
-
- GLuint pid = Shader->programId();
- f->glBindAttribLocation(pid, 0, "vPosition");
- f->glBindFragDataLocation(pid, 0, "oColor");
+ OpenGL::BuildShaderProgram(kScreenVS_OSD, kScreenFS_OSD, Shader, "OSDShader");
- Shader->link();
+ GLuint pid = Shader[2];
+ glBindAttribLocation(pid, 0, "vPosition");
+ glBindFragDataLocation(pid, 0, "oColor");
- Shader->bind();
- Shader->setUniformValue("OSDTex", (GLint)0);
- Shader->release();
+ OpenGL::LinkShaderProgram(Shader);
+ glUseProgram(pid);
+ glUniform1i(glGetUniformLocation(pid, "OSDTex"), 0);
- uScreenSize = Shader->uniformLocation("uScreenSize");
- uOSDPos = Shader->uniformLocation("uOSDPos");
- uOSDSize = Shader->uniformLocation("uOSDSize");
- uScaleFactor = Shader->uniformLocation("uScaleFactor");
+ uScreenSize = glGetUniformLocation(pid, "uScreenSize");
+ uOSDPos = glGetUniformLocation(pid, "uOSDPos");
+ uOSDSize = glGetUniformLocation(pid, "uOSDSize");
+ uScaleFactor = glGetUniformLocation(pid, "uScaleFactor");
float vertices[6*2] =
{
@@ -99,32 +95,30 @@ bool Init(QOpenGLFunctions_3_2_Core* f)
1, 1
};
- f->glGenBuffers(1, &OSDVertexBuffer);
- f->glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
- f->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+ glGenBuffers(1, &OSDVertexBuffer);
+ glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
- f->glGenVertexArrays(1, &OSDVertexArray);
- f->glBindVertexArray(OSDVertexArray);
- f->glEnableVertexAttribArray(0); // position
- f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
+ glGenVertexArrays(1, &OSDVertexArray);
+ glBindVertexArray(OSDVertexArray);
+ glEnableVertexAttribArray(0); // position
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
}
return true;
}
-void DeInit(QOpenGLFunctions_3_2_Core* f)
+void DeInit()
{
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
{
Item& item = *it;
- if (item.GLTextureLoaded && f) f->glDeleteTextures(1, &item.GLTexture);
+ if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
if (item.Bitmap) delete[] item.Bitmap;
it = ItemQueue.erase(it);
}
-
- if (f) delete Shader;
}
@@ -329,7 +323,7 @@ void AddMessage(u32 color, const char* text)
{
if (!Config::ShowOSD) return;
- while (Rendering);
+ Rendering.lock();
Item item;
@@ -342,27 +336,29 @@ void AddMessage(u32 color, const char* text)
item.GLTextureLoaded = false;
ItemQueue.push_back(item);
+
+ Rendering.unlock();
}
-void Update(QOpenGLFunctions_3_2_Core* f)
+void Update()
{
if (!Config::ShowOSD)
{
- Rendering = true;
+ Rendering.lock();
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
{
Item& item = *it;
- if (item.GLTextureLoaded && f) f->glDeleteTextures(1, &item.GLTexture);
+ if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
if (item.Bitmap) delete[] item.Bitmap;
it = ItemQueue.erase(it);
}
- Rendering = false;
+ Rendering.unlock();
return;
}
- Rendering = true;
+ Rendering.lock();
Uint32 tick_now = SDL_GetTicks();
Uint32 tick_min = tick_now - 2500;
@@ -373,7 +369,7 @@ void Update(QOpenGLFunctions_3_2_Core* f)
if (item.Timestamp < tick_min)
{
- if (item.GLTextureLoaded) f->glDeleteTextures(1, &item.GLTexture);
+ if (item.GLTextureLoaded) glDeleteTextures(1, &item.GLTexture);
if (item.Bitmap) delete[] item.Bitmap;
it = ItemQueue.erase(it);
@@ -388,14 +384,14 @@ void Update(QOpenGLFunctions_3_2_Core* f)
it++;
}
- Rendering = false;
+ Rendering.unlock();
}
void DrawNative(QPainter& painter)
{
if (!Config::ShowOSD) return;
- Rendering = true;
+ Rendering.lock();
u32 y = kOSDMargin;
@@ -417,30 +413,30 @@ void DrawNative(QPainter& painter)
it++;
}
- Rendering = false;
+ Rendering.unlock();
}
-void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h)
+void DrawGL(float w, float h)
{
if (!Config::ShowOSD) return;
if (!mainWindow || !mainWindow->panel) return;
- Rendering = true;
+ Rendering.lock();
u32 y = kOSDMargin;
- Shader->bind();
+ glUseProgram(Shader[2]);
- f->glUniform2f(uScreenSize, w, h);
- f->glUniform1f(uScaleFactor, mainWindow->devicePixelRatioF());
+ glUniform2f(uScreenSize, w, h);
+ glUniform1f(uScaleFactor, mainWindow->devicePixelRatioF());
- f->glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
- f->glBindVertexArray(OSDVertexArray);
+ glBindBuffer(GL_ARRAY_BUFFER, OSDVertexBuffer);
+ glBindVertexArray(OSDVertexArray);
- f->glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0);
- f->glEnable(GL_BLEND);
- f->glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
for (auto it = ItemQueue.begin(); it != ItemQueue.end(); )
{
@@ -448,30 +444,30 @@ void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h)
if (!item.GLTextureLoaded)
{
- f->glGenTextures(1, &item.GLTexture);
- f->glBindTexture(GL_TEXTURE_2D, item.GLTexture);
- f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
+ glGenTextures(1, &item.GLTexture);
+ glBindTexture(GL_TEXTURE_2D, item.GLTexture);
+ 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, item.Width, item.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, item.Bitmap);
item.GLTextureLoaded = true;
}
- f->glBindTexture(GL_TEXTURE_2D, item.GLTexture);
- f->glUniform2i(uOSDPos, kOSDMargin, y);
- f->glUniform2i(uOSDSize, item.Width, item.Height);
- f->glDrawArrays(GL_TRIANGLES, 0, 2*3);
+ glBindTexture(GL_TEXTURE_2D, item.GLTexture);
+ glUniform2i(uOSDPos, kOSDMargin, y);
+ glUniform2i(uOSDSize, item.Width, item.Height);
+ glDrawArrays(GL_TRIANGLES, 0, 2*3);
y += item.Height;
it++;
}
- f->glDisable(GL_BLEND);
- Shader->release();
+ glDisable(GL_BLEND);
+ glUseProgram(0);
- Rendering = false;
+ Rendering.unlock();
}
}
diff --git a/src/frontend/qt_sdl/OSD.h b/src/frontend/qt_sdl/OSD.h
index d624fc6..907496f 100644
--- a/src/frontend/qt_sdl/OSD.h
+++ b/src/frontend/qt_sdl/OSD.h
@@ -22,14 +22,14 @@
namespace OSD
{
-bool Init(QOpenGLFunctions_3_2_Core* f);
-void DeInit(QOpenGLFunctions_3_2_Core* f);
+bool Init(bool openGL);
+void DeInit();
void AddMessage(u32 color, const char* text);
-void Update(QOpenGLFunctions_3_2_Core* f);
+void Update();
void DrawNative(QPainter& painter);
-void DrawGL(QOpenGLFunctions_3_2_Core* f, float w, float h);
+void DrawGL(float w, float h);
}
diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.cpp b/src/frontend/qt_sdl/VideoSettingsDialog.cpp
index 87a796d..95ec7d3 100644
--- a/src/frontend/qt_sdl/VideoSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/VideoSettingsDialog.cpp
@@ -28,6 +28,11 @@
#include "ui_VideoSettingsDialog.h"
+inline bool UsesGL()
+{
+ return (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+}
+
VideoSettingsDialog* VideoSettingsDialog::currentDlg = nullptr;
@@ -73,6 +78,7 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
if (!Config::ScreenVSync)
ui->sbVSyncInterval->setEnabled(false);
+ setVsyncControlEnable(UsesGL());
if (Config::_3DRenderer == 0)
{
@@ -88,14 +94,6 @@ VideoSettingsDialog::VideoSettingsDialog(QWidget* parent) : QDialog(parent), ui(
ui->cbxGLResolution->setEnabled(true);
ui->cbBetterPolygons->setEnabled(true);
}
-
- // sorry
- ui->cbVSync->hide();
- ui->cbVSync->setEnabled(false);
- ui->sbVSyncInterval->hide();
- ui->sbVSyncInterval->setEnabled(false);
- ui->label_2->hide();
- ui->groupBox->layout()->addItem(new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding));
}
VideoSettingsDialog::~VideoSettingsDialog()
@@ -112,7 +110,7 @@ void VideoSettingsDialog::on_VideoSettingsDialog_accepted()
void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
{
- bool old_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+ bool old_gl = UsesGL();
Config::_3DRenderer = oldRenderer;
Config::ScreenUseGL = oldGLDisplay;
@@ -122,12 +120,17 @@ void VideoSettingsDialog::on_VideoSettingsDialog_rejected()
Config::GL_ScaleFactor = oldGLScale;
Config::GL_BetterPolygons = oldGLBetterPolygons;
- bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
- emit updateVideoSettings(old_gl != new_gl);
+ emit updateVideoSettings(old_gl != UsesGL());
closeDlg();
}
+void VideoSettingsDialog::setVsyncControlEnable(bool hasOGL)
+{
+ ui->cbVSync->setEnabled(hasOGL);
+ ui->sbVSyncInterval->setEnabled(hasOGL);
+}
+
void VideoSettingsDialog::onChange3DRenderer(int renderer)
{
bool old_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
@@ -149,8 +152,7 @@ void VideoSettingsDialog::onChange3DRenderer(int renderer)
ui->cbBetterPolygons->setEnabled(true);
}
- bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
- emit updateVideoSettings(old_gl != new_gl);
+ emit updateVideoSettings(old_gl != UsesGL());
}
void VideoSettingsDialog::on_cbGLDisplay_stateChanged(int state)
@@ -159,8 +161,9 @@ void VideoSettingsDialog::on_cbGLDisplay_stateChanged(int state)
Config::ScreenUseGL = (state != 0);
- bool new_gl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
- emit updateVideoSettings(old_gl != new_gl);
+ setVsyncControlEnable(UsesGL());
+
+ emit updateVideoSettings(old_gl != UsesGL());
}
void VideoSettingsDialog::on_cbVSync_stateChanged(int state)
@@ -168,11 +171,13 @@ void VideoSettingsDialog::on_cbVSync_stateChanged(int state)
bool vsync = (state != 0);
ui->sbVSyncInterval->setEnabled(vsync);
Config::ScreenVSync = vsync;
+ emit updateVideoSettings(false);
}
void VideoSettingsDialog::on_sbVSyncInterval_valueChanged(int val)
{
Config::ScreenVSyncInterval = val;
+ emit updateVideoSettings(false);
}
void VideoSettingsDialog::on_cbSoftwareThreaded_stateChanged(int state)
@@ -189,6 +194,8 @@ void VideoSettingsDialog::on_cbxGLResolution_currentIndexChanged(int idx)
Config::GL_ScaleFactor = idx+1;
+ setVsyncControlEnable(UsesGL());
+
emit updateVideoSettings(false);
}
diff --git a/src/frontend/qt_sdl/VideoSettingsDialog.h b/src/frontend/qt_sdl/VideoSettingsDialog.h
index 527cc93..7fee5bb 100644
--- a/src/frontend/qt_sdl/VideoSettingsDialog.h
+++ b/src/frontend/qt_sdl/VideoSettingsDialog.h
@@ -67,8 +67,9 @@ private slots:
void on_cbBetterPolygons_stateChanged(int state);
void on_cbSoftwareThreaded_stateChanged(int state);
-
private:
+ void setVsyncControlEnable(bool hasOGL);
+
Ui::VideoSettingsDialog* ui;
QButtonGroup* grp3DRenderer;
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();
diff --git a/src/frontend/qt_sdl/main.h b/src/frontend/qt_sdl/main.h
index 1977b7f..2e2a9ab 100644
--- a/src/frontend/qt_sdl/main.h
+++ b/src/frontend/qt_sdl/main.h
@@ -19,6 +19,8 @@
#ifndef MAIN_H
#define MAIN_H
+#include "glad/glad.h"
+
#include <QApplication>
#include <QThread>
#include <QWidget>
@@ -28,15 +30,15 @@
#include <QActionGroup>
#include <QTimer>
#include <QMutex>
+#include <QScreen>
+#include <QCloseEvent>
+
+#include <atomic>
-#include <QOffscreenSurface>
-#include <QOpenGLWidget>
-#include <QOpenGLContext>
-#include <QOpenGLFunctions>
-#include <QOpenGLFunctions_3_2_Core>
-#include <QOpenGLShaderProgram>
+#include <optional>
#include "FrontendUtil.h"
+#include "duckstation/gl/context.h"
class EmuThread : public QThread
{
@@ -46,9 +48,6 @@ class EmuThread : public QThread
public:
explicit EmuThread(QObject* parent = nullptr);
- void initOpenGL();
- void deinitOpenGL();
-
void changeWindowTitle(char* title);
// to be called from the UI thread
@@ -61,11 +60,13 @@ public:
bool emuIsRunning();
bool emuIsActive();
+ void initContext();
+ void deinitContext();
+
int FrontBuffer = 0;
QMutex FrontBufferLock;
- GLsync FrontBufferReverseSyncs[2] = {nullptr, nullptr};
- GLsync FrontBufferSyncs[2] = {nullptr, nullptr};
+ void updateScreenSettings(bool filter, const WindowInfo& windowInfo, int numScreens, int* screenKind, float* screenMatrix);
signals:
void windowUpdate();
@@ -86,13 +87,31 @@ signals:
void swapScreensToggle();
private:
- volatile int EmuStatus;
+ void drawScreenGL();
+ void initOpenGL();
+ void deinitOpenGL();
+
+ std::atomic<int> EmuStatus;
int PrevEmuStatus;
int EmuRunning;
int EmuPause;
- QOffscreenSurface* oglSurface;
- QOpenGLContext* oglContext;
+ std::atomic<int> ContextRequest = 0;
+
+ GL::Context* oglContext = nullptr;
+ GLuint screenVertexBuffer, screenVertexArray;
+ GLuint screenTexture;
+ GLuint screenShaderProgram[3];
+ GLuint screenShaderTransformULoc, screenShaderScreenSizeULoc;
+
+ QMutex screenSettingsLock;
+ WindowInfo windowInfo;
+ float screenMatrix[Frontend::MaxScreenTransforms][6];
+ int screenKind[Frontend::MaxScreenTransforms];
+ int numScreens;
+ bool filter;
+
+ int lastScreenWidth = -1, lastScreenHeight = -1;
};
@@ -158,7 +177,7 @@ private:
};
-class ScreenPanelGL : public QOpenGLWidget, public ScreenHandler, protected QOpenGLFunctions_3_2_Core
+class ScreenPanelGL : public QWidget, public ScreenHandler
{
Q_OBJECT
@@ -166,13 +185,22 @@ public:
explicit ScreenPanelGL(QWidget* parent);
virtual ~ScreenPanelGL();
+ std::optional<WindowInfo> getWindowInfo();
+
+ bool createContext();
+
+ GL::Context* getContext() { return glContext.get(); }
+
+ void transferLayout(EmuThread* thread);
protected:
- void initializeGL() override;
- void paintGL() override;
+ qreal devicePixelRatioFromScreen() const;
+ int scaledWindowWidth() const;
+ int scaledWindowHeight() const;
+
+ QPaintEngine* paintEngine() const override;
void resizeEvent(QResizeEvent* event) override;
- void resizeGL(int w, int h) override;
void mousePressEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
@@ -180,16 +208,14 @@ protected:
void tabletEvent(QTabletEvent* event) override;
bool event(QEvent* event) override;
+
private slots:
void onScreenLayoutChanged();
private:
void setupScreenLayout();
- QOpenGLShaderProgram* screenShader;
- GLuint screenVertexBuffer;
- GLuint screenVertexArray;
- GLuint screenTexture;
+ std::unique_ptr<GL::Context> glContext;
};
class MelonApplication : public QApplication
@@ -210,7 +236,7 @@ public:
~MainWindow();
bool hasOGL;
- QOpenGLContext* getOGLContext();
+ GL::Context* getOGLContext();
bool preloadROMs(QString filename, QString gbafilename);
@@ -306,6 +332,8 @@ private slots:
void onFullscreenToggled();
private:
+ void closeEvent(QCloseEvent* event);
+
QStringList currentROM;
QStringList currentGBAROM;
QList<QString> recentFileList;
diff --git a/src/frontend/qt_sdl/main_shaders.h b/src/frontend/qt_sdl/main_shaders.h
index ca835c0..37b964d 100644
--- a/src/frontend/qt_sdl/main_shaders.h
+++ b/src/frontend/qt_sdl/main_shaders.h
@@ -23,7 +23,6 @@ const char* kScreenVS = R"(#version 140
uniform vec2 uScreenSize;
uniform mat2x3 uTransform;
-uniform float uScaleFactor;
in vec2 vPosition;
in vec2 vTexcoord;
@@ -34,9 +33,9 @@ void main()
{
vec4 fpos;
- fpos.xy = vec3(vPosition, 1.0) * uTransform * uScaleFactor;
+ fpos.xy = vec3(vPosition, 1.0) * uTransform;
- fpos.xy = ((fpos.xy * 2.0) / (uScreenSize * uScaleFactor)) - 1.0;
+ fpos.xy = ((fpos.xy * 2.0) / uScreenSize) - 1.0;
fpos.y *= -1;
fpos.z = 0.0;
fpos.w = 1.0;