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>
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:
36 case DRM_FORMAT_BGR565:
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:
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:
59 case DRM_FORMAT_BGRA8888:
60 case DRM_FORMAT_ARGB2101010:
61 case DRM_FORMAT_ABGR2101010:
62 case DRM_FORMAT_RGBA1010102:
68 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Buffer format" <<
Qt::hex <<
format <<
"not supported";
89bool LinuxDmabufClientBufferIntegration::initSimpleTexture(
LinuxDmabufWlBuffer *dmabufBuffer)
98 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
104 QVarLengthArray<EGLint, 6 + 10 * 4 + 1>
attribs;
107 attribs.append(dmabufBuffer->size().width());
109 attribs.append(dmabufBuffer->size().height());
110 attribs.append(EGL_LINUX_DRM_FOURCC_EXT);
111 attribs.append(EGLint(dmabufBuffer->drmFormat()));
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)); \
120 if (dmabufBuffer->plane(plane_idx).modifiers != DRM_FORMAT_MOD_INVALID) { \
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)); \
128 switch (dmabufBuffer->planesNumber()) {
142 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses invalid number of planes:" << dmabufBuffer->planesNumber();
151 EGL_LINUX_DMA_BUF_EXT,
152 (EGLClientBuffer)
nullptr,
155 if (
image == EGL_NO_IMAGE_KHR) {
156 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image from" <<
157 dmabufBuffer->planesNumber() <<
"plane(s)";
161 dmabufBuffer->initImage(0,
image);
171 if (conversion.
inputPlanes != dmabufBuffer->planesNumber()) {
172 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer for this format must provide" << conversion.
inputPlanes
173 <<
"planes but only" << dmabufBuffer->planesNumber() <<
"received";
183 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
190 QVarLengthArray<EGLint, 17>
attribs = {
191 EGL_WIDTH, dmabufBuffer->size().width() / plane.
widthDivisor,
192 EGL_HEIGHT, dmabufBuffer->size().height() / plane.
heightDivisor,
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),
205 EGL_LINUX_DMA_BUF_EXT,
206 (EGLClientBuffer)
nullptr,
209 if (
image == EGL_NO_IMAGE_KHR) {
210 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image for plane" <<
i;
214 dmabufBuffer->initImage(
i,
image);
223 firstPlane.widthDivisor = 1;
224 firstPlane.heightDivisor = 1;
225 firstPlane.planeIndex = 0;
228 secondPlane.
format = DRM_FORMAT_ARGB8888;
229 secondPlane.widthDivisor = 2;
230 secondPlane.heightDivisor = 1;
231 secondPlane.planeIndex = 0;
235 formatConversion.outputPlanes = 2;
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) {
248 if (!egl_unbind_wayland_display(m_eglDisplay, m_wlDisplay))
249 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"eglUnbindWaylandDisplayWL failed";
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.";
283 if (!nativeInterface) {
284 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. No native platform interface available.";
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.";
310 QHash<uint32_t, QList<uint64_t>>
modifiers;
311 for (
const auto &
format : supportedDrmFormats()) {
317QList<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats()
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>();
335QList<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32_t
format)
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) {
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 m_importedBuffers.
value(resource);
372 if (m_importedBuffers.
contains(resource)) {
373 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"buffer has already been added";
376 m_importedBuffers[resource] = linuxDmabufBuffer;
377 if (m_yuvFormats.
contains(linuxDmabufBuffer->drmFormat()))
378 return initYuvTexture(linuxDmabufBuffer);
380 return initSimpleTexture(linuxDmabufBuffer);
385 m_importedBuffers.
remove(resource);
389 wl_resource *bufferResource,
391 : ClientBuffer(bufferResource)
392 , m_integration(integration)
420 glTexParameterf(
target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
429 ClientBuffer::setDestroyed();
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
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gl_egl_image_target_texture_2d
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
void initTexture(uint32_t plane, QOpenGLTexture *texture)
uint32_t drmFormat() const
QOpenGLTexture * texture(uint32_t plane) const
EGLImageKHR image(uint32_t plane)
void setSupportedModifiers(const QHash< uint32_t, QList< uint64_t > > &modifiers)
static QPlatformNativeInterface * platformNativeInterface()
bool remove(const Key &key)
Removes the item that has the key from the hash.
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
T value(const Key &key) const noexcept
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
TextureFormat
This enum defines the possible texture formats.
Target
This enum defines the texture target of a QOpenGLTexture object.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
Origin
This enum type is used to specify the origin of a QWaylandSurface's buffer.
struct::wl_resource * m_buffer
static QWaylandTextureOrphanage * instance()
EGLImageKHR int int EGLuint64KHR * modifiers
QSet< QString >::iterator it
struct wl_display * display
#define DRM_FORMAT_MOD_INVALID
#define ADD_PLANE_ATTRIBS(plane_idx)
static QT_BEGIN_NAMESPACE QWaylandBufferRef::BufferFormatEgl formatFromDrmFormat(EGLint format)
static QOpenGLTexture::TextureFormat openGLFormatFromBufferFormat(QWaylandBufferRef::BufferFormatEgl format)
QT_BEGIN_NAMESPACE typedef EGLBoolean(EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat)(EGLDisplay dpy
EGLint EGLint EGLuint64KHR * modifiers
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
#define DRM_FORMAT_BGR888
#define DRM_FORMAT_RGB565
#define DRM_FORMAT_RGB888
#define DRM_FORMAT_ABGR8888
#define DRM_FORMAT_BGRA1010102
#define DRM_FORMAT_RGBA8888
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum format
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)