diff --git a/src/client/protocols/linux-dmabuf-unstable-v1.xml b/src/client/protocols/linux-dmabuf-unstable-v1.xml
new file mode 100644
--- /dev/null
+++ b/src/client/protocols/linux-dmabuf-unstable-v1.xml
@@ -0,0 +1,348 @@
+
+
+
+
+ Copyright © 2014, 2015 Collabora, Ltd.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice (including the next
+ paragraph) shall be included in all copies or substantial portions of the
+ Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+
+
+
+
+ Following the interfaces from:
+ https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
+ and the Linux DRM sub-system's AddFb2 ioctl.
+
+ This interface offers ways to create generic dmabuf-based
+ wl_buffers. Immediately after a client binds to this interface,
+ the set of supported formats and format modifiers is sent with
+ 'format' and 'modifier' events.
+
+ The following are required from clients:
+
+ - Clients must ensure that either all data in the dma-buf is
+ coherent for all subsequent read access or that coherency is
+ correctly handled by the underlying kernel-side dma-buf
+ implementation.
+
+ - Don't make any more attachments after sending the buffer to the
+ compositor. Making more attachments later increases the risk of
+ the compositor not being able to use (re-import) an existing
+ dmabuf-based wl_buffer.
+
+ The underlying graphics stack must ensure the following:
+
+ - The dmabuf file descriptors relayed to the server will stay valid
+ for the whole lifetime of the wl_buffer. This means the server may
+ at any time use those fds to import the dmabuf into any kernel
+ sub-system that might accept it.
+
+ To create a wl_buffer from one or more dmabufs, a client creates a
+ zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
+ request. All planes required by the intended format are added with
+ the 'add' request. Finally, a 'create' or 'create_immed' request is
+ issued, which has the following outcome depending on the import success.
+
+ The 'create' request,
+ - on success, triggers a 'created' event which provides the final
+ wl_buffer to the client.
+ - on failure, triggers a 'failed' event to convey that the server
+ cannot use the dmabufs received from the client.
+
+ For the 'create_immed' request,
+ - on success, the server immediately imports the added dmabufs to
+ create a wl_buffer. No event is sent from the server in this case.
+ - on failure, the server can choose to either:
+ - terminate the client by raising a fatal error.
+ - mark the wl_buffer as failed, and send a 'failed' event to the
+ client. If the client uses a failed wl_buffer as an argument to any
+ request, the behaviour is compositor implementation-defined.
+
+ Warning! The protocol described in this file is experimental and
+ backward incompatible changes may be made. Backward compatible changes
+ may be added together with the corresponding interface version bump.
+ Backward incompatible changes are done by bumping the version number in
+ the protocol and interface names and resetting the interface version.
+ Once the protocol is to be declared stable, the 'z' prefix and the
+ version number in the protocol and interface names are removed and the
+ interface version number is reset.
+
+
+
+
+ Objects created through this interface, especially wl_buffers, will
+ remain valid.
+
+
+
+
+
+ This temporary object is used to collect multiple dmabuf handles into
+ a single batch to create a wl_buffer. It can only be used once and
+ should be destroyed after a 'created' or 'failed' event has been
+ received.
+
+
+
+
+
+
+ This event advertises one buffer format that the server supports.
+ All the supported formats are advertised once when the client
+ binds to this interface. A roundtrip after binding guarantees
+ that the client has received all supported formats.
+
+ For the definition of the format codes, see the
+ zwp_linux_buffer_params_v1::create request.
+
+ Warning: the 'format' event is likely to be deprecated and replaced
+ with the 'modifier' event introduced in zwp_linux_dmabuf_v1
+ version 3, described below. Please refrain from using the information
+ received from this event.
+
+
+
+
+
+
+ This event advertises the formats that the server supports, along with
+ the modifiers supported for each format. All the supported modifiers
+ for all the supported formats are advertised once when the client
+ binds to this interface. A roundtrip after binding guarantees that
+ the client has received all supported format-modifier pairs.
+
+ For the definition of the format and modifier codes, see the
+ zwp_linux_buffer_params_v1::create request.
+
+
+
+
+
+
+
+
+
+ This temporary object is a collection of dmabufs and other
+ parameters that together form a single logical buffer. The temporary
+ object may eventually create one wl_buffer unless cancelled by
+ destroying it before requesting 'create'.
+
+ Single-planar formats only require one dmabuf, however
+ multi-planar formats may require more than one dmabuf. For all
+ formats, an 'add' request must be called once per plane (even if the
+ underlying dmabuf fd is identical).
+
+ You must use consecutive plane indices ('plane_idx' argument for 'add')
+ from zero to the number of planes used by the drm_fourcc format code.
+ All planes required by the format must be given exactly once, but can
+ be given in any order. Each plane index can be set only once.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Cleans up the temporary data sent to the server for dmabuf-based
+ wl_buffer creation.
+
+
+
+
+
+ This request adds one dmabuf to the set in this
+ zwp_linux_buffer_params_v1.
+
+ The 64-bit unsigned value combined from modifier_hi and modifier_lo
+ is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
+ fb modifier, which is defined in drm_mode.h of Linux UAPI.
+ This is an opaque token. Drivers use this token to express tiling,
+ compression, etc. driver-specific modifications to the base format
+ defined by the DRM fourcc code.
+
+ This request raises the PLANE_IDX error if plane_idx is too large.
+ The error PLANE_SET is raised if attempting to set a plane that
+ was already set.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This asks for creation of a wl_buffer from the added dmabuf
+ buffers. The wl_buffer is not created immediately but returned via
+ the 'created' event if the dmabuf sharing succeeds. The sharing
+ may fail at runtime for reasons a client cannot predict, in
+ which case the 'failed' event is triggered.
+
+ The 'format' argument is a DRM_FORMAT code, as defined by the
+ libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
+ authoritative source on how the format codes should work.
+
+ The 'flags' is a bitfield of the flags defined in enum "flags".
+ 'y_invert' means the that the image needs to be y-flipped.
+
+ Flag 'interlaced' means that the frame in the buffer is not
+ progressive as usual, but interlaced. An interlaced buffer as
+ supported here must always contain both top and bottom fields.
+ The top field always begins on the first pixel row. The temporal
+ ordering between the two fields is top field first, unless
+ 'bottom_first' is specified. It is undefined whether 'bottom_first'
+ is ignored if 'interlaced' is not set.
+
+ This protocol does not convey any information about field rate,
+ duration, or timing, other than the relative ordering between the
+ two fields in one buffer. A compositor may have to estimate the
+ intended field rate from the incoming buffer rate. It is undefined
+ whether the time of receiving wl_surface.commit with a new buffer
+ attached, applying the wl_surface state, wl_surface.frame callback
+ trigger, presentation, or any other point in the compositor cycle
+ is used to measure the frame or field times. There is no support
+ for detecting missed or late frames/fields/buffers either, and
+ there is no support whatsoever for cooperating with interlaced
+ compositor output.
+
+ The composited image quality resulting from the use of interlaced
+ buffers is explicitly undefined. A compositor may use elaborate
+ hardware features or software to deinterlace and create progressive
+ output frames from a sequence of interlaced input buffers, or it
+ may produce substandard image quality. However, compositors that
+ cannot guarantee reasonable image quality in all cases are recommended
+ to just reject all interlaced buffers.
+
+ Any argument errors, including non-positive width or height,
+ mismatch between the number of planes and the format, bad
+ format, bad offset or stride, may be indicated by fatal protocol
+ errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
+ OUT_OF_BOUNDS.
+
+ Dmabuf import errors in the server that are not obvious client
+ bugs are returned via the 'failed' event as non-fatal. This
+ allows attempting dmabuf sharing and falling back in the client
+ if it fails.
+
+ This request can be sent only once in the object's lifetime, after
+ which the only legal request is destroy. This object should be
+ destroyed after issuing a 'create' request. Attempting to use this
+ object after issuing 'create' raises ALREADY_USED protocol error.
+
+ It is not mandatory to issue 'create'. If a client wants to
+ cancel the buffer creation, it can just destroy this object.
+
+
+
+
+
+
+
+
+
+ This event indicates that the attempted buffer creation was
+ successful. It provides the new wl_buffer referencing the dmabuf(s).
+
+ Upon receiving this event, the client should destroy the
+ zlinux_dmabuf_params object.
+
+
+
+
+
+
+ This event indicates that the attempted buffer creation has
+ failed. It usually means that one of the dmabuf constraints
+ has not been fulfilled.
+
+ Upon receiving this event, the client should destroy the
+ zlinux_buffer_params object.
+
+
+
+
+
+ This asks for immediate creation of a wl_buffer by importing the
+ added dmabufs.
+
+ In case of import success, no event is sent from the server, and the
+ wl_buffer is ready to be used by the client.
+
+ Upon import failure, either of the following may happen, as seen fit
+ by the implementation:
+ - the client is terminated with one of the following fatal protocol
+ errors:
+ - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
+ in case of argument errors such as mismatch between the number
+ of planes and the format, bad format, non-positive width or
+ height, or bad offset or stride.
+ - INVALID_WL_BUFFER, in case the cause for failure is unknown or
+ plaform specific.
+ - the server creates an invalid wl_buffer, marks it as failed and
+ sends a 'failed' event to the client. The result of using this
+ invalid wl_buffer as an argument in any request by the client is
+ defined by the compositor implementation.
+
+ This takes the same arguments as a 'create' request, and obeys the
+ same restrictions.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt
--- a/src/server/CMakeLists.txt
+++ b/src/server/CMakeLists.txt
@@ -17,6 +17,7 @@
fakeinput_interface.cpp
keyboard_interface.cpp
keystate_interface.cpp
+ linuxdmabuf_v1_interface.cpp
remote_access_interface.cpp
outputconfiguration_interface.cpp
outputchangeset.cpp
@@ -214,6 +215,11 @@
BASENAME keystate
)
+ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
+ PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/linux-dmabuf-unstable-v1.xml
+ BASENAME linux-dmabuf-unstable-v1
+)
+
set(SERVER_GENERATED_SRCS
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-client-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-output-management-server-protocol.h
@@ -270,6 +276,7 @@
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-server-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-client-protocol.h
${CMAKE_CURRENT_BINARY_DIR}/wayland-eglstream-controller-server-protocol.h
+ ${CMAKE_CURRENT_BINARY_DIR}/wayland-linux-dmabuf-unstable-v1-server-protocol.h
)
set_source_files_properties(${SERVER_GENERATED_SRCS} PROPERTIES SKIP_AUTOMOC ON)
@@ -354,6 +361,7 @@
xdgshell_interface.h
xdgforeign_interface.h
xdgoutput_interface.h
+ linuxdmabuf_v1_interface.h
)
install(FILES
diff --git a/src/server/buffer_interface.h b/src/server/buffer_interface.h
--- a/src/server/buffer_interface.h
+++ b/src/server/buffer_interface.h
@@ -34,6 +34,10 @@
{
class SurfaceInterface;
+namespace LinuxDmabuf
+{
+ class Buffer;
+}
/**
* @brief Reference counted representation of a Wayland buffer on Server side.
@@ -104,6 +108,10 @@
* @returns The native wl_shm_buffer if the BufferInterface represents a shared memory buffer, otherwise @c nullptr.
**/
wl_shm_buffer *shmBuffer();
+ /**
+ * Returns a pointer to the LinuxDmabuf::Buffer when the buffer is a dmabuf buffer, and nullptr otherwise.
+ */
+ LinuxDmabuf::Buffer *linuxDmabufBuffer();
/**
* @returns the native wl_resource wrapped by this BufferInterface.
**/
diff --git a/src/server/buffer_interface.cpp b/src/server/buffer_interface.cpp
--- a/src/server/buffer_interface.cpp
+++ b/src/server/buffer_interface.cpp
@@ -21,12 +21,15 @@
#include "display.h"
#include "logging.h"
#include "surface_interface.h"
+#include "linuxdmabuf_v1_interface.h"
// Wayland
#include
// EGL
#include
#include
+#include "drm_fourcc.h"
+
namespace KWayland
{
namespace Server
@@ -47,6 +50,7 @@
QImage createImage();
wl_resource *buffer;
wl_shm_buffer *shmBuffer;
+ LinuxDmabuf::Buffer *dmabufBuffer;
SurfaceInterface *surface;
int refCount;
QSize size;
@@ -103,11 +107,15 @@
BufferInterface::Private::Private(BufferInterface *q, wl_resource *resource, SurfaceInterface *parent)
: buffer(resource)
, shmBuffer(wl_shm_buffer_get(resource))
+ , dmabufBuffer(nullptr)
, surface(parent)
, refCount(0)
, alpha(false)
, q(q)
{
+ if (!shmBuffer && wl_resource_instance_of(resource, &wl_buffer_interface, LinuxDmabufUnstableV1Interface::bufferImplementation())) {
+ dmabufBuffer = static_cast(wl_resource_get_user_data(resource));
+ }
s_buffers << this;
listener.notify = destroyListenerCallback;
listener.link.prev = nullptr;
@@ -125,6 +133,43 @@
alpha = false;
break;
}
+ } else if (dmabufBuffer) {
+ switch (dmabufBuffer->format()) {
+ case DRM_FORMAT_ARGB4444:
+ case DRM_FORMAT_ABGR4444:
+ case DRM_FORMAT_RGBA4444:
+ case DRM_FORMAT_BGRA4444:
+
+ case DRM_FORMAT_ARGB1555:
+ case DRM_FORMAT_ABGR1555:
+ case DRM_FORMAT_RGBA5551:
+ case DRM_FORMAT_BGRA5551:
+
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_RGBA8888:
+ case DRM_FORMAT_BGRA8888:
+
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_BGRA1010102:
+
+ case DRM_FORMAT_XRGB8888_A8:
+ case DRM_FORMAT_XBGR8888_A8:
+ case DRM_FORMAT_RGBX8888_A8:
+ case DRM_FORMAT_BGRX8888_A8:
+ case DRM_FORMAT_RGB888_A8:
+ case DRM_FORMAT_BGR888_A8:
+ case DRM_FORMAT_RGB565_A8:
+ case DRM_FORMAT_BGR565_A8:
+ alpha = true;
+ break;
+ default:
+ alpha = false;
+ break;
+ }
+ size = dmabufBuffer->size();
} else if (parent) {
EGLDisplay eglDisplay = parent->global()->display()->eglDisplay();
static bool resolved = false;
@@ -275,6 +320,11 @@
return d->shmBuffer;
}
+LinuxDmabuf::Buffer *BufferInterface::linuxDmabufBuffer()
+{
+ return d->dmabufBuffer;
+}
+
wl_resource *BufferInterface::resource() const
{
return d->buffer;
diff --git a/src/server/display.h b/src/server/display.h
--- a/src/server/display.h
+++ b/src/server/display.h
@@ -92,6 +92,7 @@
class XdgDecorationManagerInterface;
class EglStreamControllerInterface;
class KeyStateInterface;
+class LinuxDmabufUnstableV1Interface;
/**
* @brief Class holding the Wayland server display loop.
@@ -282,6 +283,13 @@
**/
ServerSideDecorationPaletteManagerInterface *createServerSideDecorationPaletteManager(QObject *parent = nullptr);
+ /**
+ * Creates the LinuxDmabufUnstableV1Interface in interface @p version.
+ *
+ * @returns A pointer to the created interface
+ **/
+ LinuxDmabufUnstableV1Interface *createLinuxDmabufInterface(QObject *parent = nullptr);
+
/**
* Creates the XdgOutputManagerInterface
*
diff --git a/src/server/display.cpp b/src/server/display.cpp
--- a/src/server/display.cpp
+++ b/src/server/display.cpp
@@ -57,6 +57,7 @@
#include "xdgdecoration_interface.h"
#include "eglstream_controller_interface.h"
#include "keystate_interface.h"
+#include "linuxdmabuf_v1_interface.h"
#include
#include
@@ -494,6 +495,12 @@
return b;
}
+LinuxDmabufUnstableV1Interface *Display::createLinuxDmabufInterface(QObject *parent)
+{
+ auto b = new LinuxDmabufUnstableV1Interface(this, parent);
+ connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; });
+ return b;
+}
PlasmaVirtualDesktopManagementInterface *Display::createPlasmaVirtualDesktopManagement(QObject *parent)
{
diff --git a/src/server/drm_fourcc.h b/src/server/drm_fourcc.h
new file mode 100644
--- /dev/null
+++ b/src/server/drm_fourcc.h
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef DRM_FOURCC_H
+#define DRM_FOURCC_H
+
+//#include "drm.h"
+
+// These typedefs are copied from drm.h
+typedef uint32_t __u32;
+typedef uint64_t __u64;
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define fourcc_code(a, b, c, d) ((__u32)(a) | ((__u32)(b) << 8) | \
+ ((__u32)(c) << 16) | ((__u32)(d) << 24))
+
+#define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */
+
+/* color index */
+#define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */
+
+/* 8 bpp Red */
+#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+
+/* 16 bpp Red */
+#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R little endian */
+
+/* 16 bpp RG */
+#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
+#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+
+/* 32 bpp RG */
+#define DRM_FORMAT_RG1616 fourcc_code('R', 'G', '3', '2') /* [31:0] R:G 16:16 little endian */
+#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] G:R 16:16 little endian */
+
+/* 8 bpp RGB */
+#define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */
+#define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */
+
+/* 16 bpp RGB */
+#define DRM_FORMAT_XRGB4444 fourcc_code('X', 'R', '1', '2') /* [15:0] x:R:G:B 4:4:4:4 little endian */
+#define DRM_FORMAT_XBGR4444 fourcc_code('X', 'B', '1', '2') /* [15:0] x:B:G:R 4:4:4:4 little endian */
+#define DRM_FORMAT_RGBX4444 fourcc_code('R', 'X', '1', '2') /* [15:0] R:G:B:x 4:4:4:4 little endian */
+#define DRM_FORMAT_BGRX4444 fourcc_code('B', 'X', '1', '2') /* [15:0] B:G:R:x 4:4:4:4 little endian */
+
+#define DRM_FORMAT_ARGB4444 fourcc_code('A', 'R', '1', '2') /* [15:0] A:R:G:B 4:4:4:4 little endian */
+#define DRM_FORMAT_ABGR4444 fourcc_code('A', 'B', '1', '2') /* [15:0] A:B:G:R 4:4:4:4 little endian */
+#define DRM_FORMAT_RGBA4444 fourcc_code('R', 'A', '1', '2') /* [15:0] R:G:B:A 4:4:4:4 little endian */
+#define DRM_FORMAT_BGRA4444 fourcc_code('B', 'A', '1', '2') /* [15:0] B:G:R:A 4:4:4:4 little endian */
+
+#define DRM_FORMAT_XRGB1555 fourcc_code('X', 'R', '1', '5') /* [15:0] x:R:G:B 1:5:5:5 little endian */
+#define DRM_FORMAT_XBGR1555 fourcc_code('X', 'B', '1', '5') /* [15:0] x:B:G:R 1:5:5:5 little endian */
+#define DRM_FORMAT_RGBX5551 fourcc_code('R', 'X', '1', '5') /* [15:0] R:G:B:x 5:5:5:1 little endian */
+#define DRM_FORMAT_BGRX5551 fourcc_code('B', 'X', '1', '5') /* [15:0] B:G:R:x 5:5:5:1 little endian */
+
+#define DRM_FORMAT_ARGB1555 fourcc_code('A', 'R', '1', '5') /* [15:0] A:R:G:B 1:5:5:5 little endian */
+#define DRM_FORMAT_ABGR1555 fourcc_code('A', 'B', '1', '5') /* [15:0] A:B:G:R 1:5:5:5 little endian */
+#define DRM_FORMAT_RGBA5551 fourcc_code('R', 'A', '1', '5') /* [15:0] R:G:B:A 5:5:5:1 little endian */
+#define DRM_FORMAT_BGRA5551 fourcc_code('B', 'A', '1', '5') /* [15:0] B:G:R:A 5:5:5:1 little endian */
+
+#define DRM_FORMAT_RGB565 fourcc_code('R', 'G', '1', '6') /* [15:0] R:G:B 5:6:5 little endian */
+#define DRM_FORMAT_BGR565 fourcc_code('B', 'G', '1', '6') /* [15:0] B:G:R 5:6:5 little endian */
+
+/* 24 bpp RGB */
+#define DRM_FORMAT_RGB888 fourcc_code('R', 'G', '2', '4') /* [23:0] R:G:B little endian */
+#define DRM_FORMAT_BGR888 fourcc_code('B', 'G', '2', '4') /* [23:0] B:G:R little endian */
+
+/* 32 bpp RGB */
+#define DRM_FORMAT_XRGB8888 fourcc_code('X', 'R', '2', '4') /* [31:0] x:R:G:B 8:8:8:8 little endian */
+#define DRM_FORMAT_XBGR8888 fourcc_code('X', 'B', '2', '4') /* [31:0] x:B:G:R 8:8:8:8 little endian */
+#define DRM_FORMAT_RGBX8888 fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */
+#define DRM_FORMAT_BGRX8888 fourcc_code('B', 'X', '2', '4') /* [31:0] B:G:R:x 8:8:8:8 little endian */
+
+#define DRM_FORMAT_ARGB8888 fourcc_code('A', 'R', '2', '4') /* [31:0] A:R:G:B 8:8:8:8 little endian */
+#define DRM_FORMAT_ABGR8888 fourcc_code('A', 'B', '2', '4') /* [31:0] A:B:G:R 8:8:8:8 little endian */
+#define DRM_FORMAT_RGBA8888 fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
+#define DRM_FORMAT_BGRA8888 fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */
+
+#define DRM_FORMAT_XRGB2101010 fourcc_code('X', 'R', '3', '0') /* [31:0] x:R:G:B 2:10:10:10 little endian */
+#define DRM_FORMAT_XBGR2101010 fourcc_code('X', 'B', '3', '0') /* [31:0] x:B:G:R 2:10:10:10 little endian */
+#define DRM_FORMAT_RGBX1010102 fourcc_code('R', 'X', '3', '0') /* [31:0] R:G:B:x 10:10:10:2 little endian */
+#define DRM_FORMAT_BGRX1010102 fourcc_code('B', 'X', '3', '0') /* [31:0] B:G:R:x 10:10:10:2 little endian */
+
+#define DRM_FORMAT_ARGB2101010 fourcc_code('A', 'R', '3', '0') /* [31:0] A:R:G:B 2:10:10:10 little endian */
+#define DRM_FORMAT_ABGR2101010 fourcc_code('A', 'B', '3', '0') /* [31:0] A:B:G:R 2:10:10:10 little endian */
+#define DRM_FORMAT_RGBA1010102 fourcc_code('R', 'A', '3', '0') /* [31:0] R:G:B:A 10:10:10:2 little endian */
+#define DRM_FORMAT_BGRA1010102 fourcc_code('B', 'A', '3', '0') /* [31:0] B:G:R:A 10:10:10:2 little endian */
+
+/* packed YCbCr */
+#define DRM_FORMAT_YUYV fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */
+#define DRM_FORMAT_YVYU fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */
+#define DRM_FORMAT_UYVY fourcc_code('U', 'Y', 'V', 'Y') /* [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian */
+#define DRM_FORMAT_VYUY fourcc_code('V', 'Y', 'U', 'Y') /* [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian */
+
+#define DRM_FORMAT_AYUV fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */
+
+/*
+ * 2 plane RGB + A
+ * index 0 = RGB plane, same format as the corresponding non _A8 format has
+ * index 1 = A plane, [7:0] A
+ */
+#define DRM_FORMAT_XRGB8888_A8 fourcc_code('X', 'R', 'A', '8')
+#define DRM_FORMAT_XBGR8888_A8 fourcc_code('X', 'B', 'A', '8')
+#define DRM_FORMAT_RGBX8888_A8 fourcc_code('R', 'X', 'A', '8')
+#define DRM_FORMAT_BGRX8888_A8 fourcc_code('B', 'X', 'A', '8')
+#define DRM_FORMAT_RGB888_A8 fourcc_code('R', '8', 'A', '8')
+#define DRM_FORMAT_BGR888_A8 fourcc_code('B', '8', 'A', '8')
+#define DRM_FORMAT_RGB565_A8 fourcc_code('R', '5', 'A', '8')
+#define DRM_FORMAT_BGR565_A8 fourcc_code('B', '5', 'A', '8')
+
+/*
+ * 2 plane YCbCr
+ * index 0 = Y plane, [7:0] Y
+ * index 1 = Cr:Cb plane, [15:0] Cr:Cb little endian
+ * or
+ * index 1 = Cb:Cr plane, [15:0] Cb:Cr little endian
+ */
+#define DRM_FORMAT_NV12 fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV21 fourcc_code('N', 'V', '2', '1') /* 2x2 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV16 fourcc_code('N', 'V', '1', '6') /* 2x1 subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV61 fourcc_code('N', 'V', '6', '1') /* 2x1 subsampled Cb:Cr plane */
+#define DRM_FORMAT_NV24 fourcc_code('N', 'V', '2', '4') /* non-subsampled Cr:Cb plane */
+#define DRM_FORMAT_NV42 fourcc_code('N', 'V', '4', '2') /* non-subsampled Cb:Cr plane */
+
+/*
+ * 3 plane YCbCr
+ * index 0: Y plane, [7:0] Y
+ * index 1: Cb plane, [7:0] Cb
+ * index 2: Cr plane, [7:0] Cr
+ * or
+ * index 1: Cr plane, [7:0] Cr
+ * index 2: Cb plane, [7:0] Cb
+ */
+#define DRM_FORMAT_YUV410 fourcc_code('Y', 'U', 'V', '9') /* 4x4 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU410 fourcc_code('Y', 'V', 'U', '9') /* 4x4 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV411 fourcc_code('Y', 'U', '1', '1') /* 4x1 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU411 fourcc_code('Y', 'V', '1', '1') /* 4x1 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV420 fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU420 fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV422 fourcc_code('Y', 'U', '1', '6') /* 2x1 subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU422 fourcc_code('Y', 'V', '1', '6') /* 2x1 subsampled Cr (1) and Cb (2) planes */
+#define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */
+#define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */
+
+
+/*
+ * Format Modifiers:
+ *
+ * Format modifiers describe, typically, a re-ordering or modification
+ * of the data in a plane of an FB. This can be used to express tiled/
+ * swizzled formats, or compression, or a combination of the two.
+ *
+ * The upper 8 bits of the format modifier are a vendor-id as assigned
+ * below. The lower 56 bits are assigned as vendor sees fit.
+ */
+
+/* Vendor Ids: */
+#define DRM_FORMAT_MOD_NONE 0
+#define DRM_FORMAT_MOD_VENDOR_NONE 0
+#define DRM_FORMAT_MOD_VENDOR_INTEL 0x01
+#define DRM_FORMAT_MOD_VENDOR_AMD 0x02
+#define DRM_FORMAT_MOD_VENDOR_NV 0x03
+#define DRM_FORMAT_MOD_VENDOR_SAMSUNG 0x04
+#define DRM_FORMAT_MOD_VENDOR_QCOM 0x05
+#define DRM_FORMAT_MOD_VENDOR_VIVANTE 0x06
+#define DRM_FORMAT_MOD_VENDOR_BROADCOM 0x07
+/* add more to the end as needed */
+
+#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1)
+
+#define fourcc_mod_code(vendor, val) \
+ ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
+
+/*
+ * Format Modifier tokens:
+ *
+ * When adding a new token please document the layout with a code comment,
+ * similar to the fourcc codes above. drm_fourcc.h is considered the
+ * authoritative source for all of these.
+ */
+
+/*
+ * Invalid Modifier
+ *
+ * This modifier can be used as a sentinel to terminate the format modifiers
+ * list, or to initialize a variable with an invalid modifier. It might also be
+ * used to report an error back to userspace for certain APIs.
+ */
+#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED)
+
+/*
+ * Linear Layout
+ *
+ * Just plain linear layout. Note that this is different from no specifying any
+ * modifier (e.g. not setting DRM_MODE_FB_MODIFIERS in the DRM_ADDFB2 ioctl),
+ * which tells the driver to also take driver-internal information into account
+ * and so might actually result in a tiled framebuffer.
+ */
+#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0)
+
+/* Intel framebuffer modifiers */
+
+/*
+ * Intel X-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out row-major, with
+ * a platform-dependent stride. On top of that the memory can apply
+ * platform-depending swizzling of some higher address bits into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_X_TILED fourcc_mod_code(INTEL, 1)
+
+/*
+ * Intel Y-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles (except on gen2 where the tiles 2Kb)
+ * in row-major layout. Within the tile bytes are laid out in OWORD (16 bytes)
+ * chunks column-major, with a platform-dependent height. On top of that the
+ * memory can apply platform-depending swizzling of some higher address bits
+ * into bit6.
+ *
+ * This format is highly platforms specific and not useful for cross-driver
+ * sharing. It exists since on a given platform it does uniquely identify the
+ * layout in a simple way for i915-specific userspace.
+ */
+#define I915_FORMAT_MOD_Y_TILED fourcc_mod_code(INTEL, 2)
+
+/*
+ * Intel Yf-tiling layout
+ *
+ * This is a tiled layout using 4Kb tiles in row-major layout.
+ * Within the tile pixels are laid out in 16 256 byte units / sub-tiles which
+ * are arranged in four groups (two wide, two high) with column-major layout.
+ * Each group therefore consits out of four 256 byte units, which are also laid
+ * out as 2x2 column-major.
+ * 256 byte units are made out of four 64 byte blocks of pixels, producing
+ * either a square block or a 2:1 unit.
+ * 64 byte blocks of pixels contain four pixel rows of 16 bytes, where the width
+ * in pixel depends on the pixel depth.
+ */
+#define I915_FORMAT_MOD_Yf_TILED fourcc_mod_code(INTEL, 3)
+
+/*
+ * Intel color control surface (CCS) for render compression
+ *
+ * The framebuffer format must be one of the 8:8:8:8 RGB formats.
+ * The main surface will be plane index 0 and must be Y/Yf-tiled,
+ * the CCS will be plane index 1.
+ *
+ * Each CCS tile matches a 1024x512 pixel area of the main surface.
+ * To match certain aspects of the 3D hardware the CCS is
+ * considered to be made up of normal 128Bx32 Y tiles, Thus
+ * the CCS pitch must be specified in multiples of 128 bytes.
+ *
+ * In reality the CCS tile appears to be a 64Bx64 Y tile, composed
+ * of QWORD (8 bytes) chunks instead of OWORD (16 bytes) chunks.
+ * But that fact is not relevant unless the memory is accessed
+ * directly.
+ */
+#define I915_FORMAT_MOD_Y_TILED_CCS fourcc_mod_code(INTEL, 4)
+#define I915_FORMAT_MOD_Yf_TILED_CCS fourcc_mod_code(INTEL, 5)
+
+/*
+ * Tiled, NV12MT, grouped in 64 (pixels) x 32 (lines) -sized macroblocks
+ *
+ * Macroblocks are laid in a Z-shape, and each pixel data is following the
+ * standard NV12 style.
+ * As for NV12, an image is the result of two frame buffers: one for Y,
+ * one for the interleaved Cb/Cr components (1/2 the height of the Y buffer).
+ * Alignment requirements are (for each buffer):
+ * - multiple of 128 pixels for the width
+ * - multiple of 32 pixels for the height
+ *
+ * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html
+ */
+#define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1)
+
+/* Vivante framebuffer modifiers */
+
+/*
+ * Vivante 4x4 tiling layout
+ *
+ * This is a simple tiled layout using tiles of 4x4 pixels in a row-major
+ * layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_TILED fourcc_mod_code(VIVANTE, 1)
+
+/*
+ * Vivante 64x64 super-tiling layout
+ *
+ * This is a tiled layout using 64x64 pixel super-tiles, where each super-tile
+ * contains 8x4 groups of 2x4 tiles of 4x4 pixels (like above) each, all in row-
+ * major layout.
+ *
+ * For more information: see
+ * https://github.com/etnaviv/etna_viv/blob/master/doc/hardware.md#texture-tiling
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SUPER_TILED fourcc_mod_code(VIVANTE, 2)
+
+/*
+ * Vivante 4x4 tiling layout for dual-pipe
+ *
+ * Same as the 4x4 tiling layout, except every second 4x4 pixel tile starts at a
+ * different base address. Offsets from the base addresses are therefore halved
+ * compared to the non-split tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED fourcc_mod_code(VIVANTE, 3)
+
+/*
+ * Vivante 64x64 super-tiling layout for dual-pipe
+ *
+ * Same as the 64x64 super-tiling layout, except every second 4x4 pixel tile
+ * starts at a different base address. Offsets from the base addresses are
+ * therefore halved compared to the non-split super-tiled layout.
+ */
+#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
+
+/* NVIDIA Tegra frame buffer modifiers */
+
+/*
+ * Some modifiers take parameters, for example the number of vertical GOBs in
+ * a block. Reserve the lower 32 bits for parameters
+ */
+#define __fourcc_mod_tegra_mode_shift 32
+#define fourcc_mod_tegra_code(val, params) \
+ fourcc_mod_code(NV, ((((__u64)val) << __fourcc_mod_tegra_mode_shift) | params))
+#define fourcc_mod_tegra_mod(m) \
+ (m & ~((1ULL << __fourcc_mod_tegra_mode_shift) - 1))
+#define fourcc_mod_tegra_param(m) \
+ (m & ((1ULL << __fourcc_mod_tegra_mode_shift) - 1))
+
+/*
+ * Tegra Tiled Layout, used by Tegra 2, 3 and 4.
+ *
+ * Pixels are arranged in simple tiles of 16 x 16 bytes.
+ */
+#define NV_FORMAT_MOD_TEGRA_TILED fourcc_mod_tegra_code(1, 0)
+
+/*
+ * Tegra 16Bx2 Block Linear layout, used by TK1/TX1
+ *
+ * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked
+ * vertically by a power of 2 (1 to 32 GOBs) to form a block.
+ *
+ * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape.
+ *
+ * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically.
+ * Valid values are:
+ *
+ * 0 == ONE_GOB
+ * 1 == TWO_GOBS
+ * 2 == FOUR_GOBS
+ * 3 == EIGHT_GOBS
+ * 4 == SIXTEEN_GOBS
+ * 5 == THIRTYTWO_GOBS
+ *
+ * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format
+ * in full detail.
+ */
+#define NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(v) fourcc_mod_tegra_code(2, v)
+
+/*
+ * Broadcom VC4 "T" format
+ *
+ * This is the primary layout that the V3D GPU can texture from (it
+ * can't do linear). The T format has:
+ *
+ * - 64b utiles of pixels in a raster-order grid according to cpp. It's 4x4
+ * pixels at 32 bit depth.
+ *
+ * - 1k subtiles made of a 4x4 raster-order grid of 64b utiles (so usually
+ * 16x16 pixels).
+ *
+ * - 4k tiles made of a 2x2 grid of 1k subtiles (so usually 32x32 pixels). On
+ * even 4k tile rows, they're arranged as (BL, TL, TR, BR), and on odd rows
+ * they're (TR, BR, BL, TL), where bottom left is start of memory.
+ *
+ * - an image made of 4k tiles in rows either left-to-right (even rows of 4k
+ * tiles) or right-to-left (odd rows of 4k tiles).
+ */
+#define DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED fourcc_mod_code(BROADCOM, 1)
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* DRM_FOURCC_H */
diff --git a/src/server/linuxdmabuf_v1_interface.h b/src/server/linuxdmabuf_v1_interface.h
new file mode 100644
--- /dev/null
+++ b/src/server/linuxdmabuf_v1_interface.h
@@ -0,0 +1,181 @@
+/********************************************************************
+Copyright © 2018 Fredrik Höglund
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+*********************************************************************/
+
+#ifndef WAYLAND_SERVER_LINUXDMABUF_INTERFACE_H
+#define WAYLAND_SERVER_LINUXDMABUF_INTERFACE_H
+
+#include
+#include "global.h"
+#include "resource.h"
+
+#include
+
+
+struct wl_buffer_interface;
+
+namespace KWayland
+{
+
+namespace Server
+{
+
+namespace LinuxDmabuf
+{
+ enum Flag {
+ YInverted = (1 << 0), /// Contents are y-inverted
+ Interlaced = (1 << 1), /// Content is interlaced
+ BottomFieldFirst = (1 << 2) /// Bottom field first
+ };
+
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ /**
+ * Represents a plane in a buffer
+ */
+ struct Plane {
+ int fd; /// The dmabuf file descriptor
+ uint32_t offset; /// The offset from the start of buffer
+ uint32_t stride; /// The distance from the start of a row to the next row in bytes
+ uint64_t modifier; /// The layout modifier
+ };
+
+ /**
+ * The base class for linux-dmabuf buffers
+ *
+ * Compositors should reimplement this class to store objects specific
+ * to the underlying graphics stack.
+ */
+ class Buffer {
+ public:
+ /**
+ * Creates a new Buffer.
+ */
+ Buffer(uint32_t format, const QSize &size) : m_format(format), m_size(size) {}
+
+ /**
+ * Destroys the Buffer.
+ */
+ virtual ~Buffer() = default;
+
+ /**
+ * Returns the DRM format code for the buffer.
+ */
+ uint32_t format() const { return m_format; }
+
+ /**
+ * Returns the size of the buffer.
+ */
+ QSize size() const { return m_size; }
+
+ private:
+ uint32_t m_format;
+ QSize m_size;
+ };
+}
+
+
+/**
+ * Represents the global zpw_linux_dmabuf_v1 interface.
+ *
+ * This interface provides a way for clients to create generic dmabuf based wl_buffers.
+ */
+class KWAYLANDSERVER_EXPORT LinuxDmabufUnstableV1Interface : public Global
+{
+ Q_OBJECT
+
+public:
+ /**
+ * The Bridge class provides an interface from the LinuxDmabufInterface to the compositor
+ */
+ class Bridge {
+ public:
+ Bridge() = default;
+ virtual ~Bridge() = default;
+
+ /**
+ * Returns the DRM format codes supported by the compositor.
+ */
+ virtual QVector supportedFormats() const = 0;
+
+ /**
+ * Returns the layout-modifiers supported for the given DRM format code.
+ */
+ virtual QVector supportedModifiers(uint32_t format) const = 0;
+
+ /**
+ * Imports a linux-dmabuf buffer into the compositor.
+ *
+ * The returned buffer takes ownership of the file descriptor for each plane.
+ * Note that it is the responsibility of the caller to close the file descriptors
+ * when the import fails.
+ *
+ * @return The imported buffer on success, and nullptr otherwise.
+ */
+ virtual LinuxDmabuf::Buffer *importBuffer(const QVector &planes,
+ uint32_t format,
+ const QSize &size,
+ LinuxDmabuf::Flags flags) = 0;
+ };
+
+ /**
+ * Destroys the LinuxDmabufUnstableV1Interface.
+ */
+ virtual ~LinuxDmabufUnstableV1Interface();
+
+ /**
+ * Sets the compositor bridge for the dmabuf interface.
+ */
+ void setBridge(Bridge *bridge);
+
+ /**
+ * Returns the compositor bridge for the dmabuf interface.
+ */
+ Bridge *bridge() const;
+
+ /**
+ * Returns the LinuxDmabufInterface for the given resource.
+ **/
+ static LinuxDmabufUnstableV1Interface *get(wl_resource *native);
+
+ /**
+ * Returns a pointer to the wl_buffer implementation for imported dmabufs.
+ */
+ static const struct wl_buffer_interface *bufferImplementation();
+
+private:
+ /**
+ * @internal
+ */
+ explicit LinuxDmabufUnstableV1Interface(Display *display, QObject *parent = nullptr);
+ friend class Display;
+
+private:
+ class Private;
+ Private *d_func() const;
+};
+
+
+} // namespace Server
+} // namespace KWayland
+
+Q_DECLARE_METATYPE(KWayland::Server::LinuxDmabufUnstableV1Interface*)
+Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Server::LinuxDmabuf::Flags)
+
+#endif // WAYLAND_SERVER_LINUXDMABUF_INTERFACE_H
diff --git a/src/server/linuxdmabuf_v1_interface.cpp b/src/server/linuxdmabuf_v1_interface.cpp
new file mode 100644
--- /dev/null
+++ b/src/server/linuxdmabuf_v1_interface.cpp
@@ -0,0 +1,490 @@
+/********************************************************************
+Copyright © 2018 Fredrik Höglund
+
+Based on the libweston implementation,
+Copyright © 2014, 2015 Collabora, Ltd.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see .
+*********************************************************************/
+
+#include
+#include "linuxdmabuf_v1_interface.h"
+#include "wayland-linux-dmabuf-unstable-v1-server-protocol.h"
+#include "wayland-server-protocol.h"
+#include "global_p.h"
+
+#include "drm_fourcc.h"
+
+#include
+
+#include
+#include
+
+#include
+
+
+namespace KWayland
+{
+
+namespace Server
+{
+
+
+class LinuxDmabufParams
+{
+public:
+ LinuxDmabufParams(LinuxDmabufUnstableV1Interface *dmabufInterface, wl_client *client, uint32_t version, uint32_t id);
+ ~LinuxDmabufParams();
+
+ void postNoMemory() { wl_resource_post_no_memory(m_resource); }
+
+ wl_resource *resource() const { return m_resource; }
+
+ void add(int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint64_t modifier);
+ void create(wl_client *client, uint32_t bufferId, const QSize &size, uint32_t format, uint32_t flags);
+
+ static void destroy(wl_client *client, wl_resource *resource);
+ static void add(wl_client *client, wl_resource *resource, int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo);
+ static void create(wl_client *client, wl_resource *resource, int width, int height, uint32_t format, uint32_t flags);
+ static void createImmed(wl_client *client, wl_resource *resource, uint32_t new_id, int width, int height, uint32_t format, uint32_t flags);
+
+private:
+ static const struct zwp_linux_buffer_params_v1_interface s_interface;
+
+ wl_resource *m_resource;
+ LinuxDmabufUnstableV1Interface *m_dmabufInterface;
+ std::array m_planes;
+ size_t m_planeCount = 0;
+ bool m_bufferCreated = false;
+};
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct zwp_linux_buffer_params_v1_interface LinuxDmabufParams::s_interface = {
+ destroy,
+ add,
+ create,
+ createImmed
+};
+#endif
+
+
+LinuxDmabufParams::LinuxDmabufParams(LinuxDmabufUnstableV1Interface *dmabufInterface, wl_client *client, uint32_t version, uint32_t id)
+ : m_dmabufInterface(dmabufInterface)
+{
+ m_resource = wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, version, id);
+ if (!m_resource) {
+ return;
+ }
+
+ wl_resource_set_implementation(m_resource, &s_interface, this,
+ [](wl_resource *resource) {
+ delete static_cast(wl_resource_get_user_data(resource));
+ });
+
+ for (auto &plane : m_planes) {
+ plane.fd = -1;
+ plane.offset = 0;
+ plane.stride = 0;
+ plane.modifier = 0;
+ }
+}
+
+
+LinuxDmabufParams::~LinuxDmabufParams()
+{
+ // Close the file descriptors
+ for (auto &plane : m_planes) {
+ if (plane.fd != -1) {
+ ::close(plane.fd);
+ }
+ }
+}
+
+
+void LinuxDmabufParams::create(wl_client *client, uint32_t bufferId, const QSize &size, uint32_t format, uint32_t flags)
+{
+ // Validate the parameters
+ // -----------------------
+ const uint32_t width = size.width();
+ const uint32_t height = size.height();
+
+ if (m_bufferCreated) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+ "params was already used to create a wl_buffer");
+ return;
+ }
+
+ if (m_planeCount == 0) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "no dmabuf has been added to the params");
+ return;
+ }
+
+ // Check for holes in the dmabufs set (e.g. [0, 1, 3])
+ for (uint32_t i = 0; i < m_planeCount; i++) {
+ if (m_planes[i].fd != -1)
+ continue;
+
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+ "no dmabuf has been added for plane %i", i);
+ return;
+ }
+
+ if (width < 1 || height < 1) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
+ "invalid width %d or height %d", width, height);
+ return;
+ }
+
+ for (uint32_t i = 0; i < m_planeCount; i++) {
+ auto &plane = m_planes[i];
+
+ if (uint64_t(plane.offset) + plane.stride > UINT32_MAX) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "size overflow for plane %i", i);
+ return;
+ }
+
+ if (i == 0 && uint64_t(plane.offset) + plane.stride * height > UINT32_MAX) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "size overflow for plane %i", i);
+ return;
+ }
+
+ // Don't report an error as it might be caused by the kernel not supporting seeking on dmabuf
+ off_t size = ::lseek(plane.fd, 0, SEEK_END);
+ if (size == -1)
+ continue;
+
+ if (plane.offset >= size) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "invalid offset %i for plane %i",
+ plane.offset, i);
+ return;
+ }
+
+ if (plane.offset + plane.stride > size) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "invalid stride %i for plane %i",
+ plane.stride, i);
+ return;
+ }
+
+ // Only valid for first plane as other planes might be
+ // sub-sampled according to fourcc format
+ if (i == 0 && plane.offset + plane.stride * height > size) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+ "invalid buffer stride or height for plane %i", i);
+ return;
+ }
+ }
+
+
+ // Import the buffer
+ // -----------------
+ QVector planes;
+ planes.reserve(m_planeCount);
+ for (uint32_t i = 0; i < m_planeCount; i++)
+ planes << m_planes[i];
+
+ LinuxDmabuf::Buffer *buffer = m_dmabufInterface->bridge()->importBuffer(planes, format, size, (LinuxDmabuf::Flags) flags);
+ if (buffer) {
+ // The buffer has ownership of the file descriptors now
+ for (auto &plane : m_planes) {
+ plane.fd = -1;
+ }
+
+ wl_resource *resource = wl_resource_create(client, &wl_buffer_interface, 1, bufferId);
+ if (!resource ) {
+ postNoMemory();
+ delete buffer;
+ return;
+ }
+
+ wl_resource_set_implementation(resource, m_dmabufInterface->bufferImplementation(), buffer,
+ [](wl_resource *resource) { // Destructor
+ delete static_cast(wl_resource_get_user_data(resource));
+ });
+
+ // XXX Do we need this?
+ //buffer->setResource(resource);
+
+ // Send a 'created' event when the request is not for an immediate import, i.e. bufferId is zero
+ if (bufferId == 0) {
+ zwp_linux_buffer_params_v1_send_created(m_resource, resource);
+ }
+
+ m_bufferCreated = true;
+ } else {
+ if (bufferId == 0) {
+ zwp_linux_buffer_params_v1_send_failed(m_resource);
+ } else {
+ // since the behavior is left implementation defined by the
+ // protocol in case of create_immed failure due to an unknown cause,
+ // we choose to treat it as a fatal error and immediately kill the
+ // client instead of creating an invalid handle and waiting for it
+ // to be used.
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
+ "importing the supplied dmabufs failed");
+ }
+ }
+}
+
+
+void LinuxDmabufParams::add(int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint64_t modifier)
+{
+ if (m_bufferCreated) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+ "params was already used to create a wl_buffer");
+ ::close(fd);
+ return;
+ }
+
+ if (plane_idx >= m_planes.size()) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
+ "plane index %u is too high", plane_idx);
+ ::close(fd);
+ return;
+ }
+
+ auto &plane = m_planes[plane_idx];
+
+ if (plane.fd != -1) {
+ wl_resource_post_error(m_resource,
+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
+ "a dmabuf has already been added for plane %u",
+ plane_idx);
+ ::close(fd);
+ return;
+ }
+
+ plane.fd = fd;
+ plane.offset = offset;
+ plane.stride = stride;
+ plane.modifier = modifier;
+
+ m_planeCount++;
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+void LinuxDmabufParams::destroy(wl_client *client, wl_resource *resource)
+{
+ Q_UNUSED(client)
+ wl_resource_destroy(resource);
+}
+
+
+void LinuxDmabufParams::add(wl_client *client, wl_resource *resource,
+ int fd, uint32_t plane_idx,
+ uint32_t offset, uint32_t stride,
+ uint32_t modifier_hi, uint32_t modifier_lo)
+{
+ Q_UNUSED(client)
+
+ LinuxDmabufParams *params = static_cast(wl_resource_get_user_data(resource));
+ assert(params->m_resource == resource);
+ params->add(fd, plane_idx, offset, stride, (uint64_t(modifier_hi) << 32) | modifier_lo);
+}
+
+
+void LinuxDmabufParams::create(wl_client *client, wl_resource *resource,
+ int width, int height, uint32_t format, uint32_t flags)
+{
+ Q_UNUSED(client)
+
+ LinuxDmabufParams *params = static_cast(wl_resource_get_user_data(resource));
+ assert(params->m_resource == resource);
+ params->create(client, 0, QSize(width, height), format, flags);
+}
+
+
+void LinuxDmabufParams::createImmed(wl_client *client, wl_resource *resource,
+ uint32_t new_id, int width, int height,
+ uint32_t format, uint32_t flags)
+{
+ Q_UNUSED(client)
+
+ LinuxDmabufParams *params = static_cast(wl_resource_get_user_data(resource));
+ assert(params->m_resource == resource);
+ params->create(client, new_id, QSize(width, height), format, flags);
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+class LinuxDmabufUnstableV1Interface::Private : public Global::Private
+{
+public:
+ Private(LinuxDmabufUnstableV1Interface *q, Display *display);
+ ~Private();
+
+ static const struct wl_buffer_interface *bufferImplementation() { return &s_bufferImplementation; }
+ LinuxDmabufUnstableV1Interface::Bridge *bridge;
+ LinuxDmabufUnstableV1Interface * const q;
+ static const uint32_t s_version;
+
+ void bind(wl_client *client, uint32_t version, uint32_t id) override final;
+ void createParams(wl_client *client, wl_resource *resource, uint32_t id);
+
+ static void unbind(wl_client *client, wl_resource *resource);
+ static void createParamsCallback(wl_client *client, wl_resource *resource, uint32_t id);
+
+private:
+ static const struct zwp_linux_dmabuf_v1_interface s_implementation;
+ static const struct wl_buffer_interface s_bufferImplementation;
+};
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+const struct zwp_linux_dmabuf_v1_interface LinuxDmabufUnstableV1Interface::Private::s_implementation = {
+ [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); }, // unbind
+ createParamsCallback
+};
+
+
+const struct wl_buffer_interface LinuxDmabufUnstableV1Interface::Private::s_bufferImplementation = {
+ [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); } // destroy
+};
+
+const uint32_t LinuxDmabufUnstableV1Interface::Private::s_version = 3;
+#endif
+
+
+LinuxDmabufUnstableV1Interface::Private::Private(LinuxDmabufUnstableV1Interface *q, Display *display)
+ : Global::Private(display, &zwp_linux_dmabuf_v1_interface, s_version),
+ q(q)
+{
+}
+
+
+LinuxDmabufUnstableV1Interface::Private::~Private()
+{
+}
+
+
+void LinuxDmabufUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
+{
+ wl_resource *resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, std::min(s_version, version), id);
+ if (!resource) {
+ wl_client_post_no_memory(client);
+ return;
+ }
+
+ wl_resource_set_implementation(resource, &s_implementation, this, nullptr);
+
+ // Send formats & modifiers
+ // ------------------------
+ const QVector formats = bridge->supportedFormats();
+ for (uint32_t format : formats) {
+ QVector modifiers = bridge->supportedModifiers(format);
+ if (modifiers.isEmpty()) {
+ modifiers << DRM_FORMAT_MOD_INVALID;
+ }
+
+ for (uint64_t modifier : qAsConst(modifiers)) {
+ if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
+ const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
+ const uint32_t modifier_hi = modifier >> 32;
+ zwp_linux_dmabuf_v1_send_modifier(resource, format, modifier_hi, modifier_lo);
+ } else if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) {
+ zwp_linux_dmabuf_v1_send_format(resource, format);
+ }
+ }
+ }
+}
+
+
+void LinuxDmabufUnstableV1Interface::Private::createParams(wl_client *client, wl_resource *resource, uint32_t id)
+{
+ LinuxDmabufParams *params = new LinuxDmabufParams(q, client, wl_resource_get_version(resource), id);
+ if (!params->resource()) {
+ wl_resource_post_no_memory(resource);
+ delete params;
+ }
+}
+
+
+void LinuxDmabufUnstableV1Interface::Private::createParamsCallback(wl_client *client, wl_resource *resource, uint32_t id)
+{
+ LinuxDmabufUnstableV1Interface::Private *global = static_cast(wl_resource_get_user_data(resource));
+ global->createParams(client, resource, id);
+}
+
+
+
+// --------------------------------------------------------------------
+
+
+
+LinuxDmabufUnstableV1Interface::LinuxDmabufUnstableV1Interface(Display *display, QObject *parent)
+ : Global(new Private(this, display), parent)
+{
+}
+
+
+LinuxDmabufUnstableV1Interface::~LinuxDmabufUnstableV1Interface()
+{
+}
+
+
+void LinuxDmabufUnstableV1Interface::setBridge(LinuxDmabufUnstableV1Interface::Bridge *bridge)
+{
+ d_func()->bridge = bridge;
+}
+
+
+LinuxDmabufUnstableV1Interface::Bridge *LinuxDmabufUnstableV1Interface::bridge() const
+{
+ return d_func()->bridge;
+}
+
+
+const struct wl_buffer_interface *LinuxDmabufUnstableV1Interface::bufferImplementation()
+{
+ return LinuxDmabufUnstableV1Interface::Private::bufferImplementation();
+}
+
+
+LinuxDmabufUnstableV1Interface::Private *LinuxDmabufUnstableV1Interface::d_func() const
+{
+ return reinterpret_cast(d.data());
+}
+
+
+} // namespace Server
+} // namespace Wayland