From 4037f093db2d924095fbb32f0748b2429ba56989 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Mon, 8 Apr 2024 20:44:15 +0200 Subject: [PATCH] plugins/qpa: support recovering from GPU resets When the context experienced a GPU reset, the context and all swapchains need to be recreated or there will be glitches --- src/plugins/qpa/backingstore.cpp | 2 +- src/plugins/qpa/eglplatformcontext.cpp | 18 ++++++++++++++++-- src/plugins/qpa/eglplatformcontext.h | 2 +- src/plugins/qpa/window.cpp | 8 +++++--- src/plugins/qpa/window.h | 4 +++- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/plugins/qpa/backingstore.cpp b/src/plugins/qpa/backingstore.cpp index f48cc6381d..bd2d4e29f2 100644 --- a/src/plugins/qpa/backingstore.cpp +++ b/src/plugins/qpa/backingstore.cpp @@ -42,7 +42,7 @@ void BackingStore::resize(const QSize &size, const QRegion &staticContents) void BackingStore::beginPaint(const QRegion ®ion) { Window *platformWindow = static_cast(window()->handle()); - Swapchain *swapchain = platformWindow->swapchain({{DRM_FORMAT_ARGB8888, {DRM_FORMAT_MOD_LINEAR}}}); + Swapchain *swapchain = platformWindow->swapchain(nullptr, {{DRM_FORMAT_ARGB8888, {DRM_FORMAT_MOD_LINEAR}}}); if (!swapchain) { qCCritical(KWIN_QPA, "Failed to ceate a swapchain for the backing store!"); return; diff --git a/src/plugins/qpa/eglplatformcontext.cpp b/src/plugins/qpa/eglplatformcontext.cpp index 5f527149c1..5a4b549ee2 100644 --- a/src/plugins/qpa/eglplatformcontext.cpp +++ b/src/plugins/qpa/eglplatformcontext.cpp @@ -51,6 +51,9 @@ EGLPlatformContext::EGLPlatformContext(QOpenGLContext *context, EglDisplay *disp EGLPlatformContext::~EGLPlatformContext() { + if (!m_eglContext) { + return; + } if (!m_renderTargets.empty() || !m_zombieRenderTargets.empty()) { m_eglContext->makeCurrent(); m_renderTargets.clear(); @@ -60,11 +63,20 @@ EGLPlatformContext::~EGLPlatformContext() bool EGLPlatformContext::makeCurrent(QPlatformSurface *surface) { + if (!m_eglContext) { + return false; + } const bool ok = m_eglContext->makeCurrent(); if (!ok) { qCWarning(KWIN_QPA, "eglMakeCurrent failed: %x", eglGetError()); return false; } + if (m_eglContext->checkGraphicsResetStatus() != GL_NO_ERROR) { + m_renderTargets.clear(); + m_zombieRenderTargets.clear(); + m_eglContext.reset(); + return false; + } m_zombieRenderTargets.clear(); @@ -75,7 +87,7 @@ bool EGLPlatformContext::makeCurrent(QPlatformSurface *surface) QOpenGLContextPrivate::setCurrentContext(context()); Window *window = static_cast(surface); - Swapchain *swapchain = window->swapchain(m_eglDisplay->nonExternalOnlySupportedDrmFormats()); + Swapchain *swapchain = window->swapchain(m_eglContext, m_eglDisplay->nonExternalOnlySupportedDrmFormats()); GraphicsBuffer *buffer = swapchain->acquire(); if (!buffer) { @@ -116,7 +128,9 @@ bool EGLPlatformContext::makeCurrent(QPlatformSurface *surface) void EGLPlatformContext::doneCurrent() { - m_eglContext->doneCurrent(); + if (m_eglContext) { + m_eglContext->doneCurrent(); + } } bool EGLPlatformContext::isValid() const diff --git a/src/plugins/qpa/eglplatformcontext.h b/src/plugins/qpa/eglplatformcontext.h index 5f88617770..f9ffe6531c 100644 --- a/src/plugins/qpa/eglplatformcontext.h +++ b/src/plugins/qpa/eglplatformcontext.h @@ -65,7 +65,7 @@ private: EglDisplay *m_eglDisplay = nullptr; QSurfaceFormat m_format; EGLConfig m_config = EGL_NO_CONFIG_KHR; - std::unique_ptr m_eglContext; + std::shared_ptr m_eglContext; std::unordered_map> m_renderTargets; std::vector> m_zombieRenderTargets; std::shared_ptr m_current; diff --git a/src/plugins/qpa/window.cpp b/src/plugins/qpa/window.cpp index 114c52302a..b0f355d729 100644 --- a/src/plugins/qpa/window.cpp +++ b/src/plugins/qpa/window.cpp @@ -43,13 +43,14 @@ Window::~Window() unmap(); } -Swapchain *Window::swapchain(const QHash> &formats) +Swapchain *Window::swapchain(const std::shared_ptr &context, const QHash> &formats) { const QSize nativeSize = geometry().size() * devicePixelRatio(); + const bool software = window()->surfaceType() == QSurface::RasterSurface; // RasterGLSurface is unsupported by us if (!m_swapchain || m_swapchain->size() != nativeSize || !formats.contains(m_swapchain->format()) - || m_swapchain->modifiers() != formats[m_swapchain->format()]) { - const bool software = window()->surfaceType() == QSurface::RasterSurface; // RasterGLSurface is unsupported by us + || m_swapchain->modifiers() != formats[m_swapchain->format()] + || (!software && m_eglContext.lock() != context)) { GraphicsBufferAllocator *allocator; if (software) { @@ -72,6 +73,7 @@ Swapchain *Window::swapchain(const QHash> &formats) continue; } m_swapchain = std::make_unique(allocator, options, buffer); + m_eglContext = context; break; } } diff --git a/src/plugins/qpa/window.h b/src/plugins/qpa/window.h index 5b54f29fe8..c4d1d78792 100644 --- a/src/plugins/qpa/window.h +++ b/src/plugins/qpa/window.h @@ -16,6 +16,7 @@ namespace KWin { class InternalWindow; +class EglContext; namespace QPA { @@ -37,7 +38,7 @@ public: void requestActivateWindow() override; InternalWindow *internalWindow() const; - Swapchain *swapchain(const QHash> &formats); + Swapchain *swapchain(const std::shared_ptr &context, const QHash> &formats); private: void map(); @@ -46,6 +47,7 @@ private: QSurfaceFormat m_format; QPointer m_handle; std::unique_ptr m_swapchain; + std::weak_ptr m_eglContext; quint32 m_windowId; qreal m_scale = 1; };