From b9ba12d02e055bc20f678b915b33c6ab10892df3 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 11 Apr 2023 18:08:47 +0300 Subject: [PATCH] wayland: Reimplement wl-drm As of nowadays, most clients have switched to the linux-dmabuf protocol, except Xwayland, which still needs the wl-drm protocol. On the other hand, we would like to unify some buffer handling code. There are a few options: - drop the support for wl-drm protocol. Not doable, because Xwayland still needs it, even though it uses the linux dmabuf feedback protocol too - re-implement the wl-drm protocol - re-implement the minimal part of the wl-drm protocol needed by Xwayland This change goes after the third option. Only the node name and the capabilities will be sent. The buffer factory requests are not implemented, but they can be if we discover that some clients need them. --- .../scenes/opengl/abstract_egl_backend.cpp | 36 ++-- .../scenes/opengl/abstract_egl_backend.h | 16 -- .../opengl/basiceglsurfacetexture_wayland.cpp | 90 +-------- .../opengl/basiceglsurfacetexture_wayland.h | 8 - .../scenes/opengl/egldisplay.cpp | 52 +++++ .../scenes/opengl/egldisplay.h | 2 + src/wayland/CMakeLists.txt | 5 +- src/wayland/display.cpp | 16 -- src/wayland/display.h | 15 -- src/wayland/display_p.h | 3 - src/wayland/drmclientbuffer.cpp | 146 +++++++++----- src/wayland/drmclientbuffer.h | 39 ++-- src/wayland/protocols/wayland-drm.xml | 189 ++++++++++++++++++ src/wayland_server.cpp | 9 + src/wayland_server.h | 3 + 15 files changed, 390 insertions(+), 239 deletions(-) create mode 100644 src/wayland/protocols/wayland-drm.xml diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp index 83b8d37752..c06cb83aa0 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -12,7 +12,7 @@ #include "options.h" #include "utils/common.h" #include "utils/egl_context_attribute_builder.h" -#include "wayland/display.h" +#include "wayland/drmclientbuffer.h" #include "wayland_server.h" // kwin libs #include "libkwineffects/kwineglimagetexture.h" @@ -25,6 +25,7 @@ #include #include +#include namespace KWin { @@ -79,9 +80,6 @@ void AbstractEglBackend::destroyGlobalShareContext() void AbstractEglBackend::teardown() { - if (m_functions.eglUnbindWaylandDisplayWL && m_display) { - m_functions.eglUnbindWaylandDisplayWL(m_display->handle(), *(WaylandServer::self()->display())); - } destroyGlobalShareContext(); } @@ -162,19 +160,29 @@ void AbstractEglBackend::initWayland() if (!WaylandServer::self()) { return; } - if (hasExtension(QByteArrayLiteral("EGL_WL_bind_wayland_display"))) { - m_functions.eglBindWaylandDisplayWL = (eglBindWaylandDisplayWL_func)eglGetProcAddress("eglBindWaylandDisplayWL"); - m_functions.eglUnbindWaylandDisplayWL = (eglUnbindWaylandDisplayWL_func)eglGetProcAddress("eglUnbindWaylandDisplayWL"); - m_functions.eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL"); - // only bind if not already done - if (waylandServer()->display()->eglDisplay() != eglDisplay()) { - if (!m_functions.eglBindWaylandDisplayWL(eglDisplay(), *(WaylandServer::self()->display()))) { - m_functions.eglUnbindWaylandDisplayWL = nullptr; - m_functions.eglQueryWaylandBufferWL = nullptr; + + if (m_deviceId) { + QString renderNode = m_display->renderNode(); + if (renderNode.isEmpty()) { + drmDevice *device = nullptr; + if (drmGetDeviceFromDevId(deviceId(), 0, &device) != 0) { + qCWarning(KWIN_OPENGL) << "drmGetDeviceFromDevId() failed:" << strerror(errno); } else { - waylandServer()->display()->setEglDisplay(eglDisplay()); + if (device->available_nodes & (1 << DRM_NODE_RENDER)) { + renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_RENDER]); + } else if (device->available_nodes & (1 << DRM_NODE_PRIMARY)) { + qCWarning(KWIN_OPENGL) << "No render nodes have been found, falling back to primary node"; + renderNode = QString::fromLocal8Bit(device->nodes[DRM_NODE_PRIMARY]); + } + drmFreeDevice(&device); } } + + if (!renderNode.isEmpty()) { + waylandServer()->drm()->setDevice(renderNode); + } else { + qCWarning(KWIN_OPENGL) << "No render node have been found, not initializing wl-drm"; + } } auto filterFormats = [this](int bpc) { diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h index 967135e282..a3fe8dbb57 100644 --- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -21,17 +21,6 @@ struct wl_resource; namespace KWin { -typedef GLboolean (*eglBindWaylandDisplayWL_func)(::EGLDisplay dpy, wl_display *display); -typedef GLboolean (*eglUnbindWaylandDisplayWL_func)(::EGLDisplay dpy, wl_display *display); -typedef GLboolean (*eglQueryWaylandBufferWL_func)(::EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); - -struct AbstractEglBackendFunctions -{ - eglBindWaylandDisplayWL_func eglBindWaylandDisplayWL = nullptr; - eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr; - eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr; -}; - struct DmaBufAttributes; class Output; @@ -43,10 +32,6 @@ public: bool makeCurrent() override; void doneCurrent() override; - const AbstractEglBackendFunctions *functions() const - { - return &m_functions; - } ::EGLDisplay eglDisplay() const; ::EGLContext context() const; EGLSurface surface() const; @@ -85,7 +70,6 @@ private: void teardown(); - AbstractEglBackendFunctions m_functions; EglDisplay *m_display = nullptr; EGLSurface m_surface = EGL_NO_SURFACE; std::unique_ptr m_context; diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp index f0e7c0ad48..4d725518b0 100644 --- a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.cpp @@ -9,19 +9,10 @@ #include "platformsupport/scenes/opengl/abstract_egl_backend.h" #include "scene/surfaceitem_wayland.h" #include "utils/common.h" -#include "wayland/drmclientbuffer.h" #include "wayland/linuxdmabufv1clientbuffer.h" #include "wayland/shmclientbuffer.h" -#ifndef EGL_WL_bind_wayland_display -#define EGL_WAYLAND_BUFFER_WL 0x31D5 -#define EGL_WAYLAND_PLANE_WL 0x31D6 -#define EGL_TEXTURE_Y_U_V_WL 0x31D7 -#define EGL_TEXTURE_Y_UV_WL 0x31D8 -#define EGL_TEXTURE_Y_XUXV_WL 0x31D9 -#define EGL_TEXTURE_EXTERNAL_WL 0x31DA -#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB -#endif // EGL_WL_bind_wayland_display +#include namespace KWin { @@ -48,8 +39,6 @@ bool BasicEGLSurfaceTextureWayland::create() return loadDmabufTexture(buffer); } else if (auto buffer = qobject_cast(m_pixmap->buffer())) { return loadShmTexture(buffer); - } else if (auto buffer = qobject_cast(m_pixmap->buffer())) { - return loadEglTexture(buffer); } else { return false; } @@ -57,10 +46,6 @@ bool BasicEGLSurfaceTextureWayland::create() void BasicEGLSurfaceTextureWayland::destroy() { - if (m_image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(backend()->eglDisplay(), m_image); - m_image = EGL_NO_IMAGE_KHR; - } m_texture.reset(); m_bufferType = BufferType::None; } @@ -71,8 +56,6 @@ void BasicEGLSurfaceTextureWayland::update(const QRegion ®ion) updateDmabufTexture(buffer); } else if (auto buffer = qobject_cast(m_pixmap->buffer())) { updateShmTexture(buffer, region); - } else if (auto buffer = qobject_cast(m_pixmap->buffer())) { - updateEglTexture(buffer); } } @@ -111,57 +94,6 @@ void BasicEGLSurfaceTextureWayland::updateShmTexture(KWaylandServer::ShmClientBu } } -bool BasicEGLSurfaceTextureWayland::loadEglTexture(KWaylandServer::DrmClientBuffer *buffer) -{ - const AbstractEglBackendFunctions *funcs = backend()->functions(); - if (Q_UNLIKELY(!funcs->eglQueryWaylandBufferWL)) { - return false; - } - if (Q_UNLIKELY(!buffer->resource())) { - return false; - } - - m_texture.reset(new GLTexture(GL_TEXTURE_2D)); - m_texture->setSize(buffer->size()); - m_texture->create(); - m_texture->setWrapMode(GL_CLAMP_TO_EDGE); - m_texture->setFilter(GL_LINEAR); - m_texture->bind(); - m_image = attach(buffer); - m_texture->unbind(); - m_bufferType = BufferType::Egl; - - if (EGL_NO_IMAGE_KHR == m_image) { - qCDebug(KWIN_OPENGL) << "failed to create egl image"; - m_texture.reset(); - return false; - } - - return true; -} - -void BasicEGLSurfaceTextureWayland::updateEglTexture(KWaylandServer::DrmClientBuffer *buffer) -{ - if (Q_UNLIKELY(m_bufferType != BufferType::Egl)) { - destroy(); - create(); - return; - } - if (Q_UNLIKELY(!buffer->resource())) { - return; - } - - m_texture->bind(); - EGLImageKHR image = attach(buffer); - m_texture->unbind(); - if (image != EGL_NO_IMAGE_KHR) { - if (m_image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(backend()->eglDisplay(), m_image); - } - m_image = image; - } -} - bool BasicEGLSurfaceTextureWayland::loadDmabufTexture(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer) { EGLImageKHR image = backend()->importBufferAsImage(buffer); @@ -200,24 +132,4 @@ void BasicEGLSurfaceTextureWayland::updateDmabufTexture(KWaylandServer::LinuxDma m_texture->setContentTransform(buffer->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); } -EGLImageKHR BasicEGLSurfaceTextureWayland::attach(KWaylandServer::DrmClientBuffer *buffer) -{ - if (buffer->textureFormat() != EGL_TEXTURE_RGB && buffer->textureFormat() != EGL_TEXTURE_RGBA) { - qCDebug(KWIN_OPENGL) << "Unsupported texture format: " << buffer->textureFormat(); - return EGL_NO_IMAGE_KHR; - } - - const EGLint attribs[] = { - EGL_WAYLAND_PLANE_WL, 0, - EGL_NONE}; - EGLImageKHR image = eglCreateImageKHR(backend()->eglDisplay(), EGL_NO_CONTEXT, - EGL_WAYLAND_BUFFER_WL, - static_cast(buffer->resource()), attribs); - if (image != EGL_NO_IMAGE_KHR) { - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast(image)); - m_texture->setContentTransform(buffer->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms()); - } - return image; -} - } // namespace KWin diff --git a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h index c02af3eb90..779b154916 100644 --- a/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h +++ b/src/platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h @@ -8,11 +8,8 @@ #include "openglsurfacetexture_wayland.h" -#include - namespace KWaylandServer { -class DrmClientBuffer; class ShmClientBuffer; class LinuxDmaBufV1ClientBuffer; } @@ -36,21 +33,16 @@ public: private: bool loadShmTexture(KWaylandServer::ShmClientBuffer *buffer); void updateShmTexture(KWaylandServer::ShmClientBuffer *buffer, const QRegion ®ion); - bool loadEglTexture(KWaylandServer::DrmClientBuffer *buffer); - void updateEglTexture(KWaylandServer::DrmClientBuffer *buffer); bool loadDmabufTexture(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer); void updateDmabufTexture(KWaylandServer::LinuxDmaBufV1ClientBuffer *buffer); - EGLImageKHR attach(KWaylandServer::DrmClientBuffer *buffer); void destroy(); enum class BufferType { None, Shm, DmaBuf, - Egl, }; - EGLImageKHR m_image = EGL_NO_IMAGE_KHR; BufferType m_bufferType = BufferType::None; }; diff --git a/src/platformsupport/scenes/opengl/egldisplay.cpp b/src/platformsupport/scenes/opengl/egldisplay.cpp index 50c8264462..ff58687db6 100644 --- a/src/platformsupport/scenes/opengl/egldisplay.cpp +++ b/src/platformsupport/scenes/opengl/egldisplay.cpp @@ -16,6 +16,10 @@ #include #include +#ifndef EGL_DRM_RENDER_NODE_FILE_EXT +#define EGL_DRM_RENDER_NODE_FILE_EXT 0x3377 +#endif + namespace KWin { @@ -102,6 +106,54 @@ bool EglDisplay::hasExtension(const QByteArray &name) const return m_extensions.contains(name); } +static bool checkExtension(const QByteArrayView extensions, const QByteArrayView extension) +{ + for (int i = 0; i < extensions.size();) { + if (extensions[i] == ' ') { + i++; + continue; + } + int next = extensions.indexOf(' ', i); + if (next == -1) { + next = extensions.size(); + } + + const int size = next - i; + if (extension.size() == size && extensions.sliced(i, size) == extension) { + return true; + } + + i = next; + } + + return false; +} + +QString EglDisplay::renderNode() const +{ + const char *clientExtensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS); + if (checkExtension(clientExtensions, "EGL_EXT_device_query")) { + EGLAttrib eglDeviceAttrib; + if (eglQueryDisplayAttribEXT(m_handle, EGL_DEVICE_EXT, &eglDeviceAttrib)) { + EGLDeviceEXT eglDevice = reinterpret_cast(eglDeviceAttrib); + + const char *deviceExtensions = eglQueryDeviceStringEXT(eglDevice, EGL_EXTENSIONS); + if (checkExtension(deviceExtensions, "EGL_EXT_device_drm_render_node")) { + if (const char *node = eglQueryDeviceStringEXT(eglDevice, EGL_DRM_RENDER_NODE_FILE_EXT)) { + return QString::fromLocal8Bit(node); + } + } + if (checkExtension(deviceExtensions, "EGL_EXT_device_drm")) { + // Fallback to display device. + if (const char *node = eglQueryDeviceStringEXT(eglDevice, EGL_DRM_DEVICE_FILE_EXT)) { + return QString::fromLocal8Bit(node); + } + } + } + } + return QString(); +} + bool EglDisplay::supportsBufferAge() const { return m_supportsBufferAge; diff --git a/src/platformsupport/scenes/opengl/egldisplay.h b/src/platformsupport/scenes/opengl/egldisplay.h index 183a6a3324..a1e3d8a677 100644 --- a/src/platformsupport/scenes/opengl/egldisplay.h +++ b/src/platformsupport/scenes/opengl/egldisplay.h @@ -31,6 +31,8 @@ public: ::EGLDisplay handle() const; bool hasExtension(const QByteArray &name) const; + QString renderNode() const; + bool supportsBufferAge() const; bool supportsSwapBuffersWithDamage() const; bool supportsNativeFence() const; diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index de786fa3a6..d466149f7c 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -200,11 +200,14 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/kde-output-order-v1.xml BASENAME kde-output-order-v1 ) - ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${WaylandProtocols_DATADIR}/staging/fractional-scale/fractional-scale-v1.xml BASENAME fractional-scale-v1 ) +ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml + PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/wayland-drm.xml + BASENAME drm +) target_sources(kwin PRIVATE abstract_data_source.cpp diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index 9f8a559fef..f383315024 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -7,7 +7,6 @@ #include "display.h" #include "clientbufferintegration.h" #include "display_p.h" -#include "drmclientbuffer.h" #include "output_interface.h" #include "shmclientbuffer.h" #include "utils/common.h" @@ -217,21 +216,6 @@ ClientConnection *Display::createClient(int fd) return getConnection(c); } -void Display::setEglDisplay(void *display) -{ - if (d->eglDisplay != EGL_NO_DISPLAY) { - qCWarning(KWIN_CORE) << "EGLDisplay cannot be changed"; - return; - } - d->eglDisplay = (::EGLDisplay)display; - new DrmClientBufferIntegration(this); -} - -void *Display::eglDisplay() const -{ - return d->eglDisplay; -} - struct ClientBufferDestroyListener : wl_listener { ClientBufferDestroyListener(Display *display, ClientBuffer *buffer); diff --git a/src/wayland/display.h b/src/wayland/display.h index 5e26b7b039..7a3f9a341e 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -125,21 +125,6 @@ public: ClientConnection *getConnection(wl_client *client); QVector connections() const; - /** - * Set the EGL @p display for this Wayland display. - * The EGLDisplay can only be set once and must be alive as long as the Wayland display - * is alive. The user should have set up the binding between the EGLDisplay and the - * Wayland display prior to calling this method. - * - * @see eglDisplay - */ - void setEglDisplay(void *display); - /** - * @returns the EGLDisplay used for this Wayland display or EGL_NO_DISPLAY if not set. - * @see setEglDisplay - */ - void *eglDisplay() const; - /** * Returns the client buffer with the specified @a resource. Returns @c null if there's * no such a buffer. diff --git a/src/wayland/display_p.h b/src/wayland/display_p.h index a28d77229f..efdf9ab631 100644 --- a/src/wayland/display_p.h +++ b/src/wayland/display_p.h @@ -15,8 +15,6 @@ #include #include -#include - struct wl_resource; namespace KWaylandServer @@ -51,7 +49,6 @@ public: QVector seats; QVector clients; QStringList socketNames; - ::EGLDisplay eglDisplay = EGL_NO_DISPLAY; QHash<::wl_resource *, ClientBuffer *> resourceToBuffer; QHash bufferToListener; QList bufferIntegrations; diff --git a/src/wayland/drmclientbuffer.cpp b/src/wayland/drmclientbuffer.cpp index 24ef8ccd23..f7d67a3ff2 100644 --- a/src/wayland/drmclientbuffer.cpp +++ b/src/wayland/drmclientbuffer.cpp @@ -5,90 +5,132 @@ */ #include "drmclientbuffer.h" -#include "clientbuffer_p.h" #include "display.h" +#include "utils/common.h" -#include -#include - -#ifndef EGL_WL_bind_wayland_display -#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB -#endif +#include "qwayland-server-drm.h" namespace KWaylandServer { -typedef EGLBoolean (*eglQueryWaylandBufferWL_func)(::EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); -static eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr; -class DrmClientBufferPrivate : public ClientBufferPrivate +static constexpr int s_version = 2; + +class DrmClientBufferIntegrationPrivate : public QtWaylandServer::wl_drm { public: - int textureFormat = 0; - int width = 0; - int height = 0; - int yInverted = 0; - bool hasAlphaChannel = false; + explicit DrmClientBufferIntegrationPrivate(Display *display); + + QString nodeName; + +protected: + void drm_bind_resource(Resource *resource) override; + void drm_authenticate(Resource *resource, uint32_t id) override; + void drm_create_buffer(Resource *resource, + uint32_t id, + uint32_t name, + int32_t width, + int32_t height, + uint32_t stride, + uint32_t format) override; + void drm_create_planar_buffer(Resource *resource, + uint32_t id, + uint32_t name, + int32_t width, + int32_t height, + uint32_t format, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) override; + void drm_create_prime_buffer(Resource *resource, + uint32_t id, + int32_t name, + int32_t width, + int32_t height, + uint32_t format, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) override; }; -DrmClientBuffer::DrmClientBuffer(wl_resource *resource, DrmClientBufferIntegration *integration) - : ClientBuffer(resource, *new DrmClientBufferPrivate) +DrmClientBufferIntegrationPrivate::DrmClientBufferIntegrationPrivate(Display *display) + : QtWaylandServer::wl_drm(*display, s_version) { - Q_D(DrmClientBuffer); - - ::EGLDisplay eglDisplay = integration->display()->eglDisplay(); - eglQueryWaylandBufferWL(eglDisplay, resource, EGL_TEXTURE_FORMAT, &d->textureFormat); - eglQueryWaylandBufferWL(eglDisplay, resource, EGL_WIDTH, &d->width); - eglQueryWaylandBufferWL(eglDisplay, resource, EGL_HEIGHT, &d->height); - - if (!eglQueryWaylandBufferWL(eglDisplay, resource, EGL_WAYLAND_Y_INVERTED_WL, &d->yInverted)) { - // If EGL_WAYLAND_Y_INVERTED_WL is unsupported, we must assume that the buffer is inverted. - d->yInverted = true; - } } -int DrmClientBuffer::textureFormat() const +void DrmClientBufferIntegrationPrivate::drm_bind_resource(Resource *resource) { - Q_D(const DrmClientBuffer); - return d->textureFormat; + send_device(resource->handle, nodeName); + send_capabilities(resource->handle, capability_prime); } -QSize DrmClientBuffer::size() const +void DrmClientBufferIntegrationPrivate::drm_authenticate(Resource *resource, uint32_t id) { - Q_D(const DrmClientBuffer); - return QSize(d->width, d->height); + send_authenticated(resource->handle); } -bool DrmClientBuffer::hasAlphaChannel() const +void DrmClientBufferIntegrationPrivate::drm_create_buffer(Resource *resource, + uint32_t id, + uint32_t name, + int32_t width, + int32_t height, + uint32_t stride, + uint32_t format) { - Q_D(const DrmClientBuffer); - return d->textureFormat == EGL_TEXTURE_RGBA; + wl_resource_post_error(resource->handle, 0, "wl_drm.create_buffer is not implemented"); } -ClientBuffer::Origin DrmClientBuffer::origin() const +void DrmClientBufferIntegrationPrivate::drm_create_planar_buffer(Resource *resource, + uint32_t id, + uint32_t name, + int32_t width, + int32_t height, + uint32_t format, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) { - Q_D(const DrmClientBuffer); - return d->yInverted ? Origin::TopLeft : Origin::BottomLeft; + wl_resource_post_error(resource->handle, 0, "wl_drm.create_planar_buffer is not implemented"); +} + +void DrmClientBufferIntegrationPrivate::drm_create_prime_buffer(Resource *resource, + uint32_t id, + int32_t name, + int32_t width, + int32_t height, + uint32_t format, + int32_t offset0, + int32_t stride0, + int32_t offset1, + int32_t stride1, + int32_t offset2, + int32_t stride2) +{ + close(name); + wl_resource_post_error(resource->handle, 0, "wl_drm.create_prime_buffer is not implemented"); } DrmClientBufferIntegration::DrmClientBufferIntegration(Display *display) : ClientBufferIntegration(display) + , d(std::make_unique(display)) { } -ClientBuffer *DrmClientBufferIntegration::createBuffer(::wl_resource *resource) +DrmClientBufferIntegration::~DrmClientBufferIntegration() { - ::EGLDisplay eglDisplay = display()->eglDisplay(); - static bool resolved = false; - if (!resolved && eglDisplay != EGL_NO_DISPLAY) { - eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL"); - resolved = true; - } +} - EGLint format; - if (eglQueryWaylandBufferWL(eglDisplay, resource, EGL_TEXTURE_FORMAT, &format)) { - return new DrmClientBuffer(resource, this); - } - return nullptr; +void DrmClientBufferIntegration::setDevice(const QString &node) +{ + d->nodeName = node; } } // namespace KWaylandServer diff --git a/src/wayland/drmclientbuffer.h b/src/wayland/drmclientbuffer.h index 31eb3c2fa0..8fd877f203 100644 --- a/src/wayland/drmclientbuffer.h +++ b/src/wayland/drmclientbuffer.h @@ -6,15 +6,22 @@ #pragma once -#include "clientbuffer.h" #include "clientbufferintegration.h" namespace KWaylandServer { -class DrmClientBufferPrivate; +class DrmClientBufferIntegrationPrivate; /** - * The DrmClientBufferIntegration class provides support for wl_drm client buffers. + * The DrmClientBufferIntegration provides a stub implementation for the wl_drm + * protocol. + * + * It provides the minimum amount of information to Xwayland so it can run. No + * ClientBuffers are provided by the DrmClientBufferIntegration. Xwayland is + * expected to provide us linux dmabuf client buffers instead. + * + * Once the wl_drm protocol is no longer mandatory in Xwayland, this stub can be + * dropped. */ class KWIN_EXPORT DrmClientBufferIntegration : public ClientBufferIntegration { @@ -22,30 +29,12 @@ class KWIN_EXPORT DrmClientBufferIntegration : public ClientBufferIntegration public: explicit DrmClientBufferIntegration(Display *display); + ~DrmClientBufferIntegration() override; - ClientBuffer *createBuffer(::wl_resource *resource) override; -}; + void setDevice(const QString &node); -/** - * The DrmClientBuffer class represents a wl_drm client buffer. - * - * Nowadays, the wl_drm protocol is de-facto deprecated with the introduction of the - * linux-dmabuf-v1 protocol. Note that Vulkan WSI in Mesa still prefers wl_drm, but - * that's about to change, https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4942/ - */ -class KWIN_EXPORT DrmClientBuffer : public ClientBuffer -{ - Q_OBJECT - Q_DECLARE_PRIVATE(DrmClientBuffer) - -public: - explicit DrmClientBuffer(wl_resource *resource, DrmClientBufferIntegration *integration); - - int textureFormat() const; - - QSize size() const override; - bool hasAlphaChannel() const override; - Origin origin() const override; +private: + std::unique_ptr d; }; } // namespace KWaylandServer diff --git a/src/wayland/protocols/wayland-drm.xml b/src/wayland/protocols/wayland-drm.xml new file mode 100644 index 0000000000..eaf2654ab2 --- /dev/null +++ b/src/wayland/protocols/wayland-drm.xml @@ -0,0 +1,189 @@ + + + + + Copyright © 2008-2011 Kristian Høgsberg + Copyright © 2010-2011 Intel Corporation + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that\n the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Bitmask of capabilities. + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index 01a441ad62..5f2cbfdb9f 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -26,6 +26,7 @@ #include "wayland/datadevicemanager_interface.h" #include "wayland/display.h" #include "wayland/dpms_interface.h" +#include "wayland/drmclientbuffer.h" #include "wayland/drmlease_v1_interface.h" #include "wayland/filtered_display.h" #include "wayland/fractionalscale_v1_interface.h" @@ -512,6 +513,14 @@ bool WaylandServer::init(InitializationFlags flags) return true; } +KWaylandServer::DrmClientBufferIntegration *WaylandServer::drm() +{ + if (!m_drm) { + m_drm = new DrmClientBufferIntegration(m_display); + } + return m_drm; +} + KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *WaylandServer::linuxDmabuf() { if (!m_linuxDmabuf) { diff --git a/src/wayland_server.h b/src/wayland_server.h index f7bb1ace20..1cda45bec5 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -37,6 +37,7 @@ class OutputDeviceV2Interface; class OutputManagementV2Interface; class XdgForeignV2Interface; class XdgOutputManagerV1Interface; +class DrmClientBufferIntegration; class LinuxDmaBufV1ClientBufferIntegration; class TabletManagerV2Interface; class KeyboardShortcutsInhibitManagerV1Interface; @@ -130,6 +131,7 @@ public: bool isKeyboardShortcutsInhibited() const; + KWaylandServer::DrmClientBufferIntegration *drm(); KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *linuxDmabuf(); KWaylandServer::InputMethodV1Interface *inputMethod() const @@ -264,6 +266,7 @@ private: KWaylandServer::IdleInterface *m_idle = nullptr; KWaylandServer::XdgOutputManagerV1Interface *m_xdgOutputManagerV1 = nullptr; KWaylandServer::XdgDecorationManagerV1Interface *m_xdgDecorationManagerV1 = nullptr; + KWaylandServer::DrmClientBufferIntegration *m_drm = nullptr; KWaylandServer::LinuxDmaBufV1ClientBufferIntegration *m_linuxDmabuf = nullptr; KWaylandServer::KeyboardShortcutsInhibitManagerV1Interface *m_keyboardShortcutsInhibitManager = nullptr; QPointer m_xwaylandConnection;