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 ${WaylandProtocols_DATADIR}/unstable/linux-dmabuf/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 @@ -33,7 +33,7 @@ namespace Server { class SurfaceInterface; - +class LinuxDmabufBuffer; /** * @brief Reference counted representation of a Wayland buffer on Server side. @@ -104,6 +104,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 LinuxDmabufBuffer when the buffer is a dmabuf buffer, and nullptr otherwise. + */ + LinuxDmabufBuffer *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; + LinuxDmabufBuffer *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; } +LinuxDmabufBuffer *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,183 @@ +/******************************************************************** +Copyright © 2019 Roman Gilg +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 "global.h" +#include "resource.h" + +#include + +#include +#include +#include + +struct wl_buffer_interface; + +namespace KWayland +{ +namespace Server +{ +class BufferInterface; + +/** + * The base class for linux-dmabuf buffers + * + * Compositors should reimplement this class to store objects specific + * to the underlying graphics stack. + */ +class KWAYLANDSERVER_EXPORT LinuxDmabufBuffer +{ +public: + LinuxDmabufBuffer(); + virtual ~LinuxDmabufBuffer() = default; + + /** + * Returns the DRM format code for the buffer. + */ + uint32_t format() const; + /** + * Returns the size of the buffer. + */ + QSize size() const; + +private: + class Private; + Private *d; + + friend class LinuxDmabufUnstableV1Buffer; +}; + +class KWAYLANDSERVER_EXPORT LinuxDmabufUnstableV1Buffer : public LinuxDmabufBuffer +{ +public: + /** + * Creates a new Buffer. + */ + LinuxDmabufUnstableV1Buffer(uint32_t format, const QSize &size); + + /** + * Destroys the Buffer. + */ + virtual ~LinuxDmabufUnstableV1Buffer() = default; + +private: + class Private; + Private *d; +}; + +/** + * 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: + 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 Iface class provides an interface from the LinuxDmabufInterface into the compositor + */ + class Impl { + public: + Impl() = default; + virtual ~Impl() = default; + + /** + * Imports a linux-dmabuf buffer into the compositor. + * + * The parent LinuxDmabufUnstableV1Interface class takes ownership of returned + * buffer objects. + * + * In return 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 LinuxDmabufUnstableV1Buffer *importBuffer(const QVector &planes, + uint32_t format, + const QSize &size, + Flags flags) = 0; + }; + + /** + * Destroys the LinuxDmabufUnstableV1Interface. + */ + virtual ~LinuxDmabufUnstableV1Interface(); + + /** + * Sets the compositor implementation for the dmabuf interface. + */ + void setImpl(Impl *impl); + + void setSupportedFormatsWithModifiers(QHash > set); + + /** + * Returns the LinuxDmabufInterface for the given resource. + **/ + static LinuxDmabufUnstableV1Interface *get(wl_resource *native); + +private: + /** + * @internal + */ + explicit LinuxDmabufUnstableV1Interface(Display *display, QObject *parent = nullptr); + + /** + * Returns a pointer to the wl_buffer implementation for imported dmabufs. + */ + static const struct wl_buffer_interface *bufferImplementation(); + + friend class Display; + friend class BufferInterface; + + class Private; + Private *d_func() const; +}; + +} +} + +Q_DECLARE_METATYPE(KWayland::Server::LinuxDmabufUnstableV1Interface*) +Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Server::LinuxDmabufUnstableV1Interface::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,513 @@ +/******************************************************************** +Copyright © 2019 Roman Gilg +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 "linuxdmabuf_v1_interface.h" + +#include "drm_fourcc.h" +#include "global_p.h" +#include "wayland-linux-dmabuf-unstable-v1-server-protocol.h" +#include "wayland-server-protocol.h" + +#include + +#include + +#include +#include +#include + +namespace KWayland +{ +namespace Server +{ + +class LinuxDmabufBuffer::Private +{ +public: + Private(LinuxDmabufBuffer *_q) : q(_q) { + q->d = this; + } + virtual ~Private() = default; + + virtual uint32_t format() const = 0; + virtual QSize size() const = 0; + + LinuxDmabufBuffer *q; +}; + +LinuxDmabufBuffer::LinuxDmabufBuffer() +{ +} + +uint32_t LinuxDmabufBuffer::format() const +{ + return d->format(); +} + +QSize LinuxDmabufBuffer::size() const +{ + return d->size(); +} + +class LinuxDmabufUnstableV1Buffer::Private : LinuxDmabufBuffer::Private +{ +public: + Private(LinuxDmabufUnstableV1Buffer *_q) + : LinuxDmabufBuffer::Private(_q) + , q(_q) + { + } + ~Private() override = default; + + uint32_t format() const override { + return m_format; + } + QSize size() const override { + return m_size; + } + + uint32_t m_format; + QSize m_size; + + LinuxDmabufUnstableV1Buffer *q; +}; + +LinuxDmabufUnstableV1Buffer::LinuxDmabufUnstableV1Buffer(uint32_t format, const QSize &size) + : LinuxDmabufBuffer() + , d(new LinuxDmabufUnstableV1Buffer::Private(this)) +{ + d->m_format = format; + d->m_size = size; +} + +typedef LinuxDmabufUnstableV1Interface V1Iface; + +class V1Iface::Private : public Global::Private +{ +public: + Private(V1Iface *q, Display *display); + ~Private(); + + static const struct wl_buffer_interface *bufferImplementation() { return &s_bufferImplementation; } + V1Iface::Impl *impl; + QHash > supportedFormatsWithModifiers; + V1Iface * 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: + class Params + { + public: + Params(V1Iface::Private *dmabufInterface, wl_client *client, uint32_t version, uint32_t id); + ~Params(); + + 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; + V1Iface::Private *m_dmabufInterface; + std::array m_planes; + size_t m_planeCount = 0; + bool m_createRequested = false; + }; + + static const struct zwp_linux_dmabuf_v1_interface s_implementation; + static const struct wl_buffer_interface s_bufferImplementation; +}; + +void V1Iface::Private::Params::create(wl_client *client, wl_resource *resource, + int width, int height, uint32_t format, uint32_t flags) +{ + Q_UNUSED(client) + + V1Iface::Private::Params *params = static_cast(wl_resource_get_user_data(resource)); + assert(params->m_resource == resource); + params->create(client, 0, QSize(width, height), format, flags); +} + +void V1Iface::Private::Params::createImmed(wl_client *client, wl_resource *resource, + uint32_t new_id, int width, int height, + uint32_t format, uint32_t flags) +{ + Q_UNUSED(client) + + V1Iface::Private::Params *params = static_cast(wl_resource_get_user_data(resource)); + assert(params->m_resource == resource); + params->create(client, new_id, QSize(width, height), format, flags); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zwp_linux_dmabuf_v1_interface V1Iface::Private::s_implementation = { + [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); }, // unbind + createParamsCallback +}; + +const struct wl_buffer_interface V1Iface::Private::s_bufferImplementation = { + [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); } // destroy +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zwp_linux_buffer_params_v1_interface V1Iface::Private::Params::s_interface = { + destroy, + add, + create, + createImmed +}; +#endif + +V1Iface::Private::Params::Params(V1Iface::Private *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; + } +} + +V1Iface::Private::Params::~Params() +{ + // Close the file descriptors + for (auto &plane : m_planes) { + if (plane.fd != -1) { + ::close(plane.fd); + } + } +} + +void V1Iface::Private::Params::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_createRequested) { + wl_resource_post_error(m_resource, + ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED, + "params was already used to create a wl_buffer"); + return; + } + m_createRequested = true; + + 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]; + + LinuxDmabufUnstableV1Buffer *buffer = m_dmabufInterface->impl->importBuffer(planes, + format, + size, + (V1Iface::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->q->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); + } + } 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 V1Iface::Private::Params::add(int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint64_t modifier) +{ + if (m_createRequested) { + 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 V1Iface::Private::Params::destroy(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + +void V1Iface::Private::Params::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) + + V1Iface::Private::Params *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); +} + +const uint32_t V1Iface::Private::s_version = 3; +#endif + +V1Iface::Private::Private(V1Iface *q, Display *display) + : Global::Private(display, &zwp_linux_dmabuf_v1_interface, s_version), + q(q) +{ +} + +V1Iface::Private::~Private() +{ + delete impl; +} + +void V1Iface::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 + // ------------------------ + + QHash>::const_iterator it = supportedFormatsWithModifiers.constBegin(); + while (it != supportedFormatsWithModifiers.constEnd()) { + QSet modifiers = it.value(); + 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, it.key(), modifier_hi, modifier_lo); + } else if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) { + zwp_linux_dmabuf_v1_send_format(resource, it.key()); + } + } + it++; + } +} + +void V1Iface::Private::createParams(wl_client *client, wl_resource *resource, uint32_t id) +{ + Params *params = new Params(this, client, wl_resource_get_version(resource), id); + if (!params->resource()) { + wl_resource_post_no_memory(resource); + delete params; + } +} + +void V1Iface::Private::createParamsCallback(wl_client *client, wl_resource *resource, uint32_t id) +{ + V1Iface::Private *global = static_cast(wl_resource_get_user_data(resource)); + global->createParams(client, resource, id); +} + + +V1Iface::LinuxDmabufUnstableV1Interface(Display *display, QObject *parent) + : Global(new Private(this, display), parent) +{ +} + +V1Iface::~LinuxDmabufUnstableV1Interface() = default; + +void V1Iface::setImpl(V1Iface::Impl *impl) +{ + d_func()->impl = impl; +} + +void V1Iface::setSupportedFormatsWithModifiers(QHash > set) +{ + d_func()->supportedFormatsWithModifiers = set; +} + +const struct wl_buffer_interface *V1Iface::bufferImplementation() +{ + return V1Iface::Private::bufferImplementation(); +} + +V1Iface::Private *V1Iface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +} +}