diff options
Diffstat (limited to 'src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp')
-rw-r--r-- | src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp | 261 |
1 files changed, 107 insertions, 154 deletions
diff --git a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp index a85f24542..205f25d1f 100644 --- a/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp +++ b/src/hardwareintegration/compositor/linux-dmabuf-unstable-v1/linuxdmabufclientbufferintegration.cpp @@ -1,51 +1,17 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWaylandCompositor module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include "linuxdmabufclientbufferintegration.h" #include "linuxdmabuf.h" #include <QtWaylandCompositor/QWaylandCompositor> #include <QtWaylandCompositor/private/qwayland-server-wayland.h> +#include <QtWaylandCompositor/private/qwltextureorphanage_p.h> #include <qpa/qplatformnativeinterface.h> +#include <QtOpenGL/QOpenGLTexture> +#include <QtCore/QVarLengthArray> #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLTexture> #include <EGL/egl.h> #include <EGL/eglext.h> @@ -99,7 +65,7 @@ static QWaylandBufferRef::BufferFormatEgl formatFromDrmFormat(EGLint format) { case DRM_FORMAT_YUYV: return QWaylandBufferRef::BufferFormatEgl_Y_XUXV; default: - qCDebug(qLcWaylandCompositorHardwareIntegration) << "Buffer format" << hex << format << "not supported"; + qCDebug(qLcWaylandCompositorHardwareIntegration) << "Buffer format" << Qt::hex << format << "not supported"; return QWaylandBufferRef::BufferFormatEgl_Null; } } @@ -115,6 +81,11 @@ static QOpenGLTexture::TextureFormat openGLFormatFromBufferFormat(QWaylandBuffer } } +// Initialize the EGLImage for a dmabuf buffer which conceptually consists of a +// single plane. Note that depending on the modifiers, the buffer may be actually +// transported as multiple dmabuf planes which must be combined into a single +// EGLImage. For formats where the buffer needs to be represented as multiple +// EGLImages (e.g., various YUV formats) a different approach is required. bool LinuxDmabufClientBufferIntegration::initSimpleTexture(LinuxDmabufWlBuffer *dmabufBuffer) { bool success = true; @@ -128,79 +99,67 @@ bool LinuxDmabufClientBufferIntegration::initSimpleTexture(LinuxDmabufWlBuffer * success = false; } - for (uint32_t i = 0; i < dmabufBuffer->planesNumber(); ++i) { - QVarLengthArray<EGLint, 17> attribs; - switch (i) { - case 0: - attribs = { - EGL_WIDTH, dmabufBuffer->size().width(), - EGL_HEIGHT, dmabufBuffer->size().height(), - EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()), - EGL_DMA_BUF_PLANE0_FD_EXT, dmabufBuffer->plane(i).fd, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset), - EGL_DMA_BUF_PLANE0_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride), - EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff), - EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32), - EGL_NONE - }; - break; - case 1: - attribs = { - EGL_WIDTH, dmabufBuffer->size().width(), - EGL_HEIGHT, dmabufBuffer->size().height(), - EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()), - EGL_DMA_BUF_PLANE1_FD_EXT, dmabufBuffer->plane(i).fd, - EGL_DMA_BUF_PLANE1_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset), - EGL_DMA_BUF_PLANE1_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride), - EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff), - EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32), - EGL_NONE - }; - break; - case 2: - attribs = { - EGL_WIDTH, dmabufBuffer->size().width(), - EGL_HEIGHT, dmabufBuffer->size().height(), - EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()), - EGL_DMA_BUF_PLANE2_FD_EXT, dmabufBuffer->plane(i).fd, - EGL_DMA_BUF_PLANE2_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset), - EGL_DMA_BUF_PLANE2_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride), - EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff), - EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32), - EGL_NONE - }; - break; - case 3: - attribs = { - EGL_WIDTH, dmabufBuffer->size().width(), - EGL_HEIGHT, dmabufBuffer->size().height(), - EGL_LINUX_DRM_FOURCC_EXT, EGLint(dmabufBuffer->drmFormat()), - EGL_DMA_BUF_PLANE3_FD_EXT, dmabufBuffer->plane(i).fd, - EGL_DMA_BUF_PLANE3_OFFSET_EXT, EGLint(dmabufBuffer->plane(i).offset), - EGL_DMA_BUF_PLANE3_PITCH_EXT, EGLint(dmabufBuffer->plane(i).stride), - EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, EGLint(dmabufBuffer->plane(i).modifiers & 0xffffffff), - EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT, EGLint(dmabufBuffer->plane(i).modifiers >> 32), - EGL_NONE - }; + // 6 entries for the common attribs plus 10 per possible plane, plus 1 for + // the final EGL_NONE sentinel. + QVarLengthArray<EGLint, 6 + 10 * 4 + 1> attribs; + + attribs.append(EGL_WIDTH); + attribs.append(dmabufBuffer->size().width()); + attribs.append(EGL_HEIGHT); + attribs.append(dmabufBuffer->size().height()); + attribs.append(EGL_LINUX_DRM_FOURCC_EXT); + attribs.append(EGLint(dmabufBuffer->drmFormat())); + +#define ADD_PLANE_ATTRIBS(plane_idx) { \ + attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _FD_EXT); \ + attribs.append(dmabufBuffer->plane(plane_idx).fd); \ + attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _OFFSET_EXT); \ + attribs.append(EGLint(dmabufBuffer->plane(plane_idx).offset)); \ + attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _PITCH_EXT); \ + attribs.append(EGLint(dmabufBuffer->plane(plane_idx).stride)); \ + if (dmabufBuffer->plane(plane_idx).modifiers != DRM_FORMAT_MOD_INVALID) { \ + attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_LO_EXT); \ + attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers & 0xffffffff)); \ + attribs.append(EGL_DMA_BUF_PLANE ## plane_idx ## _MODIFIER_HI_EXT); \ + attribs.append(EGLint(dmabufBuffer->plane(plane_idx).modifiers >> 32)); \ + } \ +} + + switch (dmabufBuffer->planesNumber()) { + case 4: + ADD_PLANE_ATTRIBS(3); + Q_FALLTHROUGH(); + case 3: + ADD_PLANE_ATTRIBS(2); + Q_FALLTHROUGH(); + case 2: + ADD_PLANE_ATTRIBS(1); + Q_FALLTHROUGH(); + case 1: + ADD_PLANE_ATTRIBS(0); break; - default: - return false; - } + default: + qCWarning(qLcWaylandCompositorHardwareIntegration) << "Buffer uses invalid number of planes:" << dmabufBuffer->planesNumber(); + return false; + } - // note: EGLImageKHR does NOT take ownership of the file descriptors - EGLImageKHR image = egl_create_image(m_eglDisplay, - EGL_NO_CONTEXT, - EGL_LINUX_DMA_BUF_EXT, - (EGLClientBuffer) nullptr, - attribs.constData()); + attribs.append(EGL_NONE); - if (image == EGL_NO_IMAGE_KHR) { - qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image for plane" << i; - success = false; - } + // note: EGLImageKHR does NOT take ownership of the file descriptors + EGLImageKHR image = egl_create_image(m_eglDisplay, + EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, + (EGLClientBuffer) nullptr, + attribs.constData()); - dmabufBuffer->initImage(i, image); + if (image == EGL_NO_IMAGE_KHR) { + qCWarning(qLcWaylandCompositorHardwareIntegration) << "failed to create EGL image from" << + dmabufBuffer->planesNumber() << "plane(s)"; + success = false; } + + dmabufBuffer->initImage(0, image); + return success; } @@ -259,27 +218,36 @@ bool LinuxDmabufClientBufferIntegration::initYuvTexture(LinuxDmabufWlBuffer *dma LinuxDmabufClientBufferIntegration::LinuxDmabufClientBufferIntegration() { - m_yuvFormats.insert(DRM_FORMAT_YUYV, - YuvFormatConversion { - .inputPlanes = 1, - .outputPlanes = 2, - {{ - .format = DRM_FORMAT_GR88, - .widthDivisor = 1, - .heightDivisor = 1, - .planeIndex = 0 - }, { - .format = DRM_FORMAT_ARGB8888, - .widthDivisor = 2, - .heightDivisor = 1, - .planeIndex = 0 - }} - }); + YuvPlaneConversion firstPlane; + firstPlane.format = DRM_FORMAT_GR88; + firstPlane.widthDivisor = 1; + firstPlane.heightDivisor = 1; + firstPlane.planeIndex = 0; + + YuvPlaneConversion secondPlane; + secondPlane.format = DRM_FORMAT_ARGB8888; + secondPlane.widthDivisor = 2; + secondPlane.heightDivisor = 1; + secondPlane.planeIndex = 0; + + YuvFormatConversion formatConversion; + formatConversion.inputPlanes = 1; + formatConversion.outputPlanes = 2; + formatConversion.plane[0] = firstPlane; + formatConversion.plane[1] = secondPlane; + + m_yuvFormats.insert(DRM_FORMAT_YUYV, formatConversion); } LinuxDmabufClientBufferIntegration::~LinuxDmabufClientBufferIntegration() { m_importedBuffers.clear(); + + if (egl_unbind_wayland_display != nullptr && m_displayBound) { + Q_ASSERT(m_wlDisplay != nullptr); + if (!egl_unbind_wayland_display(m_eglDisplay, m_wlDisplay)) + qCWarning(qLcWaylandCompositorHardwareIntegration) << "eglUnbindWaylandDisplayWL failed"; + } } void LinuxDmabufClientBufferIntegration::initializeHardware(struct ::wl_display *display) @@ -333,66 +301,54 @@ void LinuxDmabufClientBufferIntegration::initializeHardware(struct ::wl_display if (egl_bind_wayland_display && egl_unbind_wayland_display) { m_displayBound = egl_bind_wayland_display(m_eglDisplay, display); - if (!m_displayBound) { - if (ignoreBindDisplay) { - qCWarning(qLcWaylandCompositorHardwareIntegration) << "Could not bind Wayland display. Ignoring."; - } else { - qCWarning(qLcWaylandCompositorHardwareIntegration) << "Failed to initialize EGL display. Could not bind Wayland display."; - return; - } - } + if (!m_displayBound) + qCDebug(qLcWaylandCompositorHardwareIntegration) << "Wayland display already bound by other client buffer integration."; + m_wlDisplay = display; } // request and sent formats/modifiers only after egl_display is bound - QHash<uint32_t, QVector<uint64_t>> modifiers; + QHash<uint32_t, QList<uint64_t>> modifiers; for (const auto &format : supportedDrmFormats()) { modifiers[format] = supportedDrmModifiers(format); } m_linuxDmabuf->setSupportedModifiers(modifiers); } -QVector<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats() +QList<uint32_t> LinuxDmabufClientBufferIntegration::supportedDrmFormats() { if (!egl_query_dmabuf_formats_ext) - return QVector<uint32_t>(); + return QList<uint32_t>(); // request total number of formats EGLint count = 0; EGLBoolean success = egl_query_dmabuf_formats_ext(m_eglDisplay, 0, nullptr, &count); if (success && count > 0) { - QVector<uint32_t> drmFormats(count); + QList<uint32_t> drmFormats(count); if (egl_query_dmabuf_formats_ext(m_eglDisplay, count, (EGLint *) drmFormats.data(), &count)) return drmFormats; } - return QVector<uint32_t>(); + return QList<uint32_t>(); } -QVector<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32_t format) +QList<uint64_t> LinuxDmabufClientBufferIntegration::supportedDrmModifiers(uint32_t format) { if (!egl_query_dmabuf_modifiers_ext) - return QVector<uint64_t>(); + return QList<uint64_t>(); // request total number of formats EGLint count = 0; EGLBoolean success = egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, 0, nullptr, nullptr, &count); if (success && count > 0) { - QVector<uint64_t> modifiers(count); + QList<uint64_t> modifiers(count); if (egl_query_dmabuf_modifiers_ext(m_eglDisplay, format, count, modifiers.data(), nullptr, &count)) { return modifiers; } } - return QVector<uint64_t>(); -} - -void LinuxDmabufClientBufferIntegration::deleteOrphanedTextures() -{ - Q_ASSERT(QOpenGLContext::currentContext()); - qDeleteAll(m_orphanedTextures); - m_orphanedTextures.clear(); + return QList<uint64_t>(); } void LinuxDmabufClientBufferIntegration::deleteImage(EGLImageKHR image) @@ -402,16 +358,12 @@ void LinuxDmabufClientBufferIntegration::deleteImage(EGLImageKHR image) QtWayland::ClientBuffer *LinuxDmabufClientBufferIntegration::createBufferFor(wl_resource *resource) { - // fallback for shared memory buffers - if (wl_shm_buffer_get(resource)) - return nullptr; - auto it = m_importedBuffers.find(resource); if (it != m_importedBuffers.end()) { m_importedBuffers.value(resource); return new LinuxDmabufClientBuffer(this, it.value()->resource()->handle, m_importedBuffers.value(resource)); } - qCWarning(qLcWaylandCompositorHardwareIntegration) << "could not create client buffer for dmabuf buffer"; + return nullptr; } @@ -445,7 +397,7 @@ LinuxDmabufClientBuffer::LinuxDmabufClientBuffer(LinuxDmabufClientBufferIntegrat QOpenGLTexture *LinuxDmabufClientBuffer::toOpenGlTexture(int plane) { // At this point we should have a valid OpenGL context, so it's safe to destroy textures - m_integration->deleteOrphanedTextures(); + QtWayland::QWaylandTextureOrphanage::instance()->deleteTextures(); if (!m_buffer) return nullptr; @@ -463,6 +415,7 @@ QOpenGLTexture *LinuxDmabufClientBuffer::toOpenGlTexture(int plane) } if (m_textureDirty) { + m_textureDirty = false; texture->bind(); glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); m_integration->gl_egl_image_target_texture_2d(target, d->image(plane)); |