diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -441,6 +441,7 @@ libinput/device.cpp libinput/events.cpp libinput/libinput_logging.cpp + linux_dmabuf.cpp logind.cpp main.cpp manage.cpp diff --git a/platformsupport/scenes/opengl/linux_dmabuf.h b/linux_dmabuf.h rename from platformsupport/scenes/opengl/linux_dmabuf.h rename to linux_dmabuf.h --- a/platformsupport/scenes/opengl/linux_dmabuf.h +++ b/linux_dmabuf.h @@ -3,7 +3,6 @@ This file is part of the KDE project. Copyright © 2019 Roman Gilg -Copyright © 2018 Fredrik Höglund This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -20,92 +19,56 @@ *********************************************************************/ #pragma once -#include "abstract_egl_backend.h" +#include #include #include namespace KWin { -class LinuxDmabuf; -class DmabufBuffer : public KWayland::Server::LinuxDmabufUnstableV1Buffer +class KWIN_EXPORT DmabufBuffer : public KWayland::Server::LinuxDmabufUnstableV1Buffer { public: using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; - enum class ImportType { - Direct, - Conversion - }; - - DmabufBuffer(EGLImage image, - const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl); - DmabufBuffer(const QVector &planes, uint32_t format, const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl); + Flags flags); ~DmabufBuffer() override; - void addImage(EGLImage image); - void removeImages(); - - QVector images() const { return m_images; } - Flags flags() const { return m_flags; } const QVector &planes() const { return m_planes; } + uint32_t format() const { return m_format; } + QSize size() const { return m_size; } + Flags flags() const { return m_flags; } private: - QVector m_images; QVector m_planes; + uint32_t m_format; + QSize m_size; Flags m_flags; - LinuxDmabuf *m_interfaceImpl; - ImportType m_importType; }; -class LinuxDmabuf : public KWayland::Server::LinuxDmabufUnstableV1Interface::Impl +class KWIN_EXPORT LinuxDmabuf : public KWayland::Server::LinuxDmabufUnstableV1Interface::Impl { public: using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; - static LinuxDmabuf* factory(AbstractEglBackend *backend); - - explicit LinuxDmabuf(AbstractEglBackend *backend); + explicit LinuxDmabuf(); ~LinuxDmabuf(); KWayland::Server::LinuxDmabufUnstableV1Buffer *importBuffer(const QVector &planes, uint32_t format, const QSize &size, Flags flags) override; -private: - EGLImage createImage(const QVector &planes, - uint32_t format, - const QSize &size); - - - KWayland::Server::LinuxDmabufUnstableV1Buffer *yuvImport(const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags); - - void removeBuffer(DmabufBuffer *buffer); - void setSupportedFormatsAndModifiers(); - - KWayland::Server::LinuxDmabufUnstableV1Interface *m_interface; - QSet m_buffers; - AbstractEglBackend *m_backend; - - friend class DmabufBuffer; +protected: + void setSupportedFormatsAndModifiers(QHash > &set); }; } diff --git a/linux_dmabuf.cpp b/linux_dmabuf.cpp new file mode 100644 --- /dev/null +++ b/linux_dmabuf.cpp @@ -0,0 +1,88 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright © 2019 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "linux_dmabuf.h" + +#include "wayland_server.h" + +#include + +namespace KWin +{ + +DmabufBuffer::DmabufBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags) + : KWayland::Server::LinuxDmabufUnstableV1Buffer(format, size) + , m_planes(planes) + , m_format(format) + , m_size(size) + , m_flags(flags) +{ + waylandServer()->addLinuxDmabufBuffer(this); +} + +DmabufBuffer::~DmabufBuffer() +{ + // Close all open file descriptors + for (int i = 0; i < m_planes.count(); i++) { + if (m_planes[i].fd != -1) + ::close(m_planes[i].fd); + m_planes[i].fd = -1; + } + if (waylandServer()) { + waylandServer()->removeLinuxDmabufBuffer(this); + } +} + +LinuxDmabuf::LinuxDmabuf() + : KWayland::Server::LinuxDmabufUnstableV1Interface::Impl() +{ + Q_ASSERT(waylandServer()); + waylandServer()->linuxDmabuf()->setImpl(this); +} + +LinuxDmabuf::~LinuxDmabuf() +{ + waylandServer()->linuxDmabuf()->setImpl(nullptr); +} + +using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; +using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; + +KWayland::Server::LinuxDmabufUnstableV1Buffer* LinuxDmabuf::importBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags) +{ + Q_UNUSED(planes) + Q_UNUSED(format) + Q_UNUSED(size) + Q_UNUSED(flags) + + return nullptr; +} + +void LinuxDmabuf::setSupportedFormatsAndModifiers(QHash > &set) +{ + waylandServer()->linuxDmabuf()->setSupportedFormatsWithModifiers(set); +} + +} diff --git a/platformsupport/scenes/opengl/CMakeLists.txt b/platformsupport/scenes/opengl/CMakeLists.txt --- a/platformsupport/scenes/opengl/CMakeLists.txt +++ b/platformsupport/scenes/opengl/CMakeLists.txt @@ -1,7 +1,7 @@ set(SCENE_OPENGL_BACKEND_SRCS abstract_egl_backend.cpp backend.cpp - linux_dmabuf.cpp + egl_dmabuf.cpp swap_profiler.cpp texture.cpp ) diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp --- a/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -18,7 +18,7 @@ along with this program. If not, see . *********************************************************************/ #include "abstract_egl_backend.h" -#include "linux_dmabuf.h" +#include "egl_dmabuf.h" #include "texture.h" #include "composite.h" #include "egl_context_attribute_builder.h" @@ -171,7 +171,7 @@ } } - LinuxDmabuf::factory(this); + EglDmabuf::factory(this); } void AbstractEglBackend::initClientExtensions() @@ -377,7 +377,7 @@ return; } auto s = pixmap->surface(); - if (DmabufBuffer *dmabuf = static_cast(buffer->linuxDmabufBuffer())) { + if (EglDmabufBuffer *dmabuf = static_cast(buffer->linuxDmabufBuffer())) { q->bind(); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) dmabuf->images()[0]); //TODO q->unbind(); @@ -532,7 +532,7 @@ bool AbstractEglTexture::loadDmabufTexture(const QPointer< KWayland::Server::BufferInterface > &buffer) { - DmabufBuffer *dmabuf = static_cast(buffer->linuxDmabufBuffer()); + auto *dmabuf = static_cast(buffer->linuxDmabufBuffer()); if (!dmabuf || dmabuf->images()[0] == EGL_NO_IMAGE_KHR) { qCritical(KWIN_OPENGL) << "Invalid dmabuf-based wl_buffer"; q->discard(); diff --git a/platformsupport/scenes/opengl/linux_dmabuf.h b/platformsupport/scenes/opengl/egl_dmabuf.h rename from platformsupport/scenes/opengl/linux_dmabuf.h rename to platformsupport/scenes/opengl/egl_dmabuf.h --- a/platformsupport/scenes/opengl/linux_dmabuf.h +++ b/platformsupport/scenes/opengl/egl_dmabuf.h @@ -20,17 +20,17 @@ *********************************************************************/ #pragma once -#include "abstract_egl_backend.h" +#include "../../../linux_dmabuf.h" -#include +#include "abstract_egl_backend.h" #include namespace KWin { -class LinuxDmabuf; +class EglDmabuf; -class DmabufBuffer : public KWayland::Server::LinuxDmabufUnstableV1Buffer +class EglDmabufBuffer : public DmabufBuffer { public: using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; @@ -41,46 +41,43 @@ Conversion }; - DmabufBuffer(EGLImage image, - const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl); + EglDmabufBuffer(EGLImage image, + const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags, + EglDmabuf *interfaceImpl); - DmabufBuffer(const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl); + EglDmabufBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags, + EglDmabuf *interfaceImpl); - ~DmabufBuffer() override; + ~EglDmabufBuffer() override; + void setInterfaceImplementation(EglDmabuf *interfaceImpl); void addImage(EGLImage image); void removeImages(); QVector images() const { return m_images; } - Flags flags() const { return m_flags; } - const QVector &planes() const { return m_planes; } private: QVector m_images; - QVector m_planes; - Flags m_flags; - LinuxDmabuf *m_interfaceImpl; + EglDmabuf *m_interfaceImpl; ImportType m_importType; }; -class LinuxDmabuf : public KWayland::Server::LinuxDmabufUnstableV1Interface::Impl +class EglDmabuf : public LinuxDmabuf { public: using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; - static LinuxDmabuf* factory(AbstractEglBackend *backend); + static EglDmabuf* factory(AbstractEglBackend *backend); - explicit LinuxDmabuf(AbstractEglBackend *backend); - ~LinuxDmabuf(); + explicit EglDmabuf(AbstractEglBackend *backend); + ~EglDmabuf(); KWayland::Server::LinuxDmabufUnstableV1Buffer *importBuffer(const QVector &planes, uint32_t format, @@ -92,20 +89,16 @@ uint32_t format, const QSize &size); - KWayland::Server::LinuxDmabufUnstableV1Buffer *yuvImport(const QVector &planes, uint32_t format, const QSize &size, Flags flags); - void removeBuffer(DmabufBuffer *buffer); void setSupportedFormatsAndModifiers(); - KWayland::Server::LinuxDmabufUnstableV1Interface *m_interface; - QSet m_buffers; AbstractEglBackend *m_backend; - friend class DmabufBuffer; + friend class EglDmabufBuffer; }; } diff --git a/platformsupport/scenes/opengl/linux_dmabuf.cpp b/platformsupport/scenes/opengl/egl_dmabuf.cpp rename from platformsupport/scenes/opengl/linux_dmabuf.cpp rename to platformsupport/scenes/opengl/egl_dmabuf.cpp --- a/platformsupport/scenes/opengl/linux_dmabuf.cpp +++ b/platformsupport/scenes/opengl/egl_dmabuf.cpp @@ -18,13 +18,11 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ -#include "linux_dmabuf.h" +#include "egl_dmabuf.h" #include "drm_fourcc.h" #include "../../../wayland_server.h" -#include - #include #include @@ -173,67 +171,59 @@ } }; -DmabufBuffer::DmabufBuffer(EGLImage image, - const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl) - : DmabufBuffer(planes, format, size, flags, interfaceImpl) +EglDmabufBuffer::EglDmabufBuffer(EGLImage image, + const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags, + EglDmabuf *interfaceImpl) + : EglDmabufBuffer(planes, format, size, flags, interfaceImpl) { m_importType = ImportType::Direct; addImage(image); } -DmabufBuffer::DmabufBuffer(const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags, - LinuxDmabuf *interfaceImpl) - : KWayland::Server::LinuxDmabufUnstableV1Buffer(format, size) - , m_planes(planes) - , m_flags(flags) +EglDmabufBuffer::EglDmabufBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags, + EglDmabuf *interfaceImpl) + : DmabufBuffer(planes, format, size, flags) , m_interfaceImpl(interfaceImpl) { m_importType = ImportType::Conversion; } -DmabufBuffer::~DmabufBuffer() +EglDmabufBuffer::~EglDmabufBuffer() { - if (m_interfaceImpl) { - m_interfaceImpl->removeBuffer(this); - removeImages(); - } + removeImages(); +} - // Close all open file descriptors - for (int i = 0; i < m_planes.count(); i++) { - if (m_planes[i].fd != -1) - ::close(m_planes[i].fd); - m_planes[i].fd = -1; - } +void EglDmabufBuffer::setInterfaceImplementation(EglDmabuf *interfaceImpl) +{ + m_interfaceImpl = interfaceImpl; } -void DmabufBuffer::addImage(EGLImage image) +void EglDmabufBuffer::addImage(EGLImage image) { m_images << image; } -void DmabufBuffer::removeImages() +void EglDmabufBuffer::removeImages() { for (auto image : m_images) { eglDestroyImageKHR(m_interfaceImpl->m_backend->eglDisplay(), image); } m_images.clear(); - m_interfaceImpl = nullptr; } using Plane = KWayland::Server::LinuxDmabufUnstableV1Interface::Plane; using Flags = KWayland::Server::LinuxDmabufUnstableV1Interface::Flags; -EGLImage LinuxDmabuf::createImage(const QVector &planes, - uint32_t format, - const QSize &size) +EGLImage EglDmabuf::createImage(const QVector &planes, + uint32_t format, + const QSize &size) { const bool hasModifiers = eglQueryDmaBufModifiersEXT != nullptr && planes[0].modifier != DRM_FORMAT_MOD_INVALID; @@ -306,16 +296,16 @@ return image; } -KWayland::Server::LinuxDmabufUnstableV1Buffer* LinuxDmabuf::importBuffer(const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags) +KWayland::Server::LinuxDmabufUnstableV1Buffer* EglDmabuf::importBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags) { Q_ASSERT(planes.count() > 0); // Try first to import as a single image if (auto *img = createImage(planes, format, size)) { - return new DmabufBuffer(img, planes, format, size, flags, this); + return new EglDmabufBuffer(img, planes, format, size, flags, this); } // TODO: to enable this we must be able to store multiple textures per window pixmap @@ -326,10 +316,10 @@ return nullptr; } -KWayland::Server::LinuxDmabufUnstableV1Buffer* LinuxDmabuf::yuvImport(const QVector &planes, - uint32_t format, - const QSize &size, - Flags flags) +KWayland::Server::LinuxDmabufUnstableV1Buffer* EglDmabuf::yuvImport(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags) { YuvFormat yuvFormat; for (YuvFormat f : yuvFormats) { @@ -345,7 +335,7 @@ return nullptr; } - auto *buf = new DmabufBuffer(planes, format, size, flags, this); + auto *buf = new EglDmabufBuffer(planes, format, size, flags, this); for (int i = 0; i < yuvFormat.outputPlanes; i++) { int planeIndex = yuvFormat.planes[i].planeIndex; @@ -371,7 +361,7 @@ return buf; } -LinuxDmabuf* LinuxDmabuf::factory(AbstractEglBackend *backend) +EglDmabuf* EglDmabuf::factory(AbstractEglBackend *backend) { if (!backend->hasExtension(QByteArrayLiteral("EGL_EXT_image_dma_buf_import"))) { return nullptr; @@ -386,32 +376,31 @@ return nullptr; } - return new LinuxDmabuf(backend); + return new EglDmabuf(backend); } -LinuxDmabuf::LinuxDmabuf(AbstractEglBackend *backend) - : KWayland::Server::LinuxDmabufUnstableV1Interface::Impl() +EglDmabuf::EglDmabuf(AbstractEglBackend *backend) + : LinuxDmabuf() , m_backend(backend) { - Q_ASSERT(waylandServer()); - m_interface = waylandServer()->display()->createLinuxDmabufInterface(backend); + auto prevBuffersSet = waylandServer()->linuxDmabufBuffers(); + for (auto *buffer : prevBuffersSet) { + auto *buf = static_cast(buffer); + buf->setInterfaceImplementation(this); + buf->addImage(createImage(buf->planes(), buf->format(), buf->size())); + } setSupportedFormatsAndModifiers(); - m_interface->setImpl(this); - m_interface->create(); } -LinuxDmabuf::~LinuxDmabuf() +EglDmabuf::~EglDmabuf() { - for (auto *dmabuf : qAsConst(m_buffers)) { - dmabuf->removeImages(); + auto curBuffers = waylandServer()->linuxDmabufBuffers(); + for (auto *buffer : curBuffers) { + auto *buf = static_cast(buffer); + buf->removeImages(); } } -void LinuxDmabuf::removeBuffer(DmabufBuffer *buffer) -{ - m_buffers.remove(buffer); -} - const uint32_t s_multiPlaneFormats[] = { DRM_FORMAT_XRGB8888_A8, DRM_FORMAT_XBGR8888_A8, @@ -457,7 +446,7 @@ } } -void LinuxDmabuf::setSupportedFormatsAndModifiers() +void EglDmabuf::setSupportedFormatsAndModifiers() { const EGLDisplay eglDisplay = m_backend->eglDisplay(); EGLint count = 0; @@ -498,7 +487,7 @@ set.insert(format, QSet()); } - m_interface->setSupportedFormatsWithModifiers(set); + LinuxDmabuf::setSupportedFormatsAndModifiers(set); } } diff --git a/wayland_server.h b/wayland_server.h --- a/wayland_server.h +++ b/wayland_server.h @@ -68,6 +68,8 @@ class XdgForeignInterface; class XdgOutputManagerInterface; class KeyStateInterface; +class LinuxDmabufUnstableV1Interface; +class LinuxDmabufUnstableV1Buffer; } } @@ -122,6 +124,7 @@ KWayland::Server::XdgOutputManagerInterface *xdgOutputManager() const { return m_xdgOutputManager; } + KWayland::Server::LinuxDmabufUnstableV1Interface *linuxDmabuf(); QList clients() const { return m_clients; @@ -224,6 +227,16 @@ void simulateUserActivity(); void updateKeyState(KWin::Xkb::LEDs leds); + QSet linuxDmabufBuffers() const { + return m_linuxDmabufBuffers; + } + void addLinuxDmabufBuffer(KWayland::Server::LinuxDmabufUnstableV1Buffer *buffer) { + m_linuxDmabufBuffers << buffer; + } + void removeLinuxDmabufBuffer(KWayland::Server::LinuxDmabufUnstableV1Buffer *buffer) { + m_linuxDmabufBuffers.remove(buffer); + } + Q_SIGNALS: void shellClientAdded(KWin::ShellClient*); void shellClientRemoved(KWin::ShellClient*); @@ -256,6 +269,8 @@ KWayland::Server::IdleInterface *m_idle = nullptr; KWayland::Server::XdgOutputManagerInterface *m_xdgOutputManager = nullptr; KWayland::Server::XdgDecorationManagerInterface *m_xdgDecorationManager = nullptr; + KWayland::Server::LinuxDmabufUnstableV1Interface *m_linuxDmabuf = nullptr; + QSet m_linuxDmabufBuffers; struct { KWayland::Server::ClientConnection *client = nullptr; QMetaObject::Connection destroyConnection; diff --git a/wayland_server.cpp b/wayland_server.cpp --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -471,6 +472,15 @@ return true; } +KWayland::Server::LinuxDmabufUnstableV1Interface *WaylandServer::linuxDmabuf() +{ + if (!m_linuxDmabuf) { + m_linuxDmabuf = m_display->createLinuxDmabufInterface(m_display); + m_linuxDmabuf->create(); + } + return m_linuxDmabuf; +} + SurfaceInterface *WaylandServer::findForeignTransientForSurface(SurfaceInterface *surface) { return m_XdgForeign->transientFor(surface);