7#include <QtWaylandCompositor/QWaylandCompositor>
8#include <QtWaylandCompositor/private/qwayland-server-wayland.h>
9#include <qpa/qplatformnativeinterface.h>
10#include <QtOpenGL/QOpenGLTexture>
11#include <QtCore/QVarLengthArray>
12#include <QtGui/QGuiApplication>
13#include <QtGui/QOpenGLContext>
16#include <EGL/eglext.h>
18#include <drm_fourcc.h>
24 case DRM_FORMAT_RGB332:
25 case DRM_FORMAT_BGR233:
26 case DRM_FORMAT_XRGB4444:
27 case DRM_FORMAT_XBGR4444:
28 case DRM_FORMAT_RGBX4444:
29 case DRM_FORMAT_BGRX4444:
30 case DRM_FORMAT_XRGB1555:
31 case DRM_FORMAT_XBGR1555:
32 case DRM_FORMAT_RGBX5551:
33 case DRM_FORMAT_BGRX5551:
35 case DRM_FORMAT_BGR565:
38 case DRM_FORMAT_XRGB8888:
39 case DRM_FORMAT_XBGR8888:
40 case DRM_FORMAT_RGBX8888:
41 case DRM_FORMAT_BGRX8888:
42 case DRM_FORMAT_XRGB2101010:
43 case DRM_FORMAT_XBGR2101010:
44 case DRM_FORMAT_RGBX1010102:
45 case DRM_FORMAT_BGRX1010102:
47 case DRM_FORMAT_ARGB4444:
48 case DRM_FORMAT_ABGR4444:
49 case DRM_FORMAT_RGBA4444:
50 case DRM_FORMAT_BGRA4444:
51 case DRM_FORMAT_ARGB1555:
52 case DRM_FORMAT_ABGR1555:
53 case DRM_FORMAT_RGBA5551:
54 case DRM_FORMAT_BGRA5551:
55 case DRM_FORMAT_ARGB8888:
58 case DRM_FORMAT_BGRA8888:
59 case DRM_FORMAT_ARGB2101010:
60 case DRM_FORMAT_ABGR2101010:
61 case DRM_FORMAT_RGBA1010102:
67 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Buffer format" <<
Qt::hex <<
format <<
"not supported";
88bool LinuxDmabufClientBufferIntegration::initSimpleTexture(
LinuxDmabufWlBuffer *dmabufBuffer)
97 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
109 attribs.append(EGL_LINUX_DRM_FOURCC_EXT);
112#define ADD_PLANE_ATTRIBS(plane_idx) { \
113 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _FD_EXT); \
114 attribs.append(dmabufBuffer->plane(plane_idx).fd); \
115 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _OFFSET_EXT); \
116 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).offset)); \
117 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _PITCH_EXT); \
118 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).stride)); \
119 if (dmabufBuffer->plane(plane_idx).modifiers != DRM_FORMAT_MOD_INVALID) { \
120 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_LO_EXT); \
121 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers & 0xffffffff)); \
122 attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_HI_EXT); \
123 attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers >> 32)); \
141 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses invalid number of planes:" << dmabufBuffer->
planesNumber();
150 EGL_LINUX_DMA_BUF_EXT,
151 (EGLClientBuffer)
nullptr,
154 if (
image == EGL_NO_IMAGE_KHR) {
155 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image from" <<
171 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer for this format must provide" << conversion.
inputPlanes
172 <<
"planes but only" << dmabufBuffer->
planesNumber() <<
"received";
182 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Buffer uses dmabuf modifiers, which are not supported.";
192 EGL_LINUX_DRM_FOURCC_EXT, plane.
format,
204 EGL_LINUX_DMA_BUF_EXT,
205 (EGLClientBuffer)
nullptr,
208 if (
image == EGL_NO_IMAGE_KHR) {
209 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"failed to create EGL image for plane" <<
i;
227 secondPlane.
format = DRM_FORMAT_ARGB8888;
235 formatConversion.
plane[0] = firstPlane;
236 formatConversion.
plane[1] = secondPlane;
238 m_yuvFormats.
insert(DRM_FORMAT_YUYV, formatConversion);
243 m_importedBuffers.
clear();
245 if (egl_unbind_wayland_display !=
nullptr && m_displayBound) {
247 if (!egl_unbind_wayland_display(m_eglDisplay, m_wlDisplay))
248 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"eglUnbindWaylandDisplayWL failed";
256 const bool ignoreBindDisplay = !
qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").
isEmpty() &&
qgetenv(
"QT_WAYLAND_IGNORE_BIND_DISPLAY").
toInt() != 0;
259 egl_query_dmabuf_modifiers_ext =
reinterpret_cast<PFNEGLQUERYDMABUFMODIFIERSEXTPROC
>(eglGetProcAddress(
"eglQueryDmaBufModifiersEXT"));
260 egl_query_dmabuf_formats_ext =
reinterpret_cast<PFNEGLQUERYDMABUFFORMATSEXTPROC
>(eglGetProcAddress(
"eglQueryDmaBufFormatsEXT"));
261 if (!egl_query_dmabuf_modifiers_ext || !egl_query_dmabuf_formats_ext) {
262 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglQueryDmaBufModifiersEXT and eglQueryDmaBufFormatsEXT.";
266 egl_bind_wayland_display =
reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL
>(eglGetProcAddress(
"eglBindWaylandDisplayWL"));
267 egl_unbind_wayland_display =
reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL
>(eglGetProcAddress(
"eglUnbindWaylandDisplayWL"));
268 if ((!egl_bind_wayland_display || !egl_unbind_wayland_display) && !ignoreBindDisplay) {
269 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL.";
273 egl_create_image =
reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC
>(eglGetProcAddress(
"eglCreateImageKHR"));
274 egl_destroy_image =
reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC
>(eglGetProcAddress(
"eglDestroyImageKHR"));
275 if (!egl_create_image || !egl_destroy_image) {
276 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not find eglCreateImageKHR and eglDestroyImageKHR.";
282 if (!nativeInterface) {
283 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. No native platform interface available.";
289 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. Could not get EglDisplay for window.";
293 const char *extensionString = eglQueryString(m_eglDisplay, EGL_EXTENSIONS);
294 if (!extensionString || !strstr(extensionString,
"EGL_EXT_image_dma_buf_import")) {
295 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"Failed to initialize EGL display. There is no EGL_EXT_image_dma_buf_import extension.";
298 if (strstr(extensionString,
"EGL_EXT_image_dma_buf_import_modifiers"))
299 m_supportsDmabufModifiers =
true;
301 if (egl_bind_wayland_display && egl_unbind_wayland_display) {
302 m_displayBound = egl_bind_wayland_display(m_eglDisplay,
display);
304 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"Wayland display already bound by other client buffer integration.";
310 for (
const auto &
format : supportedDrmFormats()) {
316QList<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats()
318 if (!egl_query_dmabuf_formats_ext)
323 EGLBoolean success = egl_query_dmabuf_formats_ext(m_eglDisplay, 0,
nullptr, &
count);
325 if (success &&
count > 0) {
327 if (egl_query_dmabuf_formats_ext(m_eglDisplay,
count, (EGLint *) drmFormats.data(), &
count))
336 if (!egl_query_dmabuf_modifiers_ext)
341 EGLBoolean success = egl_query_dmabuf_modifiers_ext(m_eglDisplay,
format, 0,
nullptr,
nullptr, &
count);
343 if (success &&
count > 0) {
357 Q_ASSERT(m_orphanedTextures.
size() == m_orphanedTexturesAboutToBeDestroyedConnection.
size());
373 if (!m_orphanedTextures.
isEmpty())
374 qCDebug(qLcWaylandCompositorHardwareIntegration) <<
"About to delete some textures: "
375 << m_orphanedTextures;
382 m_orphanedTexturesAboutToBeDestroyedConnection.
clear();
383 m_orphanedTextures.
clear();
388 Q_ASSERT(m_orphanedTextures.
size() == m_orphanedTexturesAboutToBeDestroyedConnection.
size());
393 if (m_orphanedTextures.
length()==0) {
394 qCWarning(qLcWaylandCompositorHardwareIntegration)
396 <<
"Looks like deleteOrphanedTextures() and this function where called simultaneously!"
397 <<
"This might cause issues!";
410 qCDebug(qLcWaylandCompositorHardwareIntegration)
412 <<
"texture deleted due to QOpenGLContext::aboutToBeDestroyed!"
413 <<
"Pointer (now dead) was:" << (
void*)
texture;
418 egl_destroy_image(m_eglDisplay,
image);
423 auto it = m_importedBuffers.
find(resource);
424 if (
it != m_importedBuffers.
end()) {
425 m_importedBuffers.
value(resource);
434 if (m_importedBuffers.
contains(resource)) {
435 qCWarning(qLcWaylandCompositorHardwareIntegration) <<
"buffer has already been added";
438 m_importedBuffers[resource] = linuxDmabufBuffer;
440 return initYuvTexture(linuxDmabufBuffer);
442 return initSimpleTexture(linuxDmabufBuffer);
447 m_importedBuffers.
remove(resource);
451 wl_resource *bufferResource,
453 : ClientBuffer(bufferResource)
454 , m_integration(integration)
482 glTexParameterf(
target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
491 ClientBuffer::setDestroyed();
void deleteGLTextureWhenPossible(QOpenGLTexture *texture, QOpenGLContext *ctx)
void deleteSpecificOrphanedTexture(QOpenGLTexture *texture)
QtWayland::ClientBuffer * createBufferFor(wl_resource *resource) override
bool importBuffer(wl_resource *resource, LinuxDmabufWlBuffer *linuxDmabufBuffer)
void deleteImage(EGLImageKHR image)
LinuxDmabufClientBufferIntegration()
~LinuxDmabufClientBufferIntegration() override
void deleteOrphanedTextures()
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
Plane & plane(uint index)
void initTexture(uint32_t plane, QOpenGLTexture *texture)
uint32_t drmFormat() const
void initImage(uint32_t plane, EGLImageKHR image)
QOpenGLTexture * texture(uint32_t plane) const
EGLImageKHR image(uint32_t plane)
uint32_t planesNumber() const
void setSupportedModifiers(const QHash< uint32_t, QList< uint64_t > > &modifiers)
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
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.
qsizetype size() const noexcept
bool isEmpty() const noexcept
void removeAt(qsizetype i)
qsizetype length() const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
void aboutToBeDestroyed()
This signal is emitted before the underlying native OpenGL context is destroyed, such that users may ...
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
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
EGLImageKHR int int EGLuint64KHR * modifiers
qDeleteAll(list.begin(), list.end())
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)
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept