From 466868f5d435c00a515cf4ecad4b65fd795ba756 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Fri, 7 Apr 2023 13:04:06 +0300 Subject: [PATCH] wayland: Refactor linux-dmabuf buffer management At the moment, the render backend provides its specific implementation of LinuxDmaBufV1ClientBuffer. This has some of its limitations. For example, due to the strong coupling, compositing restarts must be handled carefully. It's hard to have a generic code path to import dmabufs, which would be nice to have in order to unify graphics buffer allocation across various backends; currently, it's all scattered. To make the code simpler, this change drops the commented out YUV import code path for now. Given that Mesa implicitly handles it, the need for it is no longer so urgent. --- src/CMakeLists.txt | 1 - src/backends/drm/drm_dmabuf_feedback.cpp | 3 +- src/backends/drm/drm_egl_backend.cpp | 2 - src/backends/drm/drm_egl_layer.cpp | 1 - src/backends/drm/drm_egl_layer_surface.cpp | 1 - src/backends/drm/drm_virtual_egl_layer.cpp | 3 +- src/core/renderbackend.cpp | 5 + src/core/renderbackend.h | 6 + src/linux_dmabuf.cpp | 50 --- src/linux_dmabuf.h | 37 -- .../scenes/opengl/CMakeLists.txt | 1 - .../scenes/opengl/abstract_egl_backend.cpp | 148 +++++++- .../scenes/opengl/abstract_egl_backend.h | 11 +- .../opengl/basiceglsurfacetexture_wayland.cpp | 17 +- .../scenes/opengl/egl_dmabuf.cpp | 340 ------------------ .../scenes/opengl/egl_dmabuf.h | 82 ----- src/wayland/linuxdmabufv1clientbuffer.cpp | 47 ++- src/wayland/linuxdmabufv1clientbuffer.h | 40 +-- src/wayland/linuxdmabufv1clientbuffer_p.h | 2 +- src/wayland_server.h | 15 - 20 files changed, 200 insertions(+), 612 deletions(-) delete mode 100644 src/linux_dmabuf.cpp delete mode 100644 src/linux_dmabuf.h delete mode 100644 src/platformsupport/scenes/opengl/egl_dmabuf.cpp delete mode 100644 src/platformsupport/scenes/opengl/egl_dmabuf.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 83ce1d07ff..eb16fbc269 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,7 +98,6 @@ target_sources(kwin PRIVATE layers.cpp layershellv1integration.cpp layershellv1window.cpp - linux_dmabuf.cpp main.cpp modifier_only_shortcuts.cpp mousebuttons.cpp diff --git a/src/backends/drm/drm_dmabuf_feedback.cpp b/src/backends/drm/drm_dmabuf_feedback.cpp index dd4aad972a..0792323f34 100644 --- a/src/backends/drm/drm_dmabuf_feedback.cpp +++ b/src/backends/drm/drm_dmabuf_feedback.cpp @@ -10,7 +10,6 @@ #include "drm_egl_backend.h" #include "drm_gpu.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include "wayland/surface_interface.h" @@ -62,7 +61,7 @@ void DmabufFeedback::scanoutFailed(KWaylandServer::SurfaceInterface *surface, co if (!m_attemptedFormats[dmabufAttrs.format].contains(dmabufAttrs.modifier)) { m_attemptedFormats[dmabufAttrs.format] << dmabufAttrs.modifier; QVector scanoutTranches; - const auto tranches = m_eglBackend->dmabuf()->tranches(); + const auto tranches = m_eglBackend->tranches(); for (const auto &tranche : tranches) { KWaylandServer::LinuxDmaBufV1Feedback::Tranche scanoutTranche; for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) { diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp index 9fa8e8a6a0..891e26f52e 100644 --- a/src/backends/drm/drm_egl_backend.cpp +++ b/src/backends/drm/drm_egl_backend.cpp @@ -25,9 +25,7 @@ #include "drm_virtual_egl_layer.h" #include "gbm_dmabuf.h" #include "kwineglutils_p.h" -#include "linux_dmabuf.h" #include "options.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "scene/surfaceitem_wayland.h" #include "wayland/clientconnection.h" #include "wayland/linuxdmabufv1clientbuffer.h" diff --git a/src/backends/drm/drm_egl_layer.cpp b/src/backends/drm/drm_egl_layer.cpp index ea666e191c..2c8a927461 100644 --- a/src/backends/drm/drm_egl_layer.cpp +++ b/src/backends/drm/drm_egl_layer.cpp @@ -15,7 +15,6 @@ #include "drm_logging.h" #include "drm_output.h" #include "drm_pipeline.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "scene/surfaceitem_wayland.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include "wayland/surface_interface.h" diff --git a/src/backends/drm/drm_egl_layer_surface.cpp b/src/backends/drm/drm_egl_layer_surface.cpp index a30d81f653..8e1a8bba4a 100644 --- a/src/backends/drm/drm_egl_layer_surface.cpp +++ b/src/backends/drm/drm_egl_layer_surface.cpp @@ -20,7 +20,6 @@ #include "gbm_dmabuf.h" #include "kwineglutils_p.h" #include "libkwineffects/kwinglplatform.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "scene/surfaceitem_wayland.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include "wayland/surface_interface.h" diff --git a/src/backends/drm/drm_virtual_egl_layer.cpp b/src/backends/drm/drm_virtual_egl_layer.cpp index 48401b3c59..ca55b857a7 100644 --- a/src/backends/drm/drm_virtual_egl_layer.cpp +++ b/src/backends/drm/drm_virtual_egl_layer.cpp @@ -19,7 +19,6 @@ #include "drm_virtual_output.h" #include "gbm_dmabuf.h" #include "kwineglutils_p.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "scene/surfaceitem_wayland.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include "wayland/surface_interface.h" @@ -99,7 +98,7 @@ std::shared_ptr VirtualEglGbmLayer::createGbmSwapchain() const static const bool modifiersEnv = qEnvironmentVariableIntValue("KWIN_DRM_USE_MODIFIERS", &modifiersEnvSet) != 0; const bool allowModifiers = !modifiersEnvSet || modifiersEnv; - const auto tranches = m_eglBackend->dmabuf()->tranches(); + const auto tranches = m_eglBackend->tranches(); for (const auto &tranche : tranches) { for (auto it = tranche.formatTable.constBegin(); it != tranche.formatTable.constEnd(); it++) { const auto size = m_output->pixelSize(); diff --git a/src/core/renderbackend.cpp b/src/core/renderbackend.cpp index abcb9baab2..9e7866420f 100644 --- a/src/core/renderbackend.cpp +++ b/src/core/renderbackend.cpp @@ -32,6 +32,11 @@ bool RenderBackend::checkGraphicsReset() return false; } +bool RenderBackend::testImportBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) +{ + return false; +} + QHash> RenderBackend::supportedFormats() const { return QHash>{{DRM_FORMAT_XRGB8888, QVector{DRM_FORMAT_MOD_LINEAR}}}; diff --git a/src/core/renderbackend.h b/src/core/renderbackend.h index 8eaf6b7fd2..37ced87281 100644 --- a/src/core/renderbackend.h +++ b/src/core/renderbackend.h @@ -13,6 +13,11 @@ #include +namespace KWaylandServer +{ +class LinuxDmaBufV1ClientBuffer; +} + namespace KWin { @@ -43,6 +48,7 @@ public: virtual OutputLayer *cursorLayer(Output *output); virtual void present(Output *output) = 0; + virtual bool testImportBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer); virtual QHash> supportedFormats() const; virtual std::unique_ptr createSurfaceTextureInternal(SurfacePixmapInternal *pixmap); diff --git a/src/linux_dmabuf.cpp b/src/linux_dmabuf.cpp deleted file mode 100644 index 03dffffc2c..0000000000 --- a/src/linux_dmabuf.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "linux_dmabuf.h" - -#include "wayland_server.h" - -namespace KWin -{ - -LinuxDmaBufV1ClientBuffer::LinuxDmaBufV1ClientBuffer(DmaBufAttributes &&attrs, quint32 flags) - : KWaylandServer::LinuxDmaBufV1ClientBuffer(std::move(attrs), flags) -{ - waylandServer()->addLinuxDmabufBuffer(this); -} - -LinuxDmaBufV1ClientBuffer::~LinuxDmaBufV1ClientBuffer() -{ - if (waylandServer()) { - waylandServer()->removeLinuxDmabufBuffer(this); - } -} - -LinuxDmaBufV1RendererInterface::LinuxDmaBufV1RendererInterface() -{ - Q_ASSERT(waylandServer()); - waylandServer()->linuxDmabuf()->setRendererInterface(this); -} - -LinuxDmaBufV1RendererInterface::~LinuxDmaBufV1RendererInterface() -{ - waylandServer()->linuxDmabuf()->setRendererInterface(nullptr); -} - -KWaylandServer::LinuxDmaBufV1ClientBuffer *LinuxDmaBufV1RendererInterface::importBuffer(DmaBufAttributes &&attrs, quint32 flags) -{ - return nullptr; -} - -void LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(const QVector &tranches) -{ - waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(tranches); -} - -} diff --git a/src/linux_dmabuf.h b/src/linux_dmabuf.h deleted file mode 100644 index 2ffd84ecab..0000000000 --- a/src/linux_dmabuf.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 Roman Gilg - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once - -#include - -#include "wayland/linuxdmabufv1clientbuffer.h" - -namespace KWin -{ - -class KWIN_EXPORT LinuxDmaBufV1ClientBuffer : public KWaylandServer::LinuxDmaBufV1ClientBuffer -{ -public: - LinuxDmaBufV1ClientBuffer(DmaBufAttributes &&attrs, quint32 flags); - ~LinuxDmaBufV1ClientBuffer() override; -}; - -class KWIN_EXPORT LinuxDmaBufV1RendererInterface : public KWaylandServer::LinuxDmaBufV1ClientBufferIntegration::RendererInterface -{ -public: - explicit LinuxDmaBufV1RendererInterface(); - ~LinuxDmaBufV1RendererInterface() override; - - KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(DmaBufAttributes &&attrs, quint32 flags) override; - -protected: - void setSupportedFormatsAndModifiers(const QVector &tranches); -}; - -} diff --git a/src/platformsupport/scenes/opengl/CMakeLists.txt b/src/platformsupport/scenes/opengl/CMakeLists.txt index 7f5a1261a0..7317b5a5c2 100644 --- a/src/platformsupport/scenes/opengl/CMakeLists.txt +++ b/src/platformsupport/scenes/opengl/CMakeLists.txt @@ -2,7 +2,6 @@ target_sources(kwin PRIVATE abstract_egl_backend.cpp basiceglsurfacetexture_internal.cpp basiceglsurfacetexture_wayland.cpp - egl_dmabuf.cpp openglbackend.cpp openglsurfacetexture.cpp openglsurfacetexture_internal.cpp diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index 72b6a84037..372528b8f4 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -8,11 +8,8 @@ */ #include "platformsupport/scenes/opengl/abstract_egl_backend.h" #include "composite.h" -#include "core/output.h" #include "core/outputbackend.h" -#include "dmabuftexture.h" #include "options.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" #include "utils/common.h" #include "utils/egl_context_attribute_builder.h" #include "wayland/display.h" @@ -32,6 +29,11 @@ namespace KWin { +typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func)(EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); +typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func)(EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); +eglQueryDmaBufFormatsEXT_func eglQueryDmaBufFormatsEXT = nullptr; +eglQueryDmaBufModifiersEXT_func eglQueryDmaBufModifiersEXT = nullptr; + static EGLContext s_globalShareContext = EGL_NO_CONTEXT; static bool isOpenGLES_helper() @@ -50,7 +52,6 @@ AbstractEglBackend::AbstractEglBackend(dev_t deviceId) AbstractEglBackend::~AbstractEglBackend() { - delete m_dmaBuf; } EGLContext AbstractEglBackend::ensureGlobalShareContext() @@ -85,6 +86,10 @@ void AbstractEglBackend::teardown() void AbstractEglBackend::cleanup() { + for (const EGLImageKHR &image : m_importedBuffers) { + eglDestroyImageKHR(m_display, image); + } + cleanupSurfaces(); cleanupGL(); doneCurrent(); @@ -172,6 +177,34 @@ void AbstractEglBackend::initBufferAge() setSupportsSwapBuffersWithDamage(hasExtension(QByteArrayLiteral("EGL_EXT_swap_buffers_with_damage"))); } +static int bpcForFormat(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_RGB888: + case DRM_FORMAT_BGR888: + return 8; + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_RGBX1010102: + case DRM_FORMAT_BGRX1010102: + case DRM_FORMAT_ARGB2101010: + case DRM_FORMAT_ABGR2101010: + case DRM_FORMAT_RGBA1010102: + case DRM_FORMAT_BGRA1010102: + return 10; + default: + return -1; + } +} + void AbstractEglBackend::initWayland() { if (!WaylandServer::self()) { @@ -192,8 +225,78 @@ void AbstractEglBackend::initWayland() } } - Q_ASSERT(!m_dmaBuf); - m_dmaBuf = EglDmabuf::factory(this); + if (hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import")) && hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) { + eglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func)eglGetProcAddress("eglQueryDmaBufFormatsEXT"); + eglQueryDmaBufModifiersEXT = (eglQueryDmaBufModifiersEXT_func)eglGetProcAddress("eglQueryDmaBufModifiersEXT"); + + EGLint count = 0; + EGLBoolean success = eglQueryDmaBufFormatsEXT(m_display, 0, nullptr, &count); + + if (!success || count == 0) { + qCCritical(KWIN_OPENGL) << "eglQueryDmaBufFormatsEXT failed:" << getEglErrorString(); + return; + } + + QVector formats(count); + if (!eglQueryDmaBufFormatsEXT(m_display, count, (EGLint *)formats.data(), &count)) { + qCCritical(KWIN_OPENGL) << "eglQueryDmaBufFormatsEXT with count" << count << "failed:" << getEglErrorString(); + return; + } + + for (auto format : std::as_const(formats)) { + EGLint count = 0; + const EGLBoolean success = eglQueryDmaBufModifiersEXT(m_display, format, 0, nullptr, nullptr, &count); + if (success && count > 0) { + QVector modifiers(count); + QVector externalOnly(count); + if (eglQueryDmaBufModifiersEXT(m_display, format, count, modifiers.data(), externalOnly.data(), &count)) { + for (int i = modifiers.size() - 1; i >= 0; i--) { + if (externalOnly[i]) { + modifiers.remove(i); + externalOnly.remove(i); + } + } + if (!modifiers.empty()) { + m_supportedFormats.insert(format, modifiers); + } + continue; + } + } + m_supportedFormats.insert(format, {DRM_FORMAT_MOD_INVALID}); + } + qCDebug(KWIN_OPENGL) << "EGL driver advertises" << m_supportedFormats.count() << "supported dmabuf formats"; + + auto filterFormats = [this](int bpc) { + QHash> set; + for (auto it = m_supportedFormats.constBegin(); it != m_supportedFormats.constEnd(); it++) { + if (bpcForFormat(it.key()) == bpc) { + set.insert(it.key(), it.value()); + } + } + return set; + }; + if (prefer10bpc()) { + m_tranches.append({ + .device = deviceId(), + .flags = {}, + .formatTable = filterFormats(10), + }); + } + m_tranches.append({ + .device = deviceId(), + .flags = {}, + .formatTable = filterFormats(8), + }); + m_tranches.append({ + .device = deviceId(), + .flags = {}, + .formatTable = filterFormats(-1), + }); + + KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf(); + dmabuf->setRenderBackend(this); + dmabuf->setSupportedFormatsWithModifiers(m_tranches); + } } void AbstractEglBackend::initClientExtensions() @@ -367,6 +470,11 @@ void AbstractEglBackend::setSurface(const EGLSurface &surface) m_surface = surface; } +QVector AbstractEglBackend::tranches() const +{ + return m_tranches; +} + dev_t AbstractEglBackend::deviceId() const { return m_deviceId; @@ -377,9 +485,22 @@ bool AbstractEglBackend::prefer10bpc() const return false; } -EglDmabuf *AbstractEglBackend::dmabuf() const +EGLImageKHR AbstractEglBackend::importBufferAsImage(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) { - return m_dmaBuf; + auto it = m_importedBuffers.constFind(buffer); + if (Q_LIKELY(it != m_importedBuffers.constEnd())) { + return *it; + } + + EGLImageKHR image = importDmaBufAsImage(buffer->attributes()); + if (image != EGL_NO_IMAGE_KHR) { + m_importedBuffers[buffer] = image; + connect(buffer, &QObject::destroyed, this, [this, buffer]() { + eglDestroyImageKHR(m_display, m_importedBuffers.take(buffer)); + }); + } + + return image; } EGLImageKHR AbstractEglBackend::importDmaBufAsImage(const DmaBufAttributes &dmabuf) const @@ -455,13 +576,14 @@ std::shared_ptr AbstractEglBackend::importDmaBufAsTexture(const DmaBu } } +bool AbstractEglBackend::testImportBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) +{ + return importBufferAsImage(buffer) != EGL_NO_IMAGE_KHR; +} + QHash> AbstractEglBackend::supportedFormats() const { - if (m_dmaBuf) { - return m_dmaBuf->supportedFormats(); - } else { - return RenderBackend::supportedFormats(); - } + return m_supportedFormats; } bool AbstractEglBackend::initBufferConfigs() diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index e0673fdc39..e4bfdf3321 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -8,6 +8,7 @@ */ #pragma once #include "platformsupport/scenes/opengl/openglbackend.h" +#include "wayland/linuxdmabufv1clientbuffer.h" #include #include @@ -30,7 +31,6 @@ struct AbstractEglBackendFunctions }; struct DmaBufAttributes; -class EglDmabuf; class Output; class KWIN_EXPORT AbstractEglBackend : public OpenGLBackend @@ -62,14 +62,16 @@ public: return m_config; } + bool testImportBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) override; QHash> supportedFormats() const override; + QVector tranches() const; dev_t deviceId() const; virtual bool prefer10bpc() const; - EglDmabuf *dmabuf() const; std::shared_ptr importDmaBufAsTexture(const DmaBufAttributes &attributes) const; EGLImageKHR importDmaBufAsImage(const DmaBufAttributes &attributes) const; + EGLImageKHR importBufferAsImage(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer); protected: AbstractEglBackend(dev_t deviceId = 0); @@ -100,10 +102,11 @@ private: EGLSurface m_surface = EGL_NO_SURFACE; EGLContext m_context = EGL_NO_CONTEXT; EGLConfig m_config = nullptr; - // note: m_dmaBuf is nullptr if this is not the primary backend - EglDmabuf *m_dmaBuf = nullptr; QList m_clientExtensions; const dev_t m_deviceId; + QVector m_tranches; + QHash> m_supportedFormats; + QHash m_importedBuffers; static AbstractEglBackend *s_primaryBackend; }; diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp index bcf8c7d6c8..20fe33ad1f 100644 --- a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp @@ -7,7 +7,7 @@ #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" #include "kwineglext.h" #include "libkwineffects/kwingltexture.h" -#include "platformsupport/scenes/opengl/egl_dmabuf.h" +#include "platformsupport/scenes/opengl/abstract_egl_backend.h" #include "scene/surfaceitem_wayland.h" #include "utils/common.h" #include "wayland/drmclientbuffer.h" @@ -155,21 +155,21 @@ void BasicEGLSurfaceTextureWayland::updateEglTexture(KWaylandServer::DrmClientBu bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) { - auto dmabuf = static_cast(buffer); - if (Q_UNLIKELY(dmabuf->images().constFirst() == EGL_NO_IMAGE_KHR)) { + EGLImageKHR image = backend()->importBufferAsImage(buffer); + if (Q_UNLIKELY(image == EGL_NO_IMAGE_KHR)) { qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer"; return false; } m_texture.reset(new GLTexture(GL_TEXTURE_2D)); - m_texture->setSize(dmabuf->size()); + m_texture->setSize(buffer->size()); m_texture->create(); m_texture->setWrapMode(GL_CLAMP_TO_EDGE); m_texture->setFilter(GL_NEAREST); m_texture->bind(); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(dmabuf->images().constFirst())); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(image)); m_texture->unbind(); - m_texture->setContentTransform(dmabuf->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); + m_texture->setContentTransform(buffer->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); m_bufferType = BufferType::DmaBuf; return true; @@ -183,13 +183,12 @@ void BasicEGLSurfaceTextureWayland::updateDmabufTexture(KWaylandServer::LinuxDma return; } - auto dmabuf = static_cast(buffer); m_texture->bind(); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(dmabuf->images().constFirst())); + glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(backend()->importBufferAsImage(buffer))); m_texture->unbind(); // The origin in a dmabuf-buffer is at the upper-left corner, so the meaning // of Y-inverted is the inverse of OpenGL. - m_texture->setContentTransform(dmabuf->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); + m_texture->setContentTransform(buffer->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); } EGLImageKHR BasicEGLSurfaceTextureWayland::attach(KWaylandServer::DrmClientBuffer *buffer) diff --git a/src/platformsupport/scenes/opengl/egl_dmabuf.cpp b/src/platformsupport/scenes/opengl/egl_dmabuf.cpp deleted file mode 100644 index dd1e238497..0000000000 --- a/src/platformsupport/scenes/opengl/egl_dmabuf.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 Roman Gilg - SPDX-FileCopyrightText: 2018 Fredrik Höglund - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#include "platformsupport/scenes/opengl/egl_dmabuf.h" -#include "kwineglext.h" -#include "kwineglutils_p.h" - -#include "utils/common.h" -#include "wayland_server.h" - -#include -#include - -namespace KWin -{ - -typedef EGLBoolean (*eglQueryDmaBufFormatsEXT_func)(EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats); -typedef EGLBoolean (*eglQueryDmaBufModifiersEXT_func)(EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers); -eglQueryDmaBufFormatsEXT_func eglQueryDmaBufFormatsEXT = nullptr; -eglQueryDmaBufModifiersEXT_func eglQueryDmaBufModifiersEXT = nullptr; - -struct YuvPlane -{ - int widthDivisor; - int heightDivisor; - uint32_t format; - int planeIndex; -}; - -struct YuvFormat -{ - uint32_t format; - int inputPlanes; - int outputPlanes; - int textureType; - struct YuvPlane planes[3]; -}; - -YuvFormat yuvFormats[] = { - {DRM_FORMAT_YUYV, - 1, - 2, - EGL_TEXTURE_Y_XUXV_WL, - {{1, 1, - DRM_FORMAT_GR88, - 0}, - {2, 1, - DRM_FORMAT_ARGB8888, - 0}}}, - {DRM_FORMAT_NV12, - 2, - 2, - EGL_TEXTURE_Y_UV_WL, - {{1, 1, - DRM_FORMAT_R8, - 0}, - {2, 2, - DRM_FORMAT_GR88, - 1}}}, - {DRM_FORMAT_YUV420, - 3, - 3, - EGL_TEXTURE_Y_U_V_WL, - {{1, 1, - DRM_FORMAT_R8, - 0}, - {2, 2, - DRM_FORMAT_R8, - 1}, - {2, 2, - DRM_FORMAT_R8, - 2}}}, - {DRM_FORMAT_YUV444, - 3, - 3, - EGL_TEXTURE_Y_U_V_WL, - {{1, 1, - DRM_FORMAT_R8, - 0}, - {1, 1, - DRM_FORMAT_R8, - 1}, - {1, 1, - DRM_FORMAT_R8, - 2}}}}; - -EglDmabufBuffer::EglDmabufBuffer(EGLImage image, - DmaBufAttributes &&attrs, - quint32 flags, - EglDmabuf *interfaceImpl) - : EglDmabufBuffer(QVector{image}, std::move(attrs), flags, interfaceImpl) -{ - m_importType = ImportType::Direct; -} - -EglDmabufBuffer::EglDmabufBuffer(const QVector &images, - DmaBufAttributes &&attrs, - quint32 flags, - EglDmabuf *interfaceImpl) - : LinuxDmaBufV1ClientBuffer(std::move(attrs), flags) - , m_images(images) - , m_interfaceImpl(interfaceImpl) - , m_importType(ImportType::Conversion) -{ -} - -EglDmabufBuffer::~EglDmabufBuffer() -{ - removeImages(); -} - -void EglDmabufBuffer::setInterfaceImplementation(EglDmabuf *interfaceImpl) -{ - m_interfaceImpl = interfaceImpl; -} - -void EglDmabufBuffer::setImages(const QVector &images) -{ - m_images = images; -} - -void EglDmabufBuffer::removeImages() -{ - for (auto image : std::as_const(m_images)) { - eglDestroyImageKHR(m_interfaceImpl->m_backend->eglDisplay(), image); - } - m_images.clear(); -} - -KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::importBuffer(DmaBufAttributes &&attrs, quint32 flags) -{ - Q_ASSERT(attrs.planeCount > 0); - - // Try first to import as a single image - if (auto *img = m_backend->importDmaBufAsImage(attrs)) { - return new EglDmabufBuffer(img, std::move(attrs), flags, this); - } - - // TODO: to enable this we must be able to store multiple textures per window pixmap - // and when on window draw do yuv to rgb transformation per shader (see Weston) - // // not a single image, try yuv import - // return yuvImport(attrs, flags); - - return nullptr; -} - -KWaylandServer::LinuxDmaBufV1ClientBuffer *EglDmabuf::yuvImport(DmaBufAttributes &&attrs, quint32 flags) -{ - YuvFormat yuvFormat; - for (YuvFormat f : yuvFormats) { - if (f.format == attrs.format) { - yuvFormat = f; - break; - } - } - if (yuvFormat.format == 0) { - return nullptr; - } - if (attrs.planeCount != yuvFormat.inputPlanes) { - return nullptr; - } - - QVector images; - for (int i = 0; i < yuvFormat.outputPlanes; i++) { - const int planeIndex = yuvFormat.planes[i].planeIndex; - const DmaBufAttributes planeAttrs{ - .planeCount = 1, - .width = attrs.width / yuvFormat.planes[i].widthDivisor, - .height = attrs.height / yuvFormat.planes[i].heightDivisor, - .format = yuvFormat.planes[i].format, - .modifier = attrs.modifier, - .fd = {attrs.fd[planeIndex].duplicate()}, - .offset = {attrs.offset[planeIndex], 0, 0, 0}, - .pitch = {attrs.pitch[planeIndex], 0, 0, 0}, - }; - auto *image = m_backend->importDmaBufAsImage(planeAttrs); - if (!image) { - return nullptr; - } - images.push_back(image); - } - - return new EglDmabufBuffer(images, std::move(attrs), flags, this); -} - -EglDmabuf *EglDmabuf::factory(AbstractEglBackend *backend) -{ - if (!backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import"))) { - return nullptr; - } - - if (backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import_modifiers"))) { - eglQueryDmaBufFormatsEXT = (eglQueryDmaBufFormatsEXT_func)eglGetProcAddress("eglQueryDmaBufFormatsEXT"); - eglQueryDmaBufModifiersEXT = (eglQueryDmaBufModifiersEXT_func)eglGetProcAddress("eglQueryDmaBufModifiersEXT"); - } - - if (eglQueryDmaBufFormatsEXT == nullptr) { - return nullptr; - } - - return new EglDmabuf(backend); -} - -EglDmabuf::EglDmabuf(AbstractEglBackend *backend) - : m_backend(backend) -{ - auto prevBuffersSet = waylandServer()->linuxDmabufBuffers(); - for (auto *buffer : prevBuffersSet) { - auto *buf = static_cast(buffer); - buf->setInterfaceImplementation(this); - buf->setImages({m_backend->importDmaBufAsImage(buf->attributes())}); - } - setSupportedFormatsAndModifiers(); -} - -EglDmabuf::~EglDmabuf() -{ - auto curBuffers = waylandServer()->linuxDmabufBuffers(); - for (auto *buffer : curBuffers) { - auto *buf = static_cast(buffer); - buf->removeImages(); - } -} - -static int bpcForFormat(uint32_t format) -{ - switch (format) { - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_RGBX8888: - case DRM_FORMAT_BGRX8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_RGBA8888: - case DRM_FORMAT_BGRA8888: - case DRM_FORMAT_RGB888: - case DRM_FORMAT_BGR888: - return 8; - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_RGBX1010102: - case DRM_FORMAT_BGRX1010102: - case DRM_FORMAT_ARGB2101010: - case DRM_FORMAT_ABGR2101010: - case DRM_FORMAT_RGBA1010102: - case DRM_FORMAT_BGRA1010102: - return 10; - default: - return -1; - } -}; - -void EglDmabuf::setSupportedFormatsAndModifiers() -{ - const EGLDisplay eglDisplay = m_backend->eglDisplay(); - EGLint count = 0; - EGLBoolean success = eglQueryDmaBufFormatsEXT(eglDisplay, 0, nullptr, &count); - - if (!success || count == 0) { - qCCritical(KWIN_OPENGL) << "eglQueryDmaBufFormatsEXT failed!" << getEglErrorString(); - return; - } - - QVector formats(count); - if (!eglQueryDmaBufFormatsEXT(eglDisplay, count, (EGLint *)formats.data(), &count)) { - qCCritical(KWIN_OPENGL) << "eglQueryDmaBufFormatsEXT with count" << count << "failed!" << getEglErrorString(); - return; - } - - m_supportedFormats.clear(); - for (auto format : std::as_const(formats)) { - if (eglQueryDmaBufModifiersEXT != nullptr) { - EGLint count = 0; - const EGLBoolean success = eglQueryDmaBufModifiersEXT(eglDisplay, format, 0, nullptr, nullptr, &count); - if (success && count > 0) { - QVector modifiers(count); - QVector externalOnly(count); - if (eglQueryDmaBufModifiersEXT(eglDisplay, format, count, modifiers.data(), externalOnly.data(), &count)) { - for (int i = modifiers.size() - 1; i >= 0; i--) { - if (externalOnly[i]) { - modifiers.remove(i); - externalOnly.remove(i); - } - } - if (!modifiers.empty()) { - m_supportedFormats.insert(format, modifiers); - } - continue; - } - } - } - m_supportedFormats.insert(format, {DRM_FORMAT_MOD_INVALID}); - } - qCDebug(KWIN_OPENGL) << "EGL driver advertises" << m_supportedFormats.count() << "supported dmabuf formats" << (eglQueryDmaBufModifiersEXT != nullptr ? "with" : "without") << "modifiers"; - - auto filterFormats = [this](int bpc) { - QHash> set; - for (auto it = m_supportedFormats.constBegin(); it != m_supportedFormats.constEnd(); it++) { - if (bpcForFormat(it.key()) == bpc) { - set.insert(it.key(), it.value()); - } - } - return set; - }; - if (m_backend->prefer10bpc()) { - m_tranches.append({ - .device = m_backend->deviceId(), - .flags = {}, - .formatTable = filterFormats(10), - }); - } - m_tranches.append({ - .device = m_backend->deviceId(), - .flags = {}, - .formatTable = filterFormats(8), - }); - m_tranches.append({ - .device = m_backend->deviceId(), - .flags = {}, - .formatTable = filterFormats(-1), - }); - LinuxDmaBufV1RendererInterface::setSupportedFormatsAndModifiers(m_tranches); -} - -QVector EglDmabuf::tranches() const -{ - return m_tranches; -} - -QHash> EglDmabuf::supportedFormats() const -{ - return m_supportedFormats; -} -} diff --git a/src/platformsupport/scenes/opengl/egl_dmabuf.h b/src/platformsupport/scenes/opengl/egl_dmabuf.h deleted file mode 100644 index b6b4b89796..0000000000 --- a/src/platformsupport/scenes/opengl/egl_dmabuf.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - KWin - the KDE window manager - This file is part of the KDE project. - - SPDX-FileCopyrightText: 2019 Roman Gilg - SPDX-FileCopyrightText: 2018 Fredrik Höglund - - SPDX-License-Identifier: GPL-2.0-or-later -*/ -#pragma once - -#include "platformsupport/scenes/opengl/abstract_egl_backend.h" - -#include "linux_dmabuf.h" - -#include - -namespace KWin -{ -class EglDmabuf; - -class EglDmabufBuffer : public LinuxDmaBufV1ClientBuffer -{ -public: - enum class ImportType { - Direct, - Conversion - }; - - EglDmabufBuffer(EGLImage image, - DmaBufAttributes &&attrs, - quint32 flags, - EglDmabuf *interfaceImpl); - - EglDmabufBuffer(const QVector &images, - DmaBufAttributes &&attrs, - quint32 flags, - EglDmabuf *interfaceImpl); - - ~EglDmabufBuffer() override; - - void setInterfaceImplementation(EglDmabuf *interfaceImpl); - void setImages(const QVector &images); - void removeImages(); - - QVector images() const - { - return m_images; - } - -private: - QVector m_images; - EglDmabuf *m_interfaceImpl; - ImportType m_importType; -}; - -class KWIN_EXPORT EglDmabuf : public LinuxDmaBufV1RendererInterface -{ -public: - static EglDmabuf *factory(AbstractEglBackend *backend); - - explicit EglDmabuf(AbstractEglBackend *backend); - ~EglDmabuf() override; - - KWaylandServer::LinuxDmaBufV1ClientBuffer *importBuffer(DmaBufAttributes &&attrs, quint32 flags) override; - - QVector tranches() const; - QHash> supportedFormats() const; - -private: - KWaylandServer::LinuxDmaBufV1ClientBuffer *yuvImport(DmaBufAttributes &&attrs, quint32 flags); - - void setSupportedFormatsAndModifiers(); - - AbstractEglBackend *m_backend; - QVector m_tranches; - QHash> m_supportedFormats; - - friend class EglDmabufBuffer; -}; - -} diff --git a/src/wayland/linuxdmabufv1clientbuffer.cpp b/src/wayland/linuxdmabufv1clientbuffer.cpp index 086b6fba4d..29b0d918bc 100644 --- a/src/wayland/linuxdmabufv1clientbuffer.cpp +++ b/src/wayland/linuxdmabufv1clientbuffer.cpp @@ -11,6 +11,7 @@ */ #include "linuxdmabufv1clientbuffer.h" +#include "core/renderbackend.h" #include "linuxdmabufv1clientbuffer_p.h" #include "surface_interface_p.h" #include "utils/common.h" @@ -142,21 +143,26 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create(Resource *resource, return; } + KWin::RenderBackend *renderBackend = m_integration->renderBackend(); + if (Q_UNLIKELY(!renderBackend)) { + send_failed(resource->handle); + return; + } + m_isUsed = true; m_attrs.width = width; m_attrs.height = height; m_attrs.format = format; - LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(std::move(m_attrs), flags); - if (!clientBuffer) { + auto clientBuffer = std::make_unique(std::move(m_attrs), flags); + if (!renderBackend->testImportBuffer(clientBuffer.get())) { send_failed(resource->handle); return; } wl_resource *bufferResource = wl_resource_create(resource->client(), &wl_buffer_interface, 1, 0); if (!bufferResource) { - delete clientBuffer; wl_resource_post_no_memory(resource->handle); return; } @@ -165,7 +171,7 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create(Resource *resource, send_created(resource->handle, bufferResource); DisplayPrivate *displayPrivate = DisplayPrivate::get(m_integration->display()); - displayPrivate->registerClientBuffer(clientBuffer); + displayPrivate->registerClientBuffer(clientBuffer.release()); } void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *resource, @@ -184,21 +190,26 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *reso return; } + KWin::RenderBackend *renderBackend = m_integration->renderBackend(); + if (Q_UNLIKELY(!renderBackend)) { + wl_resource_post_error(resource->handle, error_invalid_wl_buffer, "importing the supplied dmabufs failed"); + return; + } + m_isUsed = true; m_attrs.width = width; m_attrs.height = height; m_attrs.format = format; - LinuxDmaBufV1ClientBuffer *clientBuffer = m_integration->rendererInterface()->importBuffer(std::move(m_attrs), flags); - if (!clientBuffer) { + auto clientBuffer = std::make_unique(std::move(m_attrs), flags); + if (!renderBackend->testImportBuffer(clientBuffer.get())) { wl_resource_post_error(resource->handle, error_invalid_wl_buffer, "importing the supplied dmabufs failed"); return; } wl_resource *bufferResource = wl_resource_create(resource->client(), &wl_buffer_interface, 1, buffer_id); if (!bufferResource) { - delete clientBuffer; wl_resource_post_no_memory(resource->handle); return; } @@ -206,7 +217,7 @@ void LinuxDmaBufParamsV1::zwp_linux_buffer_params_v1_create_immed(Resource *reso clientBuffer->initialize(bufferResource); DisplayPrivate *displayPrivate = DisplayPrivate::get(m_integration->display()); - displayPrivate->registerClientBuffer(clientBuffer); + displayPrivate->registerClientBuffer(clientBuffer.release()); } bool LinuxDmaBufParamsV1::test(Resource *resource, uint32_t width, uint32_t height) @@ -279,21 +290,21 @@ LinuxDmaBufV1ClientBufferIntegration::~LinuxDmaBufV1ClientBufferIntegration() { } -LinuxDmaBufV1ClientBufferIntegration::RendererInterface *LinuxDmaBufV1ClientBufferIntegration::rendererInterface() const -{ - return d->rendererInterface; -} - -void LinuxDmaBufV1ClientBufferIntegration::setRendererInterface(RendererInterface *rendererInterface) -{ - d->rendererInterface = rendererInterface; -} - bool operator==(const LinuxDmaBufV1Feedback::Tranche &t1, const LinuxDmaBufV1Feedback::Tranche &t2) { return t1.device == t2.device && t1.flags == t2.flags && t1.formatTable == t2.formatTable; } +KWin::RenderBackend *LinuxDmaBufV1ClientBufferIntegration::renderBackend() const +{ + return d->renderBackend; +} + +void LinuxDmaBufV1ClientBufferIntegration::setRenderBackend(KWin::RenderBackend *renderBackend) +{ + d->renderBackend = renderBackend; +} + void LinuxDmaBufV1ClientBufferIntegration::setSupportedFormatsWithModifiers(const QVector &tranches) { if (LinuxDmaBufV1FeedbackPrivate::get(d->defaultFeedback.get())->m_tranches != tranches) { diff --git a/src/wayland/linuxdmabufv1clientbuffer.h b/src/wayland/linuxdmabufv1clientbuffer.h index e4003f0208..11564f73eb 100644 --- a/src/wayland/linuxdmabufv1clientbuffer.h +++ b/src/wayland/linuxdmabufv1clientbuffer.h @@ -17,6 +17,11 @@ #include #include +namespace KWin +{ +class RenderBackend; +} + namespace KWaylandServer { class LinuxDmaBufV1ClientBufferPrivate; @@ -93,39 +98,8 @@ public: explicit LinuxDmaBufV1ClientBufferIntegration(Display *display); ~LinuxDmaBufV1ClientBufferIntegration() override; - /** - * The Iface class provides an interface from the LinuxDmabufInterface into the compositor - */ - class RendererInterface - { - public: - virtual ~RendererInterface() = default; - - /** - * Imports a linux-dmabuf buffer into the compositor. - * - * The parent LinuxDmabufUnstableV1Interface class takes ownership of returned - * buffer objects. - * - * In return the returned buffer takes ownership of the file descriptor for each - * plane. - * - * Note that it is the responsibility of the caller to close the file descriptors - * when the import fails. - * - * @return The imported buffer on success, and nullptr otherwise. - */ - virtual LinuxDmaBufV1ClientBuffer *importBuffer(KWin::DmaBufAttributes &&attrs, quint32 flags) = 0; - }; - - RendererInterface *rendererInterface() const; - - /** - * Sets the compositor implementation for the dmabuf interface. - * - * The ownership is not transferred by this call. - */ - void setRendererInterface(RendererInterface *rendererInterface); + KWin::RenderBackend *renderBackend() const; + void setRenderBackend(KWin::RenderBackend *renderBackend); void setSupportedFormatsWithModifiers(const QVector &tranches); diff --git a/src/wayland/linuxdmabufv1clientbuffer_p.h b/src/wayland/linuxdmabufv1clientbuffer_p.h index 3dab47e86c..ebc95fd38f 100644 --- a/src/wayland/linuxdmabufv1clientbuffer_p.h +++ b/src/wayland/linuxdmabufv1clientbuffer_p.h @@ -35,10 +35,10 @@ public: LinuxDmaBufV1ClientBufferIntegrationPrivate(LinuxDmaBufV1ClientBufferIntegration *q, Display *display); LinuxDmaBufV1ClientBufferIntegration *q; - LinuxDmaBufV1ClientBufferIntegration::RendererInterface *rendererInterface = nullptr; std::unique_ptr defaultFeedback; std::unique_ptr table; dev_t mainDevice; + QPointer renderBackend; QHash> supportedModifiers; protected: diff --git a/src/wayland_server.h b/src/wayland_server.h index 8c6ca66fe5..4a0f32132f 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -42,7 +42,6 @@ class OutputManagementV2Interface; class XdgForeignV2Interface; class XdgOutputManagerV1Interface; class LinuxDmaBufV1ClientBufferIntegration; -class LinuxDmaBufV1ClientBuffer; class TabletManagerV2Interface; class KeyboardShortcutsInhibitManagerV1Interface; class XdgDecorationManagerV1Interface; @@ -214,19 +213,6 @@ public: */ SocketPairConnection createConnection(); - QSet linuxDmabufBuffers() const - { - return m_linuxDmabufBuffers; - } - void addLinuxDmabufBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) - { - m_linuxDmabufBuffers << buffer; - } - void removeLinuxDmabufBuffer(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) - { - m_linuxDmabufBuffers.remove(buffer); - } - /** * Returns the first socket name that can be used to connect to this server. * For a full list, use display()->socketNames() @@ -284,7 +270,6 @@ private: KWaylandServer::XdgDecorationManagerV1Interface *m_xdgDecorationManagerV1 = nullptr; KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *m_linuxDmabuf = nullptr; KWaylandServer::KeyboardShortcutsInhibitManagerV1Interface *m_keyboardShortcutsInhibitManager = nullptr; - QSet m_linuxDmabufBuffers; QPointer m_xwaylandConnection; KWaylandServer::InputMethodV1Interface *m_inputMethod = nullptr; QPointer m_inputMethodServerConnection;