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 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();

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);
}
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()

View File

@ -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;

View File

@ -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<int>(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();

View File

@ -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;

View File

@ -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);

View File

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