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.
This commit is contained in:
Vlad Zahorodnii 2023-04-11 18:08:47 +03:00
parent 66ca843946
commit b9ba12d02e
15 changed files with 390 additions and 239 deletions

View file

@ -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 <memory>
#include <drm_fourcc.h>
#include <xf86drm.h>
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) {

View file

@ -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<EglContext> m_context;

View file

@ -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 <epoxy/egl.h>
namespace KWin
{
@ -48,8 +39,6 @@ bool BasicEGLSurfaceTextureWayland::create()
return loadDmabufTexture(buffer);
} else if (auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(m_pixmap->buffer())) {
return loadShmTexture(buffer);
} else if (auto buffer = qobject_cast<KWaylandServer::DrmClientBuffer *>(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 &region)
updateDmabufTexture(buffer);
} else if (auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(m_pixmap->buffer())) {
updateShmTexture(buffer, region);
} else if (auto buffer = qobject_cast<KWaylandServer::DrmClientBuffer *>(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<EGLClientBuffer>(buffer->resource()), attribs);
if (image != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, static_cast<GLeglImageOES>(image));
m_texture->setContentTransform(buffer->origin() == KWaylandServer::ClientBuffer::Origin::TopLeft ? TextureTransform::MirrorY : TextureTransforms());
}
return image;
}
} // namespace KWin

View file

@ -8,11 +8,8 @@
#include "openglsurfacetexture_wayland.h"
#include <epoxy/egl.h>
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 &region);
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;
};

View file

@ -16,6 +16,10 @@
#include <QOpenGLContext>
#include <drm_fourcc.h>
#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<EGLDeviceEXT>(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;

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -125,21 +125,6 @@ public:
ClientConnection *getConnection(wl_client *client);
QVector<ClientConnection *> 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.

View file

@ -15,8 +15,6 @@
#include <QString>
#include <QVector>
#include <EGL/egl.h>
struct wl_resource;
namespace KWaylandServer
@ -51,7 +49,6 @@ public:
QVector<SeatInterface *> seats;
QVector<ClientConnection *> clients;
QStringList socketNames;
::EGLDisplay eglDisplay = EGL_NO_DISPLAY;
QHash<::wl_resource *, ClientBuffer *> resourceToBuffer;
QHash<ClientBuffer *, ClientBufferDestroyListener *> bufferToListener;
QList<ClientBufferIntegration *> bufferIntegrations;

View file

@ -5,90 +5,132 @@
*/
#include "drmclientbuffer.h"
#include "clientbuffer_p.h"
#include "display.h"
#include "utils/common.h"
#include <EGL/egl.h>
#include <QtGui/qopengl.h>
#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<DrmClientBufferIntegrationPrivate>(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

View file

@ -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<DrmClientBufferIntegrationPrivate> d;
};
} // namespace KWaylandServer

View file

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="drm">
<copyright>
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.
</copyright>
<!-- drm support. This object is created by the server and published
using the display's global event. -->
<interface name="wl_drm" version="2">
<enum name="error">
<entry name="authenticate_fail" value="0"/>
<entry name="invalid_format" value="1"/>
<entry name="invalid_name" value="2"/>
</enum>
<enum name="format">
<!-- The drm format codes match the #defines in drm_fourcc.h.
The formats actually supported by the compositor will be
reported by the format event. New codes must not be added,
unless directly taken from drm_fourcc.h. -->
<entry name="c8" value="0x20203843"/>
<entry name="rgb332" value="0x38424752"/>
<entry name="bgr233" value="0x38524742"/>
<entry name="xrgb4444" value="0x32315258"/>
<entry name="xbgr4444" value="0x32314258"/>
<entry name="rgbx4444" value="0x32315852"/>
<entry name="bgrx4444" value="0x32315842"/>
<entry name="argb4444" value="0x32315241"/>
<entry name="abgr4444" value="0x32314241"/>
<entry name="rgba4444" value="0x32314152"/>
<entry name="bgra4444" value="0x32314142"/>
<entry name="xrgb1555" value="0x35315258"/>
<entry name="xbgr1555" value="0x35314258"/>
<entry name="rgbx5551" value="0x35315852"/>
<entry name="bgrx5551" value="0x35315842"/>
<entry name="argb1555" value="0x35315241"/>
<entry name="abgr1555" value="0x35314241"/>
<entry name="rgba5551" value="0x35314152"/>
<entry name="bgra5551" value="0x35314142"/>
<entry name="rgb565" value="0x36314752"/>
<entry name="bgr565" value="0x36314742"/>
<entry name="rgb888" value="0x34324752"/>
<entry name="bgr888" value="0x34324742"/>
<entry name="xrgb8888" value="0x34325258"/>
<entry name="xbgr8888" value="0x34324258"/>
<entry name="rgbx8888" value="0x34325852"/>
<entry name="bgrx8888" value="0x34325842"/>
<entry name="argb8888" value="0x34325241"/>
<entry name="abgr8888" value="0x34324241"/>
<entry name="rgba8888" value="0x34324152"/>
<entry name="bgra8888" value="0x34324142"/>
<entry name="xrgb2101010" value="0x30335258"/>
<entry name="xbgr2101010" value="0x30334258"/>
<entry name="rgbx1010102" value="0x30335852"/>
<entry name="bgrx1010102" value="0x30335842"/>
<entry name="argb2101010" value="0x30335241"/>
<entry name="abgr2101010" value="0x30334241"/>
<entry name="rgba1010102" value="0x30334152"/>
<entry name="bgra1010102" value="0x30334142"/>
<entry name="yuyv" value="0x56595559"/>
<entry name="yvyu" value="0x55595659"/>
<entry name="uyvy" value="0x59565955"/>
<entry name="vyuy" value="0x59555956"/>
<entry name="ayuv" value="0x56555941"/>
<entry name="xyuv8888" value="0x56555958"/>
<entry name="nv12" value="0x3231564e"/>
<entry name="nv21" value="0x3132564e"/>
<entry name="nv16" value="0x3631564e"/>
<entry name="nv61" value="0x3136564e"/>
<entry name="yuv410" value="0x39565559"/>
<entry name="yvu410" value="0x39555659"/>
<entry name="yuv411" value="0x31315559"/>
<entry name="yvu411" value="0x31315659"/>
<entry name="yuv420" value="0x32315559"/>
<entry name="yvu420" value="0x32315659"/>
<entry name="yuv422" value="0x36315559"/>
<entry name="yvu422" value="0x36315659"/>
<entry name="yuv444" value="0x34325559"/>
<entry name="yvu444" value="0x34325659"/>
<entry name="abgr16f" value="0x48344241"/>
<entry name="xbgr16f" value="0x48344258"/>
</enum>
<!-- Call this request with the magic received from drmGetMagic().
It will be passed on to the drmAuthMagic() or
DRIAuthConnection() call. This authentication must be
completed before create_buffer could be used. -->
<request name="authenticate">
<arg name="id" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="stride" type="uint"/>
<arg name="format" type="uint"/>
</request>
<!-- Create a wayland buffer for the named DRM buffer. The DRM
surface must have a name using the flink ioctl -->
<request name="create_planar_buffer">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
<!-- Notification of the path of the drm device which is used by
the server. The client should use this device for creating
local buffers. Only buffers created from this device should
be be passed to the server using this drm object's
create_buffer request. -->
<event name="device">
<arg name="name" type="string"/>
</event>
<event name="format">
<arg name="format" type="uint"/>
</event>
<!-- Raised if the authenticate request succeeded -->
<event name="authenticated"/>
<enum name="capability" since="2">
<description summary="wl_drm capability bitmask">
Bitmask of capabilities.
</description>
<entry name="prime" value="1" summary="wl_drm prime available"/>
</enum>
<event name="capabilities">
<arg name="value" type="uint"/>
</event>
<!-- Version 2 additions -->
<!-- Create a wayland buffer for the prime fd. Use for regular and planar
buffers. Pass 0 for offset and stride for unused planes. -->
<request name="create_prime_buffer" since="2">
<arg name="id" type="new_id" interface="wl_buffer"/>
<arg name="name" type="fd"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
<arg name="format" type="uint"/>
<arg name="offset0" type="int"/>
<arg name="stride0" type="int"/>
<arg name="offset1" type="int"/>
<arg name="stride1" type="int"/>
<arg name="offset2" type="int"/>
<arg name="stride2" type="int"/>
</request>
</interface>
</protocol>

View file

@ -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) {

View file

@ -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<KWaylandServer::ClientConnection> m_xwaylandConnection;