From d96b2a711b017b5057ea0fcf6f181be8609c9649 Mon Sep 17 00:00:00 2001 From: BearOso Date: Mon, 4 Sep 2023 11:03:21 -0500 Subject: [PATCH] Qt: Handle failed context creation better. --- qt/src/EmuCanvas.hpp | 2 +- qt/src/EmuCanvasOpenGL.cpp | 17 ++++++++++++++--- qt/src/EmuCanvasOpenGL.hpp | 2 +- qt/src/EmuCanvasVulkan.cpp | 39 ++++++++++++++++++++++++++++++-------- qt/src/EmuCanvasVulkan.hpp | 2 +- qt/src/EmuMainWindow.cpp | 39 ++++++++++++++++++++++++++++---------- qt/src/EmuMainWindow.hpp | 2 +- 7 files changed, 78 insertions(+), 25 deletions(-) diff --git a/qt/src/EmuCanvas.hpp b/qt/src/EmuCanvas.hpp index e609b67e..09fb398a 100644 --- a/qt/src/EmuCanvas.hpp +++ b/qt/src/EmuCanvas.hpp @@ -14,7 +14,7 @@ class EmuCanvas : public QWidget virtual void deinit() = 0; virtual void draw() = 0; void paintEvent(QPaintEvent *) override = 0; - virtual void createContext() {} + virtual bool createContext() { return false; } virtual void recreateUIAssets() {} void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate); void throttle(); diff --git a/qt/src/EmuCanvasOpenGL.cpp b/qt/src/EmuCanvasOpenGL.cpp index 250cc33e..a075826c 100644 --- a/qt/src/EmuCanvasOpenGL.cpp +++ b/qt/src/EmuCanvasOpenGL.cpp @@ -122,10 +122,10 @@ void EmuCanvasOpenGL::customShaderDraw() shader->render(texture, output_data.width, output_data.height, viewport.x(), viewport.y(), viewport.width(), viewport.height(), S9xViewportCallback); } -void EmuCanvasOpenGL::createContext() +bool EmuCanvasOpenGL::createContext() { if (context) - return; + return true; auto platform = QGuiApplication::platformName(); auto pni = QGuiApplication::platformNativeInterface(); @@ -139,7 +139,11 @@ void EmuCanvasOpenGL::createContext() int s = devicePixelRatio(); if (!wayland_egl_context->attach(display, surface, { parent->x(), parent->y(), parent->width(), parent->height(), s })) + { printf("Couldn't attach context to wayland surface.\n"); + context.reset(); + return false; + } context.reset(wayland_egl_context); } @@ -150,7 +154,11 @@ void EmuCanvasOpenGL::createContext() auto glx_context = new GTKGLXContext(); if (!glx_context->attach(display, xid)) + { printf("Couldn't attach to X11 window.\n"); + context.reset(); + return false; + } context.reset(glx_context); } @@ -160,7 +168,8 @@ void EmuCanvasOpenGL::createContext() if (!wgl_context->attach((HWND)hwnd)) { printf("Couldn't attach to context\n"); - return; + context.reset(); + return false; } context.reset(wgl_context); #endif @@ -194,6 +203,8 @@ void EmuCanvasOpenGL::createContext() context->swap_interval(config->enable_vsync ? 1 : 0); QGuiApplication::sync(); paintEvent(nullptr); + + return true; } void EmuCanvasOpenGL::loadShaders() diff --git a/qt/src/EmuCanvasOpenGL.hpp b/qt/src/EmuCanvasOpenGL.hpp index 2aa95dc6..d8148790 100644 --- a/qt/src/EmuCanvasOpenGL.hpp +++ b/qt/src/EmuCanvasOpenGL.hpp @@ -14,7 +14,7 @@ class EmuCanvasOpenGL : public EmuCanvas EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window); ~EmuCanvasOpenGL(); - void createContext() override; + bool createContext() override; void deinit() override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; diff --git a/qt/src/EmuCanvasVulkan.cpp b/qt/src/EmuCanvasVulkan.cpp index 486653d9..d4ad0bba 100644 --- a/qt/src/EmuCanvasVulkan.cpp +++ b/qt/src/EmuCanvasVulkan.cpp @@ -75,10 +75,10 @@ bool EmuCanvasVulkan::initImGui() return true; } -void EmuCanvasVulkan::createContext() +bool EmuCanvasVulkan::createContext() { - if (simple_output) - return; + if (context) + return true; platform = QGuiApplication::platformName(); auto pni = QGuiApplication::platformNativeInterface(); @@ -89,7 +89,11 @@ void EmuCanvasVulkan::createContext() #ifdef _WIN32 auto hwnd = (HWND)winId(); - context->init_win32(nullptr, hwnd, config->display_device_index); + if (!context->init_win32(nullptr, hwnd, config->display_device_index)) + { + context.reset(); + return false; + } #else if (platform == "wayland") { @@ -98,14 +102,21 @@ void EmuCanvasVulkan::createContext() auto surface = (wl_surface *)pni->nativeResourceForWindow("surface", main_window->windowHandle()); wayland_surface->attach(display, surface, { parent->x(), parent->y(), width(), height(), static_cast(devicePixelRatio()) }); auto [scaled_width, scaled_height] = wayland_surface->get_size(); - context->init_wayland(display, wayland_surface->child, scaled_width, scaled_height, config->display_device_index); + if (!context->init_wayland(display, wayland_surface->child, scaled_width, scaled_height, config->display_device_index)) + { + context.reset(); + return false; + } } else if (platform == "xcb") { auto display = (Display *)pni->nativeResourceForWindow("display", window); auto xid = (Window)winId(); - - context->init_Xlib(display, xid, config->display_device_index); + if (!context->init_Xlib(display, xid, config->display_device_index)) + { + context.reset(); + return false; + } } #endif @@ -116,10 +127,15 @@ void EmuCanvasVulkan::createContext() QGuiApplication::sync(); paintEvent(nullptr); + + return true; } void EmuCanvasVulkan::tryLoadShader() { + if (!context) + return; + simple_output.reset(); shader_chain.reset(); shader_parameters_dialog.reset(); @@ -143,6 +159,9 @@ void EmuCanvasVulkan::tryLoadShader() void EmuCanvasVulkan::shaderChanged() { + if (!context) + return; + if (!config->use_shader) current_shader.clear(); @@ -248,7 +267,8 @@ void EmuCanvasVulkan::deinit() if (ImGui::GetCurrentContext()) { - context->wait_idle(); + if (context) + context->wait_idle(); imgui_descriptor_pool.reset(); imgui_render_pass.reset(); ImGui_ImplVulkan_Shutdown(); @@ -305,6 +325,9 @@ void EmuCanvasVulkan::saveParameters(std::string filename) void EmuCanvasVulkan::recreateUIAssets() { + if (!context) + return; + if (ImGui::GetCurrentContext()) { context->wait_idle(); diff --git a/qt/src/EmuCanvasVulkan.hpp b/qt/src/EmuCanvasVulkan.hpp index 0a2140b8..20afb375 100644 --- a/qt/src/EmuCanvasVulkan.hpp +++ b/qt/src/EmuCanvasVulkan.hpp @@ -16,7 +16,7 @@ class EmuCanvasVulkan : public EmuCanvas EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window); ~EmuCanvasVulkan(); - void createContext() override; + bool createContext() override; void deinit() override; void paintEvent(QPaintEvent *event) override; void resizeEvent(QResizeEvent *event) override; diff --git a/qt/src/EmuMainWindow.cpp b/qt/src/EmuMainWindow.cpp index 1b45f59e..06148d5a 100644 --- a/qt/src/EmuMainWindow.cpp +++ b/qt/src/EmuMainWindow.cpp @@ -73,7 +73,7 @@ void EmuMainWindow::destroyCanvas() } } -void EmuMainWindow::createCanvas() +bool EmuMainWindow::createCanvas() { if (app->config->display_driver != "vulkan" && app->config->display_driver != "opengl" && @@ -91,8 +91,12 @@ void EmuMainWindow::createCanvas() { canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this); QGuiApplication::processEvents(); - canvas->createContext(); - } + if (!canvas->createContext()) + { + delete canvas; + return false; + } + } else if (app->config->display_driver == "opengl") { canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this); @@ -106,7 +110,7 @@ void EmuMainWindow::createCanvas() using_stacked_widget = true; QGuiApplication::processEvents(); - return; + return true; } #endif @@ -114,26 +118,41 @@ void EmuMainWindow::createCanvas() { canvas = new EmuCanvasVulkan(app->config.get(), this, this); QGuiApplication::processEvents(); - canvas->createContext(); + if (!canvas->createContext()) + { + delete canvas; + return false; + } } else if (app->config->display_driver == "opengl") { canvas = new EmuCanvasOpenGL(app->config.get(), this, this); QGuiApplication::processEvents(); app->emu_thread->runOnThread([&] { canvas->createContext(); }, true); - } + } else canvas = new EmuCanvasQt(app->config.get(), this, this); setCentralWidget(canvas); using_stacked_widget = false; + + return true; } void EmuMainWindow::recreateCanvas() { app->suspendThread(); destroyCanvas(); - createCanvas(); + + if (!createCanvas()) + { + QMessageBox::warning(this, + tr("Unable to Start Display Driver"), + tr("Unable to create a %1 context. Attempting to use qt.").arg(QString::fromUtf8(app->config->display_driver))); + app->config->display_driver = "qt"; + createCanvas(); + } + app->unsuspendThread(); } @@ -526,7 +545,7 @@ bool EmuMainWindow::event(QEvent *event) minimized_pause = false; app->unpause(); } - + break; } case QEvent::MouseMove: @@ -570,9 +589,9 @@ void EmuMainWindow::toggleFullscreen() bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event) { - if (watched == canvas) + if (watched == canvas) { - if (event->type() == QEvent::Resize) + if (event->type() == QEvent::Resize) { app->emu_thread->runOnThread([&] { canvas->resizeEvent((QResizeEvent *)event); diff --git a/qt/src/EmuMainWindow.hpp b/qt/src/EmuMainWindow.hpp index 23cbc169..c00b09cb 100644 --- a/qt/src/EmuMainWindow.hpp +++ b/qt/src/EmuMainWindow.hpp @@ -20,7 +20,7 @@ class EmuMainWindow : public QMainWindow ~EmuMainWindow(); void toggleFullscreen(); - void createCanvas(); + bool createCanvas(); void destroyCanvas(); void recreateCanvas(); void setBypassCompositor(bool);