7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
9#include <QtWaylandCompositor/private/qwltextureorphanage_p.h>
10#include <qpa/qplatformnativeinterface.h>
11#include <QtOpenGL/QOpenGLTexture>
12#include <QtCore/QVarLengthArray>
13#include <QtGui/QGuiApplication>
14#include <QtGui/QOpenGLContext>
17#include <EGL/eglext.h>
19#include <drm_fourcc.h>
23static QWaylandBufferRef::BufferFormatEgl formatFromDrmFormat(EGLint format) {
25 case DRM_FORMAT_RGB332:
26 case DRM_FORMAT_BGR233:
27 case DRM_FORMAT_XRGB4444:
28 case DRM_FORMAT_XBGR4444:
29 case DRM_FORMAT_RGBX4444:
30 case DRM_FORMAT_BGRX4444:
31 case DRM_FORMAT_XRGB1555:
32 case DRM_FORMAT_XBGR1555:
33 case DRM_FORMAT_RGBX5551:
34 case DRM_FORMAT_BGRX5551:
35 case DRM_FORMAT_RGB565:
36 case DRM_FORMAT_BGR565:
37 case DRM_FORMAT_RGB888:
38 case DRM_FORMAT_BGR888:
39 case DRM_FORMAT_XRGB8888:
40 case DRM_FORMAT_XBGR8888:
41 case DRM_FORMAT_RGBX8888:
42 case DRM_FORMAT_BGRX8888:
43 case DRM_FORMAT_XRGB2101010:
44 case DRM_FORMAT_XBGR2101010:
45 case DRM_FORMAT_RGBX1010102:
46 case DRM_FORMAT_BGRX1010102:
47 return QWaylandBufferRef::BufferFormatEgl_RGB;
48 case DRM_FORMAT_ARGB4444:
49 case DRM_FORMAT_ABGR4444:
50 case DRM_FORMAT_RGBA4444:
51 case DRM_FORMAT_BGRA4444:
52 case DRM_FORMAT_ARGB1555:
53 case DRM_FORMAT_ABGR1555:
54 case DRM_FORMAT_RGBA5551:
55 case DRM_FORMAT_BGRA5551:
56 case DRM_FORMAT_ARGB8888:
57 case DRM_FORMAT_ABGR8888:
58 case DRM_FORMAT_RGBA8888:
59 case DRM_FORMAT_BGRA8888:
60 case DRM_FORMAT_ARGB2101010:
61 case DRM_FORMAT_ABGR2101010:
62 case DRM_FORMAT_RGBA1010102:
63 case DRM_FORMAT_BGRA1010102:
64 return QWaylandBufferRef::BufferFormatEgl_RGBA;
66 return QWaylandBufferRef::BufferFormatEgl_Y_XUXV;
68 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Buffer format" << Qt::hex << format <<
"not supported";
69 return QWaylandBufferRef::BufferFormatEgl_Null;
75 case QWaylandBufferRef::BufferFormatEgl_RGB:
76 return QOpenGLTexture::RGBFormat;
77 case QWaylandBufferRef::BufferFormatEgl_RGBA:
78 return QOpenGLTexture::RGBAFormat;
80 return QOpenGLTexture::NoFormat;
94 if (!gl_egl_image_target_texture_2d)
95 gl_egl_image_target_texture_2d =
reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress(
"glEGLImageTargetTexture2DOES"));
98 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
104 QVarLengthArray<EGLint, 6 + 10 * 4 + 1> attribs;
106 attribs.append(EGL_WIDTH);
107 attribs.append(dmabufBuffer->size().width());
108 attribs.append(EGL_HEIGHT);
109 attribs.append(dmabufBuffer->size().height());
110 attribs.append(EGL_LINUX_DRM_FOURCC_EXT);
113#define ADD_PLANE_ATTRIBS(plane_idx) {
114 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _FD_EXT);
115 attribs.append(dmabufBuffer->plane(plane_idx).fd);
116 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _OFFSET_EXT);
117 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).offset));
118 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _PITCH_EXT);
119 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).stride));
121 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_LO_EXT);
122 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers & 0xffffffff
));
123 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_HI_EXT);
124 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers >> 32
));
126}
142 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses invalid number of planes:" << dmabufBuffer->planesNumber();
146 attribs.append(EGL_NONE);
149 EGLImageKHR image = egl_create_image(m_eglDisplay,
151 EGL_LINUX_DMA_BUF_EXT,
152 (EGLClientBuffer)
nullptr,
153 attribs.constData());
155 if (image == EGL_NO_IMAGE_KHR) {
156 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image from" <<
157 dmabufBuffer->planesNumber() <<
"plane(s)";
172 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer for this format must provide" << conversion.inputPlanes
173 <<
"planes but only" << dmabufBuffer->planesNumber() <<
"received";
178 if (!gl_egl_image_target_texture_2d)
179 gl_egl_image_target_texture_2d =
reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress(
"glEGLImageTargetTexture2DOES"));
183 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
190 QVarLengthArray<EGLint, 17> attribs = {
191 EGL_WIDTH, dmabufBuffer->size().width() / plane
.widthDivisor,
193 EGL_LINUX_DRM_FOURCC_EXT, plane.format,
194 EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(plane
.planeIndex).fd,
195 EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(plane
.planeIndex).offset),
196 EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(plane
.planeIndex).stride),
197 EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(plane
.planeIndex).modifiers & 0xffffffff),
198 EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(plane
.planeIndex).modifiers >> 32),
203 EGLImageKHR image = egl_create_image(m_eglDisplay,
205 EGL_LINUX_DMA_BUF_EXT,
206 (EGLClientBuffer)
nullptr,
207 attribs.constData());
209 if (image == EGL_NO_IMAGE_KHR) {
210 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image for plane" << i;
222 firstPlane.format = DRM_FORMAT_GR88;
228 secondPlane.format = DRM_FORMAT_ARGB8888;
236 formatConversion
.plane[0] = firstPlane;
237 formatConversion
.plane[1] = secondPlane;
239 m_yuvFormats.insert(DRM_FORMAT_YUYV, formatConversion);
244 m_importedBuffers.clear();
246 if (egl_unbind_wayland_display !=
nullptr && m_displayBound) {
247 Q_ASSERT(m_wlDisplay !=
nullptr);
248 if (!egl_unbind_wayland_display(m_eglDisplay, m_wlDisplay))
249 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"eglUnbindWaylandDisplayWL failed";
255 m_linuxDmabuf.reset(
new LinuxDmabuf(display,
this));
257 const bool ignoreBindDisplay = !qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty() && qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").toInt() != 0;
260 egl_query_dmabuf_modifiers_ext =
reinterpret_cast<PFNEGLQUERYDMABUFMODIFIERSEXTPROC>(eglGetProcAddress(
"eglQueryDmaBufModifiersEXT"));
261 egl_query_dmabuf_formats_ext =
reinterpret_cast<PFNEGLQUERYDMABUFFORMATSEXTPROC>(eglGetProcAddress(
"eglQueryDmaBufFormatsEXT"));
262 if (!egl_query_dmabuf_modifiers_ext || !egl_query_dmabuf_formats_ext) {
263 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglQueryDmaBufModifiersEXT and eglQueryDmaBufFormatsEXT.";
267 egl_bind_wayland_display =
reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglBindWaylandDisplayWL"));
268 egl_unbind_wayland_display =
reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress(
"eglUnbindWaylandDisplayWL"));
269 if ((!egl_bind_wayland_display || !egl_unbind_wayland_display) && !ignoreBindDisplay) {
270 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.";
274 egl_create_image =
reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress(
"eglCreateImageKHR"));
275 egl_destroy_image =
reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>(eglGetProcAddress(
"eglDestroyImageKHR"));
276 if (!egl_create_image || !egl_destroy_image) {
277 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglCreateImageKHR and eglDestroyImageKHR.";
282 QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
283 if (!nativeInterface) {
284 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. No native platform interface available.";
288 m_eglDisplay = nativeInterface->nativeResourceForIntegration(
"EglDisplay");
290 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not get EglDisplay for window.";
294 const char *extensionString = eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
295 if (!extensionString || !strstr(extensionString,
"EGL_EXT_image_dma_buf_import")) {
296 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. There is no EGL_EXT_image_dma_buf_import extension.";
299 if (strstr(extensionString,
"EGL_EXT_image_dma_buf_import_modifiers"))
300 m_supportsDmabufModifiers =
true;
302 if (egl_bind_wayland_display && egl_unbind_wayland_display) {
303 m_displayBound = egl_bind_wayland_display(m_eglDisplay, display);
305 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Wayland display already bound by other client buffer integration.";
306 m_wlDisplay = display;
310 QHash<uint32_t, QList<uint64_t>> modifiers;
311 for (
const auto &format : supportedDrmFormats()) {
312 modifiers[format] = supportedDrmModifiers(format);
314 m_linuxDmabuf->setSupportedModifiers(modifiers);
319 if (!egl_query_dmabuf_formats_ext)
320 return QList<uint32_t>();
324 EGLBoolean success = egl_query_dmabuf_formats_ext(m_eglDisplay, 0,
nullptr, &count);
326 if (success && count > 0) {
327 QList<uint32_t> drmFormats(count);
328 if (egl_query_dmabuf_formats_ext(m_eglDisplay, count, (EGLint *) drmFormats.data(), &count))
332 return QList<uint32_t>();
337 if (!egl_query_dmabuf_modifiers_ext)
338 return QList<uint64_t>();
342 EGLBoolean success = egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, 0,
nullptr,
nullptr, &count);
344 if (success && count > 0) {
345 QList<uint64_t> modifiers(count);
346 if (egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, count, modifiers.data(),
nullptr, &count)) {
351 return QList<uint64_t>();
356 egl_destroy_image(m_eglDisplay, image);
361 auto it = m_importedBuffers.find(resource);
362 if (it != m_importedBuffers.end())
363 return new LinuxDmabufClientBuffer(
this, it.value()->resource()->handle, m_importedBuffers.value(resource));
370 if (m_importedBuffers.contains(resource)) {
371 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"buffer has already been added";
374 m_importedBuffers[resource] = linuxDmabufBuffer;
375 if (m_yuvFormats.contains(linuxDmabufBuffer->drmFormat()))
376 return initYuvTexture(linuxDmabufBuffer);
378 return initSimpleTexture(linuxDmabufBuffer);
383 m_importedBuffers.remove(resource);
387 wl_resource *bufferResource,
389 : ClientBuffer(bufferResource)
390 , m_integration(integration)
398 QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures();
403 QOpenGLTexture *texture = d->texture(plane);
405 const auto target =
static_cast<QOpenGLTexture::Target>(GL_TEXTURE_2D);
408 texture =
new QOpenGLTexture(target);
409 texture->setFormat(openGLFormatFromBufferFormat(formatFromDrmFormat(d->drmFormat())));
410 texture->setSize(d->size().width(), d->size().height());
412 d->initTexture(plane, texture);
415 if (m_textureDirty) {
416 m_textureDirty =
false;
418 glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
419 m_integration->gl_egl_image_target_texture_2d(target, d
->image(plane
));
426 m_integration->removeBuffer(m_buffer);
427 ClientBuffer::setDestroyed();
448 return (d->flags() & QtWaylandServer::zwp_linux_buffer_params_v1::flags_y_invert) ? QWaylandSurface::OriginBottomLeft : QWaylandSurface::OriginTopLeft;
QtWayland::ClientBuffer * createBufferFor(wl_resource *resource) override
bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer)
void deleteImage(EGLImageKHR image)
LinuxDmabufClientBufferIntegration()
~LinuxDmabufClientBufferIntegration() override
void initializeHardware(struct ::wl_display *display) override
void removeBuffer(wl_resource *resource)
~LinuxDmabufClientBuffer() override
void setDestroyed() override
QOpenGLTexture * toOpenGlTexture(int plane) override
QSize size() const override
QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const override
QWaylandSurface::Origin origin() const override
uint32_t drmFormat() const
void initImage(uint32_t plane, EGLImageKHR image)
EGLImageKHR image(uint32_t plane)
uint32_t planesNumber() const
#define DRM_FORMAT_MOD_INVALID
#define ADD_PLANE_ATTRIBS(plane_idx)
static QOpenGLTexture::TextureFormat openGLFormatFromBufferFormat(QWaylandBufferRef::BufferFormatEgl format)