summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Olav Tvete <paul.tvete@qt.io>2019-01-07 15:01:20 +0100
committerJani Heikkinen <jani.heikkinen@qt.io>2019-01-08 11:57:40 +0000
commitc584db87cf924f3a3d883288de8c2f4210186af6 (patch)
tree78b91ca235fa7f881786160949744c6db1071060
parent024be9dcae26a0d88ffb76f9fca252f2135ad7c9 (diff)
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>
-rw-r--r--src/3rdparty/protocol/qt_attribution.json17
-rw-r--r--src/3rdparty/protocol/wl-eglstream-controller.xml37
-rw-r--r--src/client/qwaylandintegration.cpp2
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri16
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.cpp63
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamcontroller.h79
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.cpp439
-rw-r--r--src/hardwareintegration/compositor/wayland-eglstream-controller/waylandeglstreamintegration.h93
-rw-r--r--src/plugins/hardwareintegration/compositor/compositor.pro4
-rw-r--r--src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/main.cpp63
-rw-r--r--src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.json3
-rw-r--r--src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro12
12 files changed, 827 insertions, 1 deletions
diff --git a/src/3rdparty/protocol/qt_attribution.json b/src/3rdparty/protocol/qt_attribution.json
index e5bf91e1..7881e6b0 100644
--- a/src/3rdparty/protocol/qt_attribution.json
+++ b/src/3rdparty/protocol/qt_attribution.json
@@ -103,5 +103,20 @@ Copyright © 2010-2013 Intel Corporation"
"LicenseFile": "HPND_LICENSE.txt",
"Copyright": "Copyright © 2012, 2013 Intel Corporation
Copyright © 2015, 2016 Jan Arne Petersen"
- }
+ },
+
+ {
+ "Id": "wayland-eglstream-controller",
+ "Name": "Wayland EGLStream Controller Protocol",
+ "QDocModule": "qtwaylandcompositor",
+ "QtUsage": "Used in the Qt Wayland Compositor",
+ "Files": "wayland-eglstream-controller.xml",
+
+ "Description": "Allows clients to request that the compositor creates its EGLStream.",
+ "Homepage": "https://github.com/NVIDIA/egl-wayland",
+ "LicenseId": "MIT",
+ "License": "MIT License",
+ "LicenseFile": "MIT_LICENSE.txt",
+ "Copyright": "Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved."
+ }
]
diff --git a/src/3rdparty/protocol/wl-eglstream-controller.xml b/src/3rdparty/protocol/wl-eglstream-controller.xml
new file mode 100644
index 00000000..dea072e6
--- /dev/null
+++ b/src/3rdparty/protocol/wl-eglstream-controller.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wl_eglstream_controller">
+ <copyright>
+ Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the "Software"),
+ to deal in the Software without restriction, including without limitation
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ and/or sell copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ DEALINGS IN THE SOFTWARE.
+ </copyright>
+ <interface name="wl_eglstream_controller" version="1">
+ <request name="attach_eglstream_consumer">
+ <description summary="Create server stream and attach consumer">
+ Creates the corresponding server side EGLStream from the given wl_buffer
+ and attaches a consumer to it.
+ </description>
+ <arg name="wl_surface" type="object" interface="wl_surface"
+ summary="wl_surface corresponds to the client surface associated with
+ newly created eglstream"/>
+ <arg name="wl_resource" type="object" interface="wl_buffer"
+ summary="wl_resource corresponding to an EGLStream"/>
+ </request>
+ </interface>
+</protocol>
diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp
index e935ef31..97e0203c 100644
--- a/src/client/qwaylandintegration.cpp
+++ b/src/client/qwaylandintegration.cpp
@@ -339,6 +339,8 @@ void QWaylandIntegration::initializeClientBufferIntegration()
targetKey = QString::fromLocal8Bit(clientBufferIntegrationName);
} else {
targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration();
+ if (targetKey == QLatin1String("wayland-eglstream-controller"))
+ targetKey = QLatin1String("wayland-egl");
}
if (targetKey.isEmpty()) {
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
diff --git a/src/plugins/hardwareintegration/compositor/compositor.pro b/src/plugins/hardwareintegration/compositor/compositor.pro
index cd47b267..66272e83 100644
--- a/src/plugins/hardwareintegration/compositor/compositor.pro
+++ b/src/plugins/hardwareintegration/compositor/compositor.pro
@@ -19,4 +19,8 @@ qtConfig(wayland-shm-emulation-server-buffer): \
qtConfig(wayland-dmabuf-server-buffer): \
SUBDIRS += dmabuf-server
+qtConfig(wayland-egl): \
+ SUBDIRS += wayland-eglstream-controller
+
+
SUBDIRS += hardwarelayer
diff --git a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/main.cpp b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/main.cpp
new file mode 100644
index 00000000..8e1d5090
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/main.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include <QtWaylandCompositor/private/qwlclientbufferintegrationfactory_p.h>
+#include <QtWaylandCompositor/private/qwlclientbufferintegrationplugin_p.h>
+#include "waylandeglstreamintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWaylandEglStreamClientBufferIntegrationPlugin : public QtWayland::ClientBufferIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QtWaylandClientBufferIntegrationFactoryInterface_iid FILE "wayland-eglstream-controller.json")
+public:
+ QtWayland::ClientBufferIntegration *create(const QString& key, const QStringList& paramList) override;
+};
+
+QtWayland::ClientBufferIntegration *QWaylandEglStreamClientBufferIntegrationPlugin::create(const QString& key, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ Q_UNUSED(key);
+ return new WaylandEglStreamClientBufferIntegration();
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.json b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.json
new file mode 100644
index 00000000..0c94bb77
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "wayland-eglstream-controller" ]
+}
diff --git a/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro
new file mode 100644
index 00000000..f1ca7183
--- /dev/null
+++ b/src/plugins/hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pro
@@ -0,0 +1,12 @@
+QT = waylandcompositor waylandcompositor-private core-private gui-private
+
+OTHER_FILES += wayland-eglstream-controller.json
+
+SOURCES += \
+ main.cpp \
+
+include(../../../../hardwareintegration/compositor/wayland-eglstream-controller/wayland-eglstream-controller.pri)
+
+PLUGIN_TYPE = wayland-graphics-integration-server
+PLUGIN_CLASS_NAME = QWaylandEglStreamBufferIntegrationPlugin
+load(qt_plugin)