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:
parent
66ca843946
commit
b9ba12d02e
15 changed files with 390 additions and 239 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ®ion)
|
|||
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
|
||||
|
|
|
@ -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 ®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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
189
src/wayland/protocols/wayland-drm.xml
Normal file
189
src/wayland/protocols/wayland-drm.xml
Normal 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>
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue