7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
10#include <drm_fourcc.h>
16LinuxDmabuf::LinuxDmabuf(wl_display *display, LinuxDmabufClientBufferIntegration *clientBufferIntegration)
17 : zwp_linux_dmabuf_v1(display, 3 )
18 , m_clientBufferIntegration(clientBufferIntegration)
24 Q_ASSERT(resourceMap().isEmpty());
25 m_modifiers = modifiers;
30 for (
auto it = m_modifiers.constBegin(); it != m_modifiers.constEnd(); ++it) {
31 auto format = it.key();
32 auto modifiers = it.value();
34 if (modifiers.isEmpty())
36 for (
const auto &modifier : std::as_const(modifiers)) {
37 if (resource->version() >= ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION) {
38 const uint32_t modifier_lo = modifier & 0xFFFFFFFF;
39 const uint32_t modifier_hi = modifier >> 32;
40 send_modifier(resource->handle, format, modifier_hi, modifier_lo);
42 send_format(resource->handle, format);
50 wl_resource *r = wl_resource_create(resource->client(), &zwp_linux_buffer_params_v1_interface,
51 wl_resource_get_version(resource->handle), params_id);
57 , m_clientBufferIntegration(clientBufferIntegration)
63 for (
auto it = m_planes.begin(); it != m_planes.end(); ++it) {
64 if (it.value().fd != -1)
70bool LinuxDmabufParams::handleCreateParams(Resource *resource,
int width,
int height, uint format, uint flags)
73 wl_resource_post_error(resource->handle,
74 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
75 "Params already used");
79 if (width <= 0 || height <= 0) {
80 wl_resource_post_error(resource->handle,
81 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
82 "Invalid dimensions in create request");
86 if (m_planes.isEmpty()) {
87 wl_resource_post_error(resource->handle,
88 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
89 "Cannot create a buffer with no planes");
94 auto planeIds = m_planes.keys();
95 std::sort(planeIds.begin(), planeIds.end());
96 for (
int i = 0; i < planeIds.size(); ++i) {
97 if (uint(i) != planeIds[i]) {
98 wl_resource_post_error(resource->handle,
99 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
100 "No dmabuf parameters provided for plane %i", i);
106 for (
auto it = m_planes.constBegin(); it != m_planes.constEnd(); ++it) {
107 const auto planeId = it.key();
108 const auto plane = it.value();
109 if (
static_cast<int64_t>(plane.offset) + plane.stride > UINT32_MAX) {
110 wl_resource_post_error(resource->handle,
111 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
112 "Size overflow for plane %i",
116 if (planeId == 0 &&
static_cast<int64_t>(plane.offset) + plane.stride *
static_cast<int64_t>(height) > UINT32_MAX) {
117 wl_resource_post_error(resource->handle,
118 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
119 "Size overflow for plane %i",
125 off_t size = lseek(plane.fd, 0, SEEK_END);
127 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Seeking is not supported";
131 if (
static_cast<int64_t>(plane.offset) >= size) {
132 wl_resource_post_error(resource->handle,
133 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
134 "Invalid offset %i for plane %i",
135 plane.offset, planeId);
139 if (
static_cast<int64_t>(plane.offset) +
static_cast<int64_t>(plane.stride) > size) {
140 wl_resource_post_error(resource->handle,
141 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
142 "Invalid stride %i for plane %i",
143 plane.stride, planeId);
148 if (planeId == 0 && plane.offset +
static_cast<int64_t>(plane.stride) * height > size) {
149 wl_resource_post_error(resource->handle,
150 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
151 "Invalid buffer stride or height for plane %i", planeId);
156 m_size = QSize(width, height);
157 m_drmFormat = format;
166 wl_resource_destroy(resource->handle);
177 const uint64_t modifiers = (
static_cast<uint64_t>(modifier_hi) << 32) | modifier_lo;
179 wl_resource_post_error(resource->handle,
180 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
181 "Plane index %i is out of bounds", plane_idx);
184 if (m_planes.contains(plane_idx)) {
185 wl_resource_post_error(resource->handle,
186 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
187 "Plane already set");
195 m_planes.insert(plane_idx, plane);
200 if (!handleCreateParams(resource, width, height, format, flags))
204 buffer->m_size = m_size;
205 buffer->m_flags = m_flags;
206 buffer->m_drmFormat = m_drmFormat;
207 buffer->m_planesNumber = m_planes.size();
208 for (
auto it = m_planes.begin(); it != m_planes.end(); ++it) {
209 buffer->m_planes[it.key()] = it.value();
213 if (!m_clientBufferIntegration
->importBuffer(buffer->resource()->handle
, buffer
)) {
214 send_failed(resource->handle);
216 send_created(resource->handle, buffer->resource()->handle);
222 if (!handleCreateParams(resource, width, height, format, flags))
225 auto *buffer =
new LinuxDmabufWlBuffer(resource->client(), m_clientBufferIntegration, buffer_id);
226 buffer->m_size = m_size;
227 buffer->m_flags = m_flags;
228 buffer->m_drmFormat = m_drmFormat;
229 buffer->m_planesNumber = m_planes.size();
230 for (
auto it = m_planes.begin(); it != m_planes.end(); ++it) {
231 buffer->m_planes[it.key()] = it.value();
235 if (!m_clientBufferIntegration
->importBuffer(buffer->resource()->handle
, buffer
)) {
239 wl_resource_post_error(resource->handle,
240 ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER,
241 "Import of the provided DMA buffer failed");
248 , m_clientBufferIntegration(clientBufferIntegration)
262 wl_resource_destroy(resource->handle);
267 QMutexLocker locker(&m_texturesLock);
269 for (uint32_t i = 0; i < m_planesNumber; ++i) {
270 if (m_textures[i] !=
nullptr) {
271 QtWayland::QWaylandTextureOrphanage::instance()->admitTexture(m_textures[i],
272 m_texturesContext[i]);
273 m_textures[i] =
nullptr;
274 m_texturesContext[i] =
nullptr;
275 QObject::disconnect(m_texturesAboutToBeDestroyedConnection[i]);
276 m_texturesAboutToBeDestroyedConnection[i] = QMetaObject::Connection();
278 if (m_eglImages[i] != EGL_NO_IMAGE_KHR) {
279 m_clientBufferIntegration->deleteImage(m_eglImages[i]);
280 m_eglImages[i] = EGL_NO_IMAGE_KHR;
282 if (m_planes[i].fd != -1)
283 close(m_planes[i].fd);
291 Q_ASSERT(plane < m_planesNumber);
292 Q_ASSERT(m_eglImages.at(plane) == EGL_NO_IMAGE_KHR);
293 m_eglImages[plane] = image;
298 QMutexLocker locker(&m_texturesLock);
300 Q_ASSERT(plane < m_planesNumber);
301 Q_ASSERT(m_textures.at(plane) ==
nullptr);
302 Q_ASSERT(QOpenGLContext::currentContext());
303 m_textures[plane] = texture;
304 m_texturesContext[plane] = QOpenGLContext::currentContext();
306 m_texturesAboutToBeDestroyedConnection[plane] =
307 QObject::connect(m_texturesContext[plane], &QOpenGLContext::aboutToBeDestroyed,
308 m_texturesContext[plane], [
this, plane]() {
310 QMutexLocker locker(&
this->m_texturesLock);
314 if (
this->m_textures[plane] ==
nullptr)
317 delete this->m_textures[plane];
319 qCDebug(qLcWaylandCompositorHardwareIntegration)
321 <<
"texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
322 <<
"Pointer (now dead) was:" << (
void*)(
this->m_textures[plane])
323 <<
" Associated context (about to die too) is: " << (
void*)(
this->m_texturesContext[plane]);
325 this->m_textures[plane] =
nullptr;
326 this->m_texturesContext[plane] =
nullptr;
328 QObject::disconnect(
this->m_texturesAboutToBeDestroyedConnection[plane]);
329 this->m_texturesAboutToBeDestroyedConnection[plane] = QMetaObject::Connection();
331 }, Qt::DirectConnection);
bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer)
void removeBuffer(wl_resource *resource)
void zwp_linux_buffer_params_v1_create_immed(Resource *resource, uint32_t buffer_id, int32_t width, int32_t height, uint32_t format, uint32_t flags) override
~LinuxDmabufParams() override
LinuxDmabufParams(LinuxDmabufClientBufferIntegration *clientBufferIntegration, wl_resource *resource)
void zwp_linux_buffer_params_v1_create(Resource *resource, int32_t width, int32_t height, uint32_t format, uint32_t flags) override
void zwp_linux_buffer_params_v1_destroy(Resource *resource) override
void zwp_linux_buffer_params_v1_add(Resource *resource, int32_t fd, uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, uint32_t modifier_lo) override
void zwp_linux_buffer_params_v1_destroy_resource(Resource *resource) override
void initTexture(uint32_t plane, QOpenGLTexture *texture)
void initImage(uint32_t plane, EGLImageKHR image)
void buffer_destroy(Resource *resource) override
~LinuxDmabufWlBuffer() override
LinuxDmabufWlBuffer(::wl_client *client, LinuxDmabufClientBufferIntegration *clientBufferIntegration, uint id=0)
static const uint32_t MaxDmabufPlanes
void buffer_destroy_resource(Resource *resource) override
void zwp_linux_dmabuf_v1_bind_resource(Resource *resource) override
void setSupportedModifiers(const QHash< uint32_t, QList< uint64_t > > &modifiers)
void zwp_linux_dmabuf_v1_create_params(Resource *resource, uint32_t params_id) override
#define DRM_FORMAT_MOD_LINEAR
#define DRM_FORMAT_MOD_INVALID