Qt: Handle failed context creation better.

This commit is contained in:
BearOso 2023-09-04 11:03:21 -05:00
parent cf49325555
commit d96b2a711b
7 changed files with 78 additions and 25 deletions

View File

@ -14,7 +14,7 @@ class EmuCanvas : public QWidget
virtual void deinit() = 0; virtual void deinit() = 0;
virtual void draw() = 0; virtual void draw() = 0;
void paintEvent(QPaintEvent *) override = 0; void paintEvent(QPaintEvent *) override = 0;
virtual void createContext() {} virtual bool createContext() { return false; }
virtual void recreateUIAssets() {} virtual void recreateUIAssets() {}
void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate); void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate);
void throttle(); void throttle();

View File

@ -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); 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) if (context)
return; return true;
auto platform = QGuiApplication::platformName(); auto platform = QGuiApplication::platformName();
auto pni = QGuiApplication::platformNativeInterface(); auto pni = QGuiApplication::platformNativeInterface();
@ -139,7 +139,11 @@ void EmuCanvasOpenGL::createContext()
int s = devicePixelRatio(); int s = devicePixelRatio();
if (!wayland_egl_context->attach(display, surface, { parent->x(), parent->y(), parent->width(), parent->height(), s })) 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"); printf("Couldn't attach context to wayland surface.\n");
context.reset();
return false;
}
context.reset(wayland_egl_context); context.reset(wayland_egl_context);
} }
@ -150,7 +154,11 @@ void EmuCanvasOpenGL::createContext()
auto glx_context = new GTKGLXContext(); auto glx_context = new GTKGLXContext();
if (!glx_context->attach(display, xid)) if (!glx_context->attach(display, xid))
{
printf("Couldn't attach to X11 window.\n"); printf("Couldn't attach to X11 window.\n");
context.reset();
return false;
}
context.reset(glx_context); context.reset(glx_context);
} }
@ -160,7 +168,8 @@ void EmuCanvasOpenGL::createContext()
if (!wgl_context->attach((HWND)hwnd)) if (!wgl_context->attach((HWND)hwnd))
{ {
printf("Couldn't attach to context\n"); printf("Couldn't attach to context\n");
return; context.reset();
return false;
} }
context.reset(wgl_context); context.reset(wgl_context);
#endif #endif
@ -194,6 +203,8 @@ void EmuCanvasOpenGL::createContext()
context->swap_interval(config->enable_vsync ? 1 : 0); context->swap_interval(config->enable_vsync ? 1 : 0);
QGuiApplication::sync(); QGuiApplication::sync();
paintEvent(nullptr); paintEvent(nullptr);
return true;
} }
void EmuCanvasOpenGL::loadShaders() void EmuCanvasOpenGL::loadShaders()

View File

@ -14,7 +14,7 @@ class EmuCanvasOpenGL : public EmuCanvas
EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window); EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window);
~EmuCanvasOpenGL(); ~EmuCanvasOpenGL();
void createContext() override; bool createContext() override;
void deinit() override; void deinit() override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;

View File

@ -75,10 +75,10 @@ bool EmuCanvasVulkan::initImGui()
return true; return true;
} }
void EmuCanvasVulkan::createContext() bool EmuCanvasVulkan::createContext()
{ {
if (simple_output) if (context)
return; return true;
platform = QGuiApplication::platformName(); platform = QGuiApplication::platformName();
auto pni = QGuiApplication::platformNativeInterface(); auto pni = QGuiApplication::platformNativeInterface();
@ -89,7 +89,11 @@ void EmuCanvasVulkan::createContext()
#ifdef _WIN32 #ifdef _WIN32
auto hwnd = (HWND)winId(); 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 #else
if (platform == "wayland") if (platform == "wayland")
{ {
@ -98,14 +102,21 @@ void EmuCanvasVulkan::createContext()
auto surface = (wl_surface *)pni->nativeResourceForWindow("surface", main_window->windowHandle()); auto surface = (wl_surface *)pni->nativeResourceForWindow("surface", main_window->windowHandle());
wayland_surface->attach(display, surface, { parent->x(), parent->y(), width(), height(), static_cast<int>(devicePixelRatio()) }); wayland_surface->attach(display, surface, { parent->x(), parent->y(), width(), height(), static_cast<int>(devicePixelRatio()) });
auto [scaled_width, scaled_height] = wayland_surface->get_size(); 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") else if (platform == "xcb")
{ {
auto display = (Display *)pni->nativeResourceForWindow("display", window); auto display = (Display *)pni->nativeResourceForWindow("display", window);
auto xid = (Window)winId(); auto xid = (Window)winId();
if (!context->init_Xlib(display, xid, config->display_device_index))
context->init_Xlib(display, xid, config->display_device_index); {
context.reset();
return false;
}
} }
#endif #endif
@ -116,10 +127,15 @@ void EmuCanvasVulkan::createContext()
QGuiApplication::sync(); QGuiApplication::sync();
paintEvent(nullptr); paintEvent(nullptr);
return true;
} }
void EmuCanvasVulkan::tryLoadShader() void EmuCanvasVulkan::tryLoadShader()
{ {
if (!context)
return;
simple_output.reset(); simple_output.reset();
shader_chain.reset(); shader_chain.reset();
shader_parameters_dialog.reset(); shader_parameters_dialog.reset();
@ -143,6 +159,9 @@ void EmuCanvasVulkan::tryLoadShader()
void EmuCanvasVulkan::shaderChanged() void EmuCanvasVulkan::shaderChanged()
{ {
if (!context)
return;
if (!config->use_shader) if (!config->use_shader)
current_shader.clear(); current_shader.clear();
@ -248,7 +267,8 @@ void EmuCanvasVulkan::deinit()
if (ImGui::GetCurrentContext()) if (ImGui::GetCurrentContext())
{ {
context->wait_idle(); if (context)
context->wait_idle();
imgui_descriptor_pool.reset(); imgui_descriptor_pool.reset();
imgui_render_pass.reset(); imgui_render_pass.reset();
ImGui_ImplVulkan_Shutdown(); ImGui_ImplVulkan_Shutdown();
@ -305,6 +325,9 @@ void EmuCanvasVulkan::saveParameters(std::string filename)
void EmuCanvasVulkan::recreateUIAssets() void EmuCanvasVulkan::recreateUIAssets()
{ {
if (!context)
return;
if (ImGui::GetCurrentContext()) if (ImGui::GetCurrentContext())
{ {
context->wait_idle(); context->wait_idle();

View File

@ -16,7 +16,7 @@ class EmuCanvasVulkan : public EmuCanvas
EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window); EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window);
~EmuCanvasVulkan(); ~EmuCanvasVulkan();
void createContext() override; bool createContext() override;
void deinit() override; void deinit() override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;

View File

@ -73,7 +73,7 @@ void EmuMainWindow::destroyCanvas()
} }
} }
void EmuMainWindow::createCanvas() bool EmuMainWindow::createCanvas()
{ {
if (app->config->display_driver != "vulkan" && if (app->config->display_driver != "vulkan" &&
app->config->display_driver != "opengl" && app->config->display_driver != "opengl" &&
@ -91,8 +91,12 @@ void EmuMainWindow::createCanvas()
{ {
canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this); canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this);
QGuiApplication::processEvents(); QGuiApplication::processEvents();
canvas->createContext(); if (!canvas->createContext())
} {
delete canvas;
return false;
}
}
else if (app->config->display_driver == "opengl") else if (app->config->display_driver == "opengl")
{ {
canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this); canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this);
@ -106,7 +110,7 @@ void EmuMainWindow::createCanvas()
using_stacked_widget = true; using_stacked_widget = true;
QGuiApplication::processEvents(); QGuiApplication::processEvents();
return; return true;
} }
#endif #endif
@ -114,26 +118,41 @@ void EmuMainWindow::createCanvas()
{ {
canvas = new EmuCanvasVulkan(app->config.get(), this, this); canvas = new EmuCanvasVulkan(app->config.get(), this, this);
QGuiApplication::processEvents(); QGuiApplication::processEvents();
canvas->createContext(); if (!canvas->createContext())
{
delete canvas;
return false;
}
} }
else if (app->config->display_driver == "opengl") else if (app->config->display_driver == "opengl")
{ {
canvas = new EmuCanvasOpenGL(app->config.get(), this, this); canvas = new EmuCanvasOpenGL(app->config.get(), this, this);
QGuiApplication::processEvents(); QGuiApplication::processEvents();
app->emu_thread->runOnThread([&] { canvas->createContext(); }, true); app->emu_thread->runOnThread([&] { canvas->createContext(); }, true);
} }
else else
canvas = new EmuCanvasQt(app->config.get(), this, this); canvas = new EmuCanvasQt(app->config.get(), this, this);
setCentralWidget(canvas); setCentralWidget(canvas);
using_stacked_widget = false; using_stacked_widget = false;
return true;
} }
void EmuMainWindow::recreateCanvas() void EmuMainWindow::recreateCanvas()
{ {
app->suspendThread(); app->suspendThread();
destroyCanvas(); 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(); app->unsuspendThread();
} }
@ -526,7 +545,7 @@ bool EmuMainWindow::event(QEvent *event)
minimized_pause = false; minimized_pause = false;
app->unpause(); app->unpause();
} }
break; break;
} }
case QEvent::MouseMove: case QEvent::MouseMove:
@ -570,9 +589,9 @@ void EmuMainWindow::toggleFullscreen()
bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event) 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([&] { app->emu_thread->runOnThread([&] {
canvas->resizeEvent((QResizeEvent *)event); canvas->resizeEvent((QResizeEvent *)event);

View File

@ -20,7 +20,7 @@ class EmuMainWindow : public QMainWindow
~EmuMainWindow(); ~EmuMainWindow();
void toggleFullscreen(); void toggleFullscreen();
void createCanvas(); bool createCanvas();
void destroyCanvas(); void destroyCanvas();
void recreateCanvas(); void recreateCanvas();
void setBypassCompositor(bool); void setBypassCompositor(bool);