diff options
author | Paul Olav Tvete <paul.tvete@qt.io> | 2019-01-07 15:01:20 +0100 |
---|---|---|
committer | Jani Heikkinen <jani.heikkinen@qt.io> | 2019-01-08 11:57:40 +0000 |
commit | c584db87cf924f3a3d883288de8c2f4210186af6 (patch) | |
tree | 78b91ca235fa7f881786160949744c6db1071060 /src/hardwareintegration | |
parent | 024be9dcae26a0d88ffb76f9fca252f2135ad7c9 (diff) | |
download | qtwayland-c584db87cf924f3a3d883288de8c2f4210186af6.tar.gz |
wl_eglstream_controller implementation for NVIDIA
This adds a new client buffer integration: wayland-eglstream-controller,
which contains the EGLStream logic from wayland-egl, and additionally
uses NVIDIA's wayland-eglstream-controller protocol to avoid the issue
where the stream is not ready at the time of first buffer attach.
This is not enabled by default. Can be used like this:
QT_WAYLAND_CLIENT_BUFFER_INTEGRATION=wayland-eglstream-controller ./pure-qml
Fixes: QTBUG-71697
Change-Id: I73bb2a8fe9852afe1b5807cbb8c35dc4c7624dad
Reviewed-by: Johan Helsing <johan.helsing@qt.io>
Diffstat (limited to 'src/hardwareintegration')
5 files changed, 690 insertions, 0 deletions
diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri b/src/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri new file mode 100644 index 00000000..931475ef --- /dev/null +++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri @@ -0,0 +1,16 @@ +INCLUDEPATH += $$PWD + +QMAKE_USE_PRIVATE += egl wayland-server wayland-egl + +CONFIG += wayland-scanner +WAYLANDSERVERSOURCES += $$PWD/../../../3rdparty/protocol/wl-eglstream-controller.xml + +QT += egl_support-private + +SOURCES += \ + $$PWD/waylandeglstreamintegration.cpp \ + $$PWD/waylandeglstreamcontroller.cpp + +HEADERS += \ + $$PWD/waylandeglstreamintegration.h \ + $$PWD/waylandeglstreamcontroller.h diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.cpp b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.cpp new file mode 100644 index 00000000..09859d7e --- /dev/null +++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +#include "waylandeglstreamcontroller.h" +#include "waylandeglstreamintegration.h" + +#include <QtWaylandCompositor/QWaylandCompositor> + +#include <unistd.h> + +QT_BEGIN_NAMESPACE + + + +WaylandEglStreamController::WaylandEglStreamController(wl_display *display, WaylandEglStreamClientBufferIntegration *clientBufferIntegration) + : wl_eglstream_controller(display, 1 /*version*/) + , m_clientBufferIntegration(clientBufferIntegration) +{ +} + +void WaylandEglStreamController::eglstream_controller_attach_eglstream_consumer(Resource *resource, struct ::wl_resource *wl_surface, struct ::wl_resource *wl_buffer) +{ + Q_UNUSED(resource); + m_clientBufferIntegration->attachEglStreamConsumer(wl_surface, wl_buffer); +} + +QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.h b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.h new file mode 100644 index 00000000..3a7fcee7 --- /dev/null +++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins 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$ +** +****************************************************************************/ + +#ifndef WAYLANDEGLSTREAMCONTROLLER_H +#define WAYLANDEGLSTREAMCONTROLLER_H + +#include "qwayland-server-wl-eglstream-controller.h" + +#include <QtWaylandCompositor/private/qwayland-server-wayland.h> +#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> + +#include <QtCore/QObject> +#include <QtCore/QHash> +#include <QtCore/QSize> +#include <QtCore/QTextStream> +#include <QtGui/QOpenGLTexture> + +#include <EGL/egl.h> +#include <EGL/eglext.h> + + +QT_BEGIN_NAMESPACE + +class QWaylandCompositor; +class QWaylandResource; +class WaylandEglStreamClientBufferIntegration; + +class WaylandEglStreamController : public QtWaylandServer::wl_eglstream_controller +{ +public: + explicit WaylandEglStreamController(wl_display *display, WaylandEglStreamClientBufferIntegration *clientBufferIntegration); + +protected: + void eglstream_controller_attach_eglstream_consumer(Resource *resource, struct ::wl_resource *wl_surface, struct ::wl_resource *wl_buffer) override; + +private: + WaylandEglStreamClientBufferIntegration *m_clientBufferIntegration; +}; + + +QT_END_NAMESPACE + +#endif // WAYLANDEGLSTREAMCONTROLLER_H diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp new file mode 100644 index 00000000..1493e9fc --- /dev/null +++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +#include "waylandeglstreamintegration.h" +#include "waylandeglstreamcontroller.h" + +#include <QtWaylandCompositor/QWaylandCompositor> +#include <QtGui/QGuiApplication> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLTexture> +#include <QtGui/QOffscreenSurface> + +#include <QtEglSupport/private/qeglstreamconvenience_p.h> +#include <qpa/qplatformnativeinterface.h> + +#include <QtWaylandCompositor/private/qwaylandcompositor_p.h> +#include <QtWaylandCompositor/private/qwlbuffermanager_p.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <unistd.h> + +#ifndef GL_TEXTURE_EXTERNAL_OES +#define GL_TEXTURE_EXTERNAL_OES 0x8D65 +#endif + +#ifndef EGL_WAYLAND_BUFFER_WL +#define EGL_WAYLAND_BUFFER_WL 0x31D5 +#endif + +#ifndef EGL_WAYLAND_EGLSTREAM_WL +#define EGL_WAYLAND_EGLSTREAM_WL 0x334B +#endif + +#ifndef EGL_WAYLAND_PLANE_WL +#define EGL_WAYLAND_PLANE_WL 0x31D6 +#endif + +#ifndef EGL_WAYLAND_Y_INVERTED_WL +#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB +#endif + +#ifndef EGL_TEXTURE_RGB +#define EGL_TEXTURE_RGB 0x305D +#endif + +#ifndef EGL_TEXTURE_RGBA +#define EGL_TEXTURE_RGBA 0x305E +#endif + +#ifndef EGL_TEXTURE_EXTERNAL_WL +#define EGL_TEXTURE_EXTERNAL_WL 0x31DA +#endif + +#ifndef EGL_TEXTURE_Y_U_V_WL +#define EGL_TEXTURE_Y_U_V_WL 0x31D7 +#endif + +#ifndef EGL_TEXTURE_Y_UV_WL +#define EGL_TEXTURE_Y_UV_WL 0x31D8 +#endif + +#ifndef EGL_TEXTURE_Y_XUXV_WL +#define EGL_TEXTURE_Y_XUXV_WL 0x31D9 +#endif + +#ifndef EGL_PLATFORM_X11_KHR +#define EGL_PLATFORM_X11_KHR 0x31D5 +#endif + +QT_BEGIN_NAMESPACE + +/* Needed for compatibility with Mesa older than 10.0. */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL_compat) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value); + +#ifndef EGL_WL_bind_wayland_display +typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display); +#endif + +static const char * +egl_error_string(EGLint code) +{ +#define MYERRCODE(x) case x: return #x; + switch (code) { + MYERRCODE(EGL_SUCCESS) + MYERRCODE(EGL_NOT_INITIALIZED) + MYERRCODE(EGL_BAD_ACCESS) + MYERRCODE(EGL_BAD_ALLOC) + MYERRCODE(EGL_BAD_ATTRIBUTE) + MYERRCODE(EGL_BAD_CONTEXT) + MYERRCODE(EGL_BAD_CONFIG) + MYERRCODE(EGL_BAD_CURRENT_SURFACE) + MYERRCODE(EGL_BAD_DISPLAY) + MYERRCODE(EGL_BAD_SURFACE) + MYERRCODE(EGL_BAD_MATCH) + MYERRCODE(EGL_BAD_PARAMETER) + MYERRCODE(EGL_BAD_NATIVE_PIXMAP) + MYERRCODE(EGL_BAD_NATIVE_WINDOW) + MYERRCODE(EGL_CONTEXT_LOST) + default: + return "unknown"; + } +#undef MYERRCODE +} + +struct BufferState +{ + BufferState() = default; + + EGLint egl_format = EGL_TEXTURE_EXTERNAL_WL; + QOpenGLTexture *textures[3] = {}; + EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR; + + bool isYInverted = false; + QSize size; +}; + +class WaylandEglStreamClientBufferIntegrationPrivate +{ +public: + WaylandEglStreamClientBufferIntegrationPrivate() = default; + + bool ensureContext(); + bool initEglStream(WaylandEglStreamClientBuffer *buffer, struct ::wl_resource *bufferHandle); + void handleEglstreamTexture(WaylandEglStreamClientBuffer *buffer); + void deleteGLTextureWhenPossible(QOpenGLTexture *texture) { orphanedTextures << texture; } + void deleteOrphanedTextures(); + + EGLDisplay egl_display = EGL_NO_DISPLAY; + bool display_bound = false; + QOffscreenSurface *offscreenSurface = nullptr; + QOpenGLContext *localContext = nullptr; + QVector<QOpenGLTexture *> orphanedTextures; + + WaylandEglStreamController *eglStreamController = nullptr; + + PFNEGLBINDWAYLANDDISPLAYWL egl_bind_wayland_display = nullptr; + PFNEGLUNBINDWAYLANDDISPLAYWL egl_unbind_wayland_display = nullptr; + PFNEGLQUERYWAYLANDBUFFERWL_compat egl_query_wayland_buffer = nullptr; + + QEGLStreamConvenience *funcs = nullptr; + static WaylandEglStreamClientBufferIntegrationPrivate *get(WaylandEglStreamClientBufferIntegration *integration) { + return shuttingDown ? nullptr : integration->d_ptr.data(); + } + + static bool shuttingDown; +}; + +bool WaylandEglStreamClientBufferIntegrationPrivate::shuttingDown = false; + +void WaylandEglStreamClientBufferIntegrationPrivate::deleteOrphanedTextures() +{ + Q_ASSERT(QOpenGLContext::currentContext()); + qDeleteAll(orphanedTextures); + orphanedTextures.clear(); +} + +bool WaylandEglStreamClientBufferIntegrationPrivate::ensureContext() +{ + bool localContextNeeded = false; + if (!QOpenGLContext::currentContext()) { + if (!localContext && QOpenGLContext::globalShareContext()) { + localContext = new QOpenGLContext; + localContext->setShareContext(QOpenGLContext::globalShareContext()); + localContext->create(); + } + if (localContext) { + if (!offscreenSurface) { + offscreenSurface = new QOffscreenSurface; + offscreenSurface->setFormat(localContext->format()); + offscreenSurface->create(); + } + localContext->makeCurrent(offscreenSurface); + localContextNeeded = true; + } + } + return localContextNeeded; +} + + +bool WaylandEglStreamClientBufferIntegrationPrivate::initEglStream(WaylandEglStreamClientBuffer *buffer, wl_resource *bufferHandle) +{ + BufferState &state = *buffer->d; + state.egl_format = EGL_TEXTURE_EXTERNAL_WL; + state.isYInverted = false; + + EGLNativeFileDescriptorKHR streamFd = EGL_NO_FILE_DESCRIPTOR_KHR; + + if (egl_query_wayland_buffer(egl_display, bufferHandle, EGL_WAYLAND_BUFFER_WL, &streamFd)) { + state.egl_stream = funcs->create_stream_from_file_descriptor(egl_display, streamFd); + close(streamFd); + } else { + EGLAttrib stream_attribs[] = { + EGL_WAYLAND_EGLSTREAM_WL, (EGLAttrib)bufferHandle, + EGL_NONE + }; + state.egl_stream = funcs->create_stream_attrib_nv(egl_display, stream_attribs); + } + + if (state.egl_stream == EGL_NO_STREAM_KHR) { + qWarning("%s:%d: eglCreateStreamFromFileDescriptorKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + return false; + } + + bool usingLocalContext = ensureContext(); + + Q_ASSERT(QOpenGLContext::currentContext()); + + auto texture = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(GL_TEXTURE_EXTERNAL_OES)); + texture->create(); + state.textures[0] = texture; // TODO: support multiple planes + + texture->bind(); + + auto newStream = funcs->stream_consumer_gltexture(egl_display, state.egl_stream); + if (usingLocalContext) + localContext->doneCurrent(); + + if (!newStream) { + EGLint code = eglGetError(); + qWarning() << "Could not initialize EGLStream:" << egl_error_string(code) << hex << (long)code; + funcs->destroy_stream(egl_display, state.egl_stream); + state.egl_stream = EGL_NO_STREAM_KHR; + return false; + } + return true; +} + +void WaylandEglStreamClientBufferIntegrationPrivate::handleEglstreamTexture(WaylandEglStreamClientBuffer *buffer) +{ + bool usingLocalContext = ensureContext(); + + BufferState &state = *buffer->d; + auto texture = state.textures[0]; + + // EGLStream requires calling acquire on every frame. + texture->bind(); + EGLint stream_state; + funcs->query_stream(egl_display, state.egl_stream, EGL_STREAM_STATE_KHR, &stream_state); + + if (stream_state == EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) { + if (funcs->stream_consumer_acquire(egl_display, state.egl_stream) != EGL_TRUE) + qWarning("%s:%d: eglStreamConsumerAcquireKHR failed: 0x%x", Q_FUNC_INFO, __LINE__, eglGetError()); + } + + if (usingLocalContext) + localContext->doneCurrent(); +} + + +WaylandEglStreamClientBufferIntegration::WaylandEglStreamClientBufferIntegration() + : d_ptr(new WaylandEglStreamClientBufferIntegrationPrivate) +{ +} + +WaylandEglStreamClientBufferIntegration::~WaylandEglStreamClientBufferIntegration() +{ + WaylandEglStreamClientBufferIntegrationPrivate::shuttingDown = true; +} + +void WaylandEglStreamClientBufferIntegration::attachEglStreamConsumer(struct ::wl_resource *wl_surface, struct ::wl_resource *wl_buffer) +{ + Q_D(WaylandEglStreamClientBufferIntegration); + Q_UNUSED(wl_surface); + + // NOTE: must use getBuffer to create the buffer here, so the buffer will end up in the buffer manager's hash + + auto *bufferManager = QWaylandCompositorPrivate::get(m_compositor)->bufferManager(); + auto *clientBuffer = static_cast<WaylandEglStreamClientBuffer*>(bufferManager->getBuffer(wl_buffer)); + + d->initEglStream(clientBuffer, wl_buffer); +} + +void WaylandEglStreamClientBufferIntegration::initializeHardware(struct wl_display *display) +{ + Q_D(WaylandEglStreamClientBufferIntegration); + + const bool ignoreBindDisplay = !qgetenv("QT_WAYLAND_IGNORE_BIND_DISPLAY").isEmpty(); + + QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); + if (!nativeInterface) { + qWarning("QtCompositor: Failed to initialize EGL display. No native platform interface available."); + return; + } + + d->egl_display = nativeInterface->nativeResourceForIntegration("EglDisplay"); + if (!d->egl_display) { + qWarning("QtCompositor: Failed to initialize EGL display. Could not get EglDisplay for window."); + return; + } + + const char *extensionString = eglQueryString(d->egl_display, EGL_EXTENSIONS); + if ((!extensionString || !strstr(extensionString, "EGL_WL_bind_wayland_display")) && !ignoreBindDisplay) { + qWarning("QtCompositor: Failed to initialize EGL display. There is no EGL_WL_bind_wayland_display extension."); + return; + } + + d->egl_bind_wayland_display = reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL")); + d->egl_unbind_wayland_display = reinterpret_cast<PFNEGLUNBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglUnbindWaylandDisplayWL")); + if ((!d->egl_bind_wayland_display || !d->egl_unbind_wayland_display) && !ignoreBindDisplay) { + qWarning("QtCompositor: Failed to initialize EGL display. Could not find eglBindWaylandDisplayWL and eglUnbindWaylandDisplayWL."); + return; + } + + d->egl_query_wayland_buffer = reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL_compat>(eglGetProcAddress("eglQueryWaylandBufferWL")); + if (!d->egl_query_wayland_buffer) { + qWarning("QtCompositor: Failed to initialize EGL display. Could not find eglQueryWaylandBufferWL."); + return; + } + + if (d->egl_bind_wayland_display && d->egl_unbind_wayland_display) { + d->display_bound = d->egl_bind_wayland_display(d->egl_display, display); + if (!d->display_bound) { + if (!ignoreBindDisplay) { + qWarning("QtCompositor: Failed to initialize EGL display. Could not bind Wayland display."); + return; + } else { + qWarning("QtCompositor: Could not bind Wayland display. Ignoring."); + } + } + } + + d->eglStreamController = new WaylandEglStreamController(display, this); + + d->funcs = new QEGLStreamConvenience; + d->funcs->initialize(d->egl_display); +} + +QtWayland::ClientBuffer *WaylandEglStreamClientBufferIntegration::createBufferFor(wl_resource *buffer) +{ + if (wl_shm_buffer_get(buffer)) + return nullptr; + + return new WaylandEglStreamClientBuffer(this, buffer); +} + + +WaylandEglStreamClientBuffer::WaylandEglStreamClientBuffer(WaylandEglStreamClientBufferIntegration *integration, wl_resource *buffer) + : ClientBuffer(buffer) + , m_integration(integration) +{ + auto *p = WaylandEglStreamClientBufferIntegrationPrivate::get(m_integration); + d = new BufferState; + if (buffer && !wl_shm_buffer_get(buffer)) { + EGLint width, height; + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_WIDTH, &width); + p->egl_query_wayland_buffer(p->egl_display, buffer, EGL_HEIGHT, &height); + d->size = QSize(width, height); + } +} + +WaylandEglStreamClientBuffer::~WaylandEglStreamClientBuffer() +{ + auto *p = WaylandEglStreamClientBufferIntegrationPrivate::get(m_integration); + + if (p) { + if (d->egl_stream) + p->funcs->destroy_stream(p->egl_display, d->egl_stream); + + for (auto *texture : d->textures) + p->deleteGLTextureWhenPossible(texture); + } + delete d; +} + + +QWaylandBufferRef::BufferFormatEgl WaylandEglStreamClientBuffer::bufferFormatEgl() const +{ + return QWaylandBufferRef::BufferFormatEgl_EXTERNAL_OES; +} + + +QSize WaylandEglStreamClientBuffer::size() const +{ + return d->size; +} + +QWaylandSurface::Origin WaylandEglStreamClientBuffer::origin() const +{ + return d->isYInverted ? QWaylandSurface::OriginTopLeft : QWaylandSurface::OriginBottomLeft; +} + +QOpenGLTexture *WaylandEglStreamClientBuffer::toOpenGlTexture(int plane) +{ + auto *p = WaylandEglStreamClientBufferIntegrationPrivate::get(m_integration); + // At this point we should have a valid OpenGL context, so it's safe to destroy textures + p->deleteOrphanedTextures(); + + if (!m_buffer) + return nullptr; + + return d->textures[plane]; +} + +void WaylandEglStreamClientBuffer::setCommitted(QRegion &damage) +{ + ClientBuffer::setCommitted(damage); + auto *p = WaylandEglStreamClientBufferIntegrationPrivate::get(m_integration); + p->handleEglstreamTexture(this); +} + +QT_END_NAMESPACE diff --git a/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.h b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.h new file mode 100644 index 00000000..d1930204 --- /dev/null +++ b/src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ +#ifndef WAYLANDEGLSTREAMINTEGRATION_H +#define WAYLANDEGLSTREAMINTEGRATION_H + +#include <QtWaylandCompositor/private/qwlclientbufferintegration_p.h> +#include <QtCore/QScopedPointer> +#include <QtWaylandCompositor/private/qwlclientbuffer_p.h> + +QT_BEGIN_NAMESPACE + +class WaylandEglStreamClientBufferIntegrationPrivate; + +class WaylandEglStreamClientBufferIntegration : public QtWayland::ClientBufferIntegration +{ + Q_DECLARE_PRIVATE(WaylandEglStreamClientBufferIntegration) +public: + WaylandEglStreamClientBufferIntegration(); + ~WaylandEglStreamClientBufferIntegration() override; + + void initializeHardware(struct ::wl_display *display) override; + + QtWayland::ClientBuffer *createBufferFor(wl_resource *buffer) override; + + void attachEglStreamConsumer(struct ::wl_resource *wl_surface, struct ::wl_resource *wl_buffer); + +private: + Q_DISABLE_COPY(WaylandEglStreamClientBufferIntegration) + QScopedPointer<WaylandEglStreamClientBufferIntegrationPrivate> d_ptr; +}; + +struct BufferState; + +class WaylandEglStreamClientBuffer : public QtWayland::ClientBuffer +{ +public: + ~WaylandEglStreamClientBuffer() override; + + QWaylandBufferRef::BufferFormatEgl bufferFormatEgl() const override; + QSize size() const override; + QWaylandSurface::Origin origin() const override; + QOpenGLTexture *toOpenGlTexture(int plane) override; + void setCommitted(QRegion &damage) override; + +private: + friend class WaylandEglStreamClientBufferIntegration; + friend class WaylandEglStreamClientBufferIntegrationPrivate; + + WaylandEglStreamClientBuffer(WaylandEglStreamClientBufferIntegration* integration, wl_resource *bufferResource); + + BufferState *d = nullptr; + WaylandEglStreamClientBufferIntegration *m_integration = nullptr; +}; + +QT_END_NAMESPACE + +#endif // WAYLANDEGLSTREAMINTEGRATION_H |