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:
parent
e2611d710f
commit
4037f093db
5 changed files with 26 additions and 8 deletions
|
@ -42,7 +42,7 @@ void BackingStore::resize(const QSize &size, const QRegion &staticContents)
|
|||
void BackingStore::beginPaint(const QRegion ®ion)
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue