10 #include "linuxdmabuf_v1_interface.h" 12 #include "drm_fourcc.h" 14 #include "wayland-linux-dmabuf-unstable-v1-server-protocol.h" 15 #include "wayland-server-protocol.h" 29 class LinuxDmabufBuffer::Private
32 Private(LinuxDmabufBuffer *_q) : q(_q) {
35 virtual ~Private() =
default;
37 virtual uint32_t
format()
const = 0;
43 LinuxDmabufBuffer::LinuxDmabufBuffer()
57 class LinuxDmabufUnstableV1Buffer::Private : LinuxDmabufBuffer::Private
60 Private(LinuxDmabufUnstableV1Buffer *_q)
61 : LinuxDmabufBuffer::Private(_q)
65 ~Private()
override =
default;
67 uint32_t
format()
const override {
77 LinuxDmabufUnstableV1Buffer *q;
80 LinuxDmabufUnstableV1Buffer::LinuxDmabufUnstableV1Buffer(uint32_t
format,
const QSize &
size)
82 , d(
new LinuxDmabufUnstableV1Buffer::Private(
this))
90 class V1Iface::Private :
public Global::Private
93 Private(V1Iface *q,
Display *display);
96 static const struct wl_buffer_interface *bufferImplementation() {
return &s_bufferImplementation; }
100 static const uint32_t s_version;
102 void bind(wl_client *client, uint32_t version, uint32_t
id)
override final;
103 void createParams(wl_client *client, wl_resource *resource, uint32_t
id);
105 static void unbind(wl_client *client, wl_resource *resource);
106 static void createParamsCallback(wl_client *client, wl_resource *resource, uint32_t
id);
112 Params(V1Iface::Private *dmabufInterface, wl_client *client, uint32_t version, uint32_t
id);
115 void postNoMemory() { wl_resource_post_no_memory(m_resource); }
117 wl_resource *resource()
const {
return m_resource; }
119 void add(
int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint64_t modifier);
120 void create(wl_client *client, uint32_t bufferId,
const QSize &size, uint32_t format, uint32_t flags);
122 static void destroy(wl_client *client, wl_resource *resource);
123 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);
124 static void create(wl_client *client, wl_resource *resource,
int width,
int height, uint32_t format, uint32_t flags);
125 static void createImmed(wl_client *client, wl_resource *resource, uint32_t new_id,
int width,
int height, uint32_t format, uint32_t flags);
128 static const struct zwp_linux_buffer_params_v1_interface s_interface;
130 wl_resource *m_resource;
131 V1Iface::Private *m_dmabufInterface;
132 std::array<V1Iface::Plane, 4> m_planes;
133 size_t m_planeCount = 0;
134 bool m_createRequested =
false;
137 static const struct zwp_linux_dmabuf_v1_interface s_implementation;
138 static const struct wl_buffer_interface s_bufferImplementation;
141 void V1Iface::Private::Params::create(wl_client *client, wl_resource *resource,
142 int width,
int height, uint32_t format, uint32_t flags)
146 V1Iface::Private::Params *params =
static_cast<V1Iface::Private::Params *
>(wl_resource_get_user_data(resource));
147 assert(params->m_resource == resource);
148 params->create(client, 0,
QSize(width, height), format, flags);
151 void V1Iface::Private::Params::createImmed(wl_client *client, wl_resource *resource,
152 uint32_t new_id,
int width,
int height,
153 uint32_t format, uint32_t flags)
157 V1Iface::Private::Params *params =
static_cast<V1Iface::Private::Params *
>(wl_resource_get_user_data(resource));
158 assert(params->m_resource == resource);
159 params->create(client, new_id,
QSize(width, height), format, flags);
163 const struct zwp_linux_dmabuf_v1_interface V1Iface::Private::s_implementation = {
164 [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); },
168 const struct wl_buffer_interface V1Iface::Private::s_bufferImplementation = {
169 [](wl_client *, wl_resource *resource) { wl_resource_destroy(resource); }
173 const struct zwp_linux_buffer_params_v1_interface V1Iface::Private::Params::s_interface = {
181 V1Iface::Private::Params::Params(V1Iface::Private *dmabufInterface, wl_client *client, uint32_t version, uint32_t
id)
182 : m_dmabufInterface(dmabufInterface)
184 m_resource = wl_resource_create(client, &zwp_linux_buffer_params_v1_interface, version,
id);
189 wl_resource_set_implementation(m_resource, &s_interface,
this,
190 [](wl_resource *resource) {
191 delete static_cast<V1Iface::Private::Params *
>(wl_resource_get_user_data(resource));
194 for (
auto &plane : m_planes) {
202 V1Iface::Private::Params::~Params()
205 for (
auto &plane : m_planes) {
206 if (plane.fd != -1) {
212 void V1Iface::Private::Params::create(wl_client *client, uint32_t bufferId,
const QSize &size, uint32_t format, uint32_t flags)
216 const uint32_t width = size.
width();
217 const uint32_t height = size.
height();
219 if (m_createRequested) {
220 wl_resource_post_error(m_resource,
221 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
222 "params was already used to create a wl_buffer");
225 m_createRequested =
true;
227 if (m_planeCount == 0) {
228 wl_resource_post_error(m_resource,
229 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
230 "no dmabuf has been added to the params");
235 for (uint32_t i = 0; i < m_planeCount; i++) {
236 if (m_planes[i].fd != -1)
239 wl_resource_post_error(m_resource,
240 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
241 "no dmabuf has been added for plane %i", i);
245 if (width < 1 || height < 1) {
246 wl_resource_post_error(m_resource,
247 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
248 "invalid width %d or height %d", width, height);
252 for (uint32_t i = 0; i < m_planeCount; i++) {
253 auto &plane = m_planes[i];
255 if (uint64_t(plane.offset) + plane.stride > UINT32_MAX) {
256 wl_resource_post_error(m_resource,
257 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
258 "size overflow for plane %i", i);
262 if (i == 0 && uint64_t(plane.offset) + plane.stride * height > UINT32_MAX) {
263 wl_resource_post_error(m_resource,
264 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
265 "size overflow for plane %i", i);
270 off_t size = ::lseek(plane.fd, 0, SEEK_END);
274 if (plane.offset >= size) {
275 wl_resource_post_error(m_resource,
276 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
277 "invalid offset %i for plane %i",
282 if (plane.offset + plane.stride > size) {
283 wl_resource_post_error(m_resource,
284 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
285 "invalid stride %i for plane %i",
292 if (i == 0 && plane.offset + plane.stride * height > size) {
293 wl_resource_post_error(m_resource,
294 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
295 "invalid buffer stride or height for plane %i", i);
304 for (uint32_t i = 0; i < m_planeCount; i++)
305 planes << m_planes[i];
307 LinuxDmabufUnstableV1Buffer *buffer = m_dmabufInterface->impl->importBuffer(planes,
313 for (
auto &plane : m_planes) {
317 wl_resource *resource = wl_resource_create(client, &wl_buffer_interface, 1, bufferId);
324 wl_resource_set_implementation(resource, m_dmabufInterface->q->bufferImplementation(), buffer,
325 [](wl_resource *resource) {
326 delete static_cast<LinuxDmabufUnstableV1Buffer *
>(wl_resource_get_user_data(resource));
334 zwp_linux_buffer_params_v1_send_created(m_resource, resource);
338 zwp_linux_buffer_params_v1_send_failed(m_resource);
345 wl_resource_post_error(m_resource,
346 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
347 "importing the supplied dmabufs failed");
352 void V1Iface::Private::Params::add(
int fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint64_t modifier)
354 if (m_createRequested) {
355 wl_resource_post_error(m_resource,
356 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
357 "params was already used to create a wl_buffer");
362 if (plane_idx >= m_planes.size()) {
363 wl_resource_post_error(m_resource,
364 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
365 "plane index %u is too high", plane_idx);
370 auto &plane = m_planes[plane_idx];
372 if (plane.fd != -1) {
373 wl_resource_post_error(m_resource,
374 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
375 "a dmabuf has already been added for plane %u",
382 plane.offset = offset;
383 plane.stride = stride;
384 plane.modifier = modifier;
389 void V1Iface::Private::Params::destroy(wl_client *client, wl_resource *resource)
392 wl_resource_destroy(resource);
395 void V1Iface::Private::Params::add(wl_client *client, wl_resource *resource,
396 int fd, uint32_t plane_idx,
397 uint32_t offset, uint32_t stride,
398 uint32_t modifier_hi, uint32_t modifier_lo)
402 V1Iface::Private::Params *params =
static_cast<V1Iface::Private::Params *
>(wl_resource_get_user_data(resource));
403 assert(params->m_resource == resource);
404 params->add(fd, plane_idx, offset, stride, (uint64_t(modifier_hi) << 32) | modifier_lo);
407 const uint32_t V1Iface::Private::s_version = 3;
410 V1Iface::Private::Private(V1Iface *q,
Display *display)
411 : Global::Private(display, &zwp_linux_dmabuf_v1_interface, s_version),
416 V1Iface::Private::~Private() =
default;
418 void V1Iface::Private::bind(wl_client *client, uint32_t version, uint32_t
id)
420 wl_resource *resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface, std::min(s_version, version),
id);
422 wl_client_post_no_memory(client);
426 wl_resource_set_implementation(resource, &s_implementation,
this,
nullptr);
432 while (it != supportedFormatsWithModifiers.
constEnd()) {
435 modifiers << DRM_FORMAT_MOD_INVALID;
438 for (uint64_t modifier : qAsConst(modifiers)) {
439 if (version >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
440 const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
441 const uint32_t modifier_hi = modifier >> 32;
442 zwp_linux_dmabuf_v1_send_modifier(resource, it.
key(), modifier_hi, modifier_lo);
443 }
else if (modifier == DRM_FORMAT_MOD_LINEAR || modifier == DRM_FORMAT_MOD_INVALID) {
444 zwp_linux_dmabuf_v1_send_format(resource, it.
key());
451 void V1Iface::Private::createParams(wl_client *client, wl_resource *resource, uint32_t
id)
453 Params *params =
new Params(
this, client, wl_resource_get_version(resource),
id);
454 if (!params->resource()) {
455 wl_resource_post_no_memory(resource);
460 void V1Iface::Private::createParamsCallback(wl_client *client, wl_resource *resource, uint32_t
id)
462 V1Iface::Private *global =
static_cast<V1Iface::Private *
>(wl_resource_get_user_data(resource));
463 global->createParams(client, resource,
id);
467 V1Iface::LinuxDmabufUnstableV1Interface(
Display *display,
QObject *parent)
468 :
Global(
new Private(
this, display), parent)
476 d_func()->impl = impl;
481 d_func()->supportedFormatsWithModifiers =
set;
484 const struct wl_buffer_interface *V1Iface::bufferImplementation()
486 return V1Iface::Private::bufferImplementation();
489 V1Iface::Private *V1Iface::d_func()
const 491 return reinterpret_cast<Private*
>(d.data());
virtual ~LinuxDmabufUnstableV1Interface()
Destroys the LinuxDmabufUnstableV1Interface.
const Key key(const T &value) const const
Represents the global zpw_linux_dmabuf_v1 interface.
QSize size() const
Returns the size of the buffer.
void setImpl(Impl *impl)
Sets the compositor implementation for the dmabuf interface.
QHash::const_iterator constEnd() const const
Class holding the Wayland server display loop.
The Iface class provides an interface from the LinuxDmabufInterface into the compositor.
const T value(const Key &key) const const
Base class for all Globals.
QHash::const_iterator constBegin() const const
bool isEmpty() const const
The base class for linux-dmabuf buffers.
uint32_t format() const
Returns the DRM format code for the buffer.