diff --git a/include/panda_qt/main_window.hpp b/include/panda_qt/main_window.hpp index 831074a2..717da5e7 100644 --- a/include/panda_qt/main_window.hpp +++ b/include/panda_qt/main_window.hpp @@ -50,6 +50,7 @@ class MainWindow : public QMainWindow { PressTouchscreen, ReleaseTouchscreen, ReloadUbershader, + SetScreenSize, }; // Tagged union representing our message queue messages @@ -81,6 +82,11 @@ class MainWindow : public QMainWindow { u16 x; u16 y; } touchscreen; + + struct { + u32 width; + u32 height; + } screenSize; }; }; @@ -141,4 +147,6 @@ class MainWindow : public QMainWindow { void loadLuaScript(const std::string& code); void reloadShader(const std::string& shader); void editCheat(u32 handle, const std::vector& cheat, const std::function& callback); + + void handleScreenResize(u32 width, u32 height); }; diff --git a/include/panda_qt/screen.hpp b/include/panda_qt/screen.hpp index dcff3e90..a39b5076 100644 --- a/include/panda_qt/screen.hpp +++ b/include/panda_qt/screen.hpp @@ -11,11 +11,20 @@ class ScreenWidget : public QWidget { public: ScreenWidget(QWidget* parent = nullptr); + void resizeEvent(QResizeEvent* event) override; + // Called by the emulator thread for resizing the actual GL surface, since the emulator thread owns the GL context + void resizeSurface(u32 width, u32 height); + GL::Context* getGLContext() { return glContext.get(); } // Dimensions of our output surface u32 surfaceWidth = 0; u32 surfaceHeight = 0; + WindowInfo windowInfo; + + // Cached "previous" dimensions, used when resizing our window + u32 previousWidth = 0; + u32 previousHeight = 0; private: std::unique_ptr glContext = nullptr; diff --git a/src/panda_qt/main_window.cpp b/src/panda_qt/main_window.cpp index cfa45e85..a66222b6 100644 --- a/src/panda_qt/main_window.cpp +++ b/src/panda_qt/main_window.cpp @@ -16,6 +16,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent) // Enable drop events for loading ROMs setAcceptDrops(true); resize(800, 240 * 4); + setCentralWidget(&screen); screen.show(); appRunning = true; @@ -360,6 +361,15 @@ void MainWindow::dispatchMessage(const EmulatorMessage& message) { emu->getRenderer()->setUbershader(*message.string.str); delete message.string.str; break; + + case MessageType::SetScreenSize: { + const u32 width = message.screenSize.width; + const u32 height = message.screenSize.height; + + emu->setOutputSize(width, height); + screen.resizeSurface(width, height); + break; + } } } @@ -482,6 +492,14 @@ void MainWindow::editCheat(u32 handle, const std::vector& cheat, const sendMessage(message); } +void MainWindow::handleScreenResize(u32 width, u32 height) { + EmulatorMessage message{.type = MessageType::SetScreenSize}; + message.screenSize.width = width; + message.screenSize.height = height; + + sendMessage(message); +} + void MainWindow::initControllers() { // Make SDL use consistent positional button mapping SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); diff --git a/src/panda_qt/screen.cpp b/src/panda_qt/screen.cpp index 5a254e79..b2d7caf6 100644 --- a/src/panda_qt/screen.cpp +++ b/src/panda_qt/screen.cpp @@ -12,6 +12,7 @@ #include #endif +#include "panda_qt/main_window.hpp" #include "panda_qt/screen.hpp" // OpenGL screen widget, based on https://github.com/stenzek/duckstation/blob/master/src/duckstation-qt/displaywidget.cpp @@ -35,6 +36,31 @@ ScreenWidget::ScreenWidget(QWidget* parent) : QWidget(parent) { } } +void ScreenWidget::resizeEvent(QResizeEvent* event) { + previousWidth = surfaceWidth; + previousHeight = surfaceHeight; + + QWidget::resizeEvent(event); + + // Update surfaceWidth/surfaceHeight following the resize + std::optional windowInfo = getWindowInfo(); + if (windowInfo) { + this->windowInfo = *windowInfo; + } + + // This will call take care of calling resizeSurface from the emulator thread + static_cast(parentWidget())->handleScreenResize(surfaceWidth, surfaceHeight); +} + +// Note: This will run on the emulator thread, we don't want any Qt calls happening there. +void ScreenWidget::resizeSurface(u32 width, u32 height) { + if (previousWidth != width || previousHeight != height) { + if (glContext) { + glContext->ResizeSurface(width, height); + } + } +} + bool ScreenWidget::createGLContext() { // List of GL context versions we will try. Anything 4.1+ is good static constexpr std::array versionsToTry = { @@ -45,6 +71,8 @@ bool ScreenWidget::createGLContext() { std::optional windowInfo = getWindowInfo(); if (windowInfo.has_value()) { + this->windowInfo = *windowInfo; + glContext = GL::Context::Create(*getWindowInfo(), versionsToTry); glContext->DoneCurrent(); }