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
This commit is contained in:
Xaver Hugl 2024-04-08 20:44:15 +02:00
parent e2611d710f
commit 4037f093db
5 changed files with 26 additions and 8 deletions

View file

@ -42,7 +42,7 @@ void BackingStore::resize(const QSize &size, const QRegion &staticContents)
void BackingStore::beginPaint(const QRegion &region)
{
Window *platformWindow = static_cast<Window *>(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;

View file

@ -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<Window *>(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

View file

@ -65,7 +65,7 @@ private:
EglDisplay *m_eglDisplay = nullptr;
QSurfaceFormat m_format;
EGLConfig m_config = EGL_NO_CONFIG_KHR;
std::unique_ptr<EglContext> m_eglContext;
std::shared_ptr<EglContext> m_eglContext;
std::unordered_map<GraphicsBuffer *, std::shared_ptr<EGLRenderTarget>> m_renderTargets;
std::vector<std::shared_ptr<EGLRenderTarget>> m_zombieRenderTargets;
std::shared_ptr<EGLRenderTarget> m_current;

View file

@ -43,13 +43,14 @@ Window::~Window()
unmap();
}
Swapchain *Window::swapchain(const QHash<uint32_t, QList<uint64_t>> &formats)
Swapchain *Window::swapchain(const std::shared_ptr<EglContext> &context, const QHash<uint32_t, QList<uint64_t>> &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<uint32_t, QList<uint64_t>> &formats)
continue;
}
m_swapchain = std::make_unique<Swapchain>(allocator, options, buffer);
m_eglContext = context;
break;
}
}

View file

@ -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<uint32_t, QList<uint64_t>> &formats);
Swapchain *swapchain(const std::shared_ptr<EglContext> &context, const QHash<uint32_t, QList<uint64_t>> &formats);
private:
void map();
@ -46,6 +47,7 @@ private:
QSurfaceFormat m_format;
QPointer<InternalWindow> m_handle;
std::unique_ptr<Swapchain> m_swapchain;
std::weak_ptr<EglContext> m_eglContext;
quint32 m_windowId;
qreal m_scale = 1;
};