summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-10-13 16:07:19 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2015-10-14 11:39:18 +0000
commitf0d21f6921275032edfc35bf36f71807b90fdfa2 (patch)
tree554dbe11919a711fc911f977b7324400ab64c241
parentbc6d32686cbec7e225999f19ba5fb149507c8dec (diff)
Add support for the Jetson TK1 Pro using EGLDevice
For now we pick one crtc and find the corresponding layer. If this is not desired, set QT_QPA_EGLFS_LAYER_INDEX to override the layer to be used. Enable qt.qpa.eglfs.kms to get logs about the available layers. Change-Id: I762783f960739e32966c8cde17d8f55fbe40091f Done-with: Louai Al-Khanji <louai.al-khanji@theqtcompany.com> Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> Reviewed-by: Louai Al-Khanji <louai.al-khanji@theqtcompany.com>
-rw-r--r--config.tests/qpa/eglfs-egldevice/eglfs-egldevice.cpp53
-rw-r--r--config.tests/qpa/eglfs-egldevice/eglfs-egldevice.pro12
-rwxr-xr-xconfigure12
-rw-r--r--mkspecs/devices/linux-jetson-tk1-pro-g++/qmake.conf38
-rw-r--r--mkspecs/devices/linux-jetson-tk1-pro-g++/qplatformdefs.h34
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro1
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json3
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro21
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp464
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h137
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp49
11 files changed, 823 insertions, 1 deletions
diff --git a/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.cpp b/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.cpp
new file mode 100644
index 0000000000..06809b2624
--- /dev/null
+++ b/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Test both EGLDevice/Output/Stream and DRM as we only use them in combination.
+//
+// Other KMS/DRM tests relying on pkgconfig for libdrm are not suitable since
+// some systems do not use pkgconfig for the graphics stuff.
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+int main(int, char **)
+{
+ EGLDeviceEXT device = 0;
+ EGLStreamKHR stream = 0;
+ EGLOutputLayerEXT layer = 0;
+ drmModeCrtcPtr currentMode = drmModeGetCrtc(0, 0);
+ return EGL_DRM_CRTC_EXT;
+}
diff --git a/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.pro b/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.pro
new file mode 100644
index 0000000000..87214abc7a
--- /dev/null
+++ b/config.tests/qpa/eglfs-egldevice/eglfs-egldevice.pro
@@ -0,0 +1,12 @@
+SOURCES = eglfs-egldevice.cpp
+
+for(p, QMAKE_LIBDIR_EGL) {
+ exists($$p):LIBS += -L$$p
+}
+
+INCLUDEPATH += $$QMAKE_INCDIR_EGL
+LIBS += $$QMAKE_LIBS_EGL
+
+LIBS += -ldrm
+
+CONFIG -= qt
diff --git a/configure b/configure
index 80ed12cdbe..3a32487dcf 100755
--- a/configure
+++ b/configure
@@ -685,6 +685,7 @@ CFG_XCB_XLIB=auto
CFG_XCB_GLX=no
CFG_EGLFS=auto
CFG_EGLFS_BRCM=no
+CFG_EGLFS_EGLDEVICE=no
CFG_EGLFS_MALI=no
CFG_EGLFS_VIV=no
CFG_DIRECTFB=auto
@@ -5746,6 +5747,11 @@ if [ "$CFG_EGLFS" != "no" ]; then
else
CFG_EGLFS_BRCM=no
fi
+ if compileTest qpa/eglfs-egldevice "eglfs-egldevice"; then
+ CFG_EGLFS_EGLDEVICE=yes
+ else
+ CFG_EGLFS_EGLDEVICE=no
+ fi
if compileTest qpa/eglfs-mali "eglfs-mali" \
|| compileTest qpa/eglfs-mali-2 "eglfs-mali-2"; then
CFG_EGLFS_MALI=yes
@@ -6194,6 +6200,9 @@ fi
if [ "$CFG_EGLFS_BRCM" = "yes" ]; then
QT_CONFIG="$QT_CONFIG eglfs_brcm"
fi
+if [ "$CFG_EGLFS_EGLDEVICE" = "yes" ]; then
+ QT_CONFIG="$QT_CONFIG eglfs_egldevice"
+fi
if [ "$CFG_EGLFS_MALI" = "yes" ]; then
QT_CONFIG="$QT_CONFIG eglfs_mali"
fi
@@ -7259,7 +7268,8 @@ report_support " PulseAudio ............." "$CFG_PULSEAUDIO"
report_support " QPA backends:"
report_support " DirectFB ............." "$CFG_DIRECTFB"
report_support " EGLFS ................" "$CFG_EGLFS"
-report_support " EGLFS i.MX6....... ." "$CFG_EGLFS_VIV"
+report_support " EGLFS i.MX6 ........" "$CFG_EGLFS_VIV"
+report_support " EGLFS EGLDevice ...." "$CFG_EGLFS_EGLDEVICE"
report_support " EGLFS KMS .........." "$CFG_KMS"
report_support " EGLFS Mali ........." "$CFG_EGLFS_MALI"
report_support " EGLFS Raspberry Pi ." "$CFG_EGLFS_BRCM"
diff --git a/mkspecs/devices/linux-jetson-tk1-pro-g++/qmake.conf b/mkspecs/devices/linux-jetson-tk1-pro-g++/qmake.conf
new file mode 100644
index 0000000000..ca9ebda087
--- /dev/null
+++ b/mkspecs/devices/linux-jetson-tk1-pro-g++/qmake.conf
@@ -0,0 +1,38 @@
+#
+# qmake configuration for the Jetson TK1 Pro boards
+#
+# A typical configure line might look like:
+# configure \
+# -device jetson-tk1-pro \
+# -device-option VIBRANTE_SDK_TOPDIR=/opt/nvidia/vibrante-vcm30t124-linux
+# -device-option CROSS_COMPILE=/opt/nvidia/toolchains/tegra-4.8.1-nv/usr/bin/arm-cortex_a15-linux-gnueabi/arm-cortex_a15-linux-gnueabi- \
+# -sysroot /opt/nvidia/vibrante-vcm30t124-linux/targetfs \
+# -no-gcc-sysroot
+
+include(../common/linux_device_pre.conf)
+
+isEmpty(VIBRANTE_SDK_TOPDIR):error("You must pass -device-option VIBRANTE_SDK_TOPDIR=/path/to/sdk")
+
+QMAKE_INCDIR += \
+ $${VIBRANTE_SDK_TOPDIR}/include \
+ $$[QT_SYSROOT]/usr/include
+
+QMAKE_LIBDIR += \
+ $${VIBRANTE_SDK_TOPDIR}/lib-target \
+ $$[QT_SYSROOT]/usr/lib \
+ $$[QT_SYSROOT]/lib/arm-linux-gnueabihf \
+ $$[QT_SYSROOT]/usr/lib/arm-linux-gnueabihf
+
+QMAKE_LFLAGS += \
+ -Wl,-rpath-link,$${VIBRANTE_SDK_TOPDIR}/lib-target \
+ -Wl,-rpath-link,$$[QT_SYSROOT]/usr/lib \
+ -Wl,-rpath-link,$$[QT_SYSROOT]/usr/lib/arm-linux-gnueabihf \
+ -Wl,-rpath-link,$$[QT_SYSROOT]/lib/arm-linux-gnueabihf
+
+DISTRO_OPTS += hard-float
+COMPILER_FLAGS += -mtune=cortex-a15 -march=armv7-a -mfpu=neon-vfpv4 -DWIN_INTERFACE_CUSTOM
+
+EGLFS_DEVICE_INTEGRATION = eglfs_kms_egldevice
+
+include(../common/linux_arm_device_post.conf)
+load(qt_config)
diff --git a/mkspecs/devices/linux-jetson-tk1-pro-g++/qplatformdefs.h b/mkspecs/devices/linux-jetson-tk1-pro-g++/qplatformdefs.h
new file mode 100644
index 0000000000..beacd150b8
--- /dev/null
+++ b/mkspecs/devices/linux-jetson-tk1-pro-g++/qplatformdefs.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "../../linux-g++/qplatformdefs.h"
diff --git a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
index 0adbb0d49f..f8bb854f1c 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
+++ b/src/plugins/platforms/eglfs/deviceintegration/deviceintegration.pro
@@ -2,6 +2,7 @@ TEMPLATE = subdirs
contains(QT_CONFIG, egl_x11): SUBDIRS += eglfs_x11
contains(QT_CONFIG, kms): SUBDIRS += eglfs_kms
+contains(QT_CONFIG, eglfs_egldevice): SUBDIRS += eglfs_kms_egldevice
contains(QT_CONFIG, eglfs_brcm): SUBDIRS += eglfs_brcm
contains(QT_CONFIG, eglfs_mali): SUBDIRS += eglfs_mali
contains(QT_CONFIG, eglfs_viv): SUBDIRS += eglfs_viv
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json
new file mode 100644
index 0000000000..169ba1eb02
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "eglfs_kms_egldevice" ]
+}
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
new file mode 100644
index 0000000000..2274c5b228
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/eglfs_kms_egldevice.pro
@@ -0,0 +1,21 @@
+TARGET = qeglfs-kms-egldevice-integration
+
+PLUGIN_TYPE = egldeviceintegrations
+PLUGIN_CLASS_NAME = QEglFSKmsEglDeviceIntegrationPlugin
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private eglfs_device_lib-private
+
+INCLUDEPATH += $$PWD/../..
+
+CONFIG += egl
+QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
+
+SOURCES += $$PWD/qeglfskmsegldevicemain.cpp \
+ $$PWD/qeglfskmsegldeviceintegration.cpp
+
+HEADERS += $$PWD/qeglfskmsegldeviceintegration.h
+
+OTHER_FILES += $$PWD/eglfs_kms_egldevice.json
+
+LIBS += -ldrm
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
new file mode 100644
index 0000000000..2f32bd73a3
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.cpp
@@ -0,0 +1,464 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfskmsegldeviceintegration.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
+
+QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration()
+ : m_dri_fd(-1)
+ , m_egl_device(EGL_NO_DEVICE_EXT)
+ , m_egl_display(EGL_NO_DISPLAY)
+ , m_drm_connector(Q_NULLPTR)
+ , m_drm_encoder(Q_NULLPTR)
+ , m_drm_crtc(0)
+{
+ qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created");
+}
+
+void QEglFSKmsEglDeviceIntegration::platformInit()
+{
+ if (!query_egl_device())
+ qFatal("Could not set up EGL device!");
+
+ const char *deviceName = m_query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT);
+ if (!deviceName)
+ qFatal("Failed to query device name from EGLDevice");
+
+ qCDebug(qLcEglfsKmsDebug, "Opening %s", deviceName);
+
+ m_dri_fd = drmOpen(deviceName, Q_NULLPTR);
+ if (m_dri_fd < 0)
+ qFatal("Could not open DRM device");
+
+ if (!setup_kms())
+ qFatal("Could not set up KMS on device %s!", m_device.constData());
+
+ qCDebug(qLcEglfsKmsDebug, "DRM/KMS initialized");
+}
+
+void QEglFSKmsEglDeviceIntegration::platformDestroy()
+{
+ if (qt_safe_close(m_dri_fd) == -1)
+ qErrnoWarning("Could not close DRM device");
+
+ m_dri_fd = -1;
+}
+
+EGLNativeDisplayType QEglFSKmsEglDeviceIntegration::platformDisplay() const
+{
+ return static_cast<EGLNativeDisplayType>(m_egl_device);
+}
+
+EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
+{
+ qCDebug(qLcEglfsKmsDebug, "Creating display");
+
+ const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+
+ m_get_platform_display = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
+ m_has_egl_platform_device = extensions && strstr(extensions, "EGL_EXT_platform_device");
+
+ EGLDisplay display;
+
+ if (!m_has_egl_platform_device) {
+ qWarning("EGL_EXT_platform_device not available, falling back to legacy path!");
+ display = eglGetDisplay(nativeDisplay);
+ } else {
+ display = m_get_platform_display(EGL_PLATFORM_DEVICE_EXT, nativeDisplay, Q_NULLPTR);
+ }
+
+ if (display == EGL_NO_DISPLAY)
+ qFatal("Could not get EGL display");
+
+ EGLint major, minor;
+ if (!eglInitialize(display, &major, &minor))
+ qFatal("Could not initialize egl display");
+
+ if (!eglBindAPI(EGL_OPENGL_ES_API))
+ qFatal("Failed to bind EGL_OPENGL_ES_API\n");
+
+ return display;
+}
+
+QSizeF QEglFSKmsEglDeviceIntegration::physicalScreenSize() const
+{
+ return QSizeF(m_drm_connector->mmWidth, m_drm_connector->mmHeight);
+}
+
+QSize QEglFSKmsEglDeviceIntegration::screenSize() const
+{
+ return QSize(m_drm_mode.hdisplay, m_drm_mode.vdisplay);
+}
+
+int QEglFSKmsEglDeviceIntegration::screenDepth() const
+{
+ return 32;
+}
+
+QSurfaceFormat QEglFSKmsEglDeviceIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+{
+ QSurfaceFormat format(inputFormat);
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ format.setRedBufferSize(8);
+ format.setGreenBufferSize(8);
+ format.setBlueBufferSize(8);
+ return format;
+}
+
+EGLint QEglFSKmsEglDeviceIntegration::surfaceType() const
+{
+ return EGL_STREAM_BIT_KHR;
+}
+
+class QEglJetsonTK1Window : public QEglFSWindow
+{
+public:
+ QEglJetsonTK1Window(QWindow *w, const QEglFSKmsEglDeviceIntegration *integration)
+ : QEglFSWindow(w)
+ , m_integration(integration)
+ , m_egl_stream(EGL_NO_STREAM_KHR)
+ { }
+
+ void invalidateSurface() Q_DECL_OVERRIDE;
+ void resetSurface() Q_DECL_OVERRIDE;
+
+ const QEglFSKmsEglDeviceIntegration *m_integration;
+ EGLStreamKHR m_egl_stream;
+ EGLint m_latency;
+};
+
+void QEglJetsonTK1Window::invalidateSurface()
+{
+ QEglFSWindow::invalidateSurface();
+ m_integration->m_destroy_stream(screen()->display(), m_egl_stream);
+}
+
+void QEglJetsonTK1Window::resetSurface()
+{
+ qCDebug(qLcEglfsKmsDebug, "Creating stream");
+
+ EGLDisplay display = screen()->display();
+ EGLOutputLayerEXT layer = EGL_NO_OUTPUT_LAYER_EXT;
+ EGLint count;
+
+ m_egl_stream = m_integration->m_create_stream(display, Q_NULLPTR);
+ if (m_egl_stream == EGL_NO_STREAM_KHR) {
+ qWarning("resetSurface: Couldn't create EGLStream for native window");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Created stream %p on display %p", m_egl_stream, display);
+
+ if (!m_integration->m_get_output_layers(display, Q_NULLPTR, Q_NULLPTR, 0, &count) || count == 0) {
+ qWarning("No output layers found");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Output has %d layers", count);
+
+ QVector<EGLOutputLayerEXT> layers;
+ layers.resize(count);
+ EGLint actualCount;
+ if (!m_integration->m_get_output_layers(display, Q_NULLPTR, layers.data(), count, &actualCount)) {
+ qWarning("Failed to get layers");
+ return;
+ }
+
+ for (int i = 0; i < actualCount; ++i) {
+ EGLAttrib id;
+ if (m_integration->m_query_output_layer_attrib(display, layers[i], EGL_DRM_CRTC_EXT, &id)) {
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], id);
+ if (id == EGLAttrib(m_integration->m_drm_crtc))
+ layer = layers[i];
+ } else if (m_integration->m_query_output_layer_attrib(display, layers[i], EGL_DRM_PLANE_EXT, &id)) {
+ // Not used yet, just for debugging.
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - plane %d", i, layers[i], id);
+ } else {
+ qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - unknown", i, layers[i]);
+ }
+ }
+
+ QByteArray reqLayerIndex = qgetenv("QT_QPA_EGLFS_LAYER_INDEX");
+ if (!reqLayerIndex.isEmpty()) {
+ int idx = reqLayerIndex.toInt();
+ if (idx >= 0 && idx < layers.count())
+ layer = layers[idx];
+ }
+
+ if (layer == EGL_NO_OUTPUT_LAYER_EXT) {
+ qWarning("resetSurface: Couldn't get EGLOutputLayer for native window");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Using layer %p", layer);
+
+ if (!m_integration->m_stream_consumer_output(display, m_egl_stream, layer))
+ qWarning("resetSurface: Unable to connect stream");
+
+ m_config = QEglFSIntegration::chooseConfig(display, m_integration->surfaceFormatFor(window()->requestedFormat()));
+ m_format = q_glFormatFromConfig(display, m_config);
+ qCDebug(qLcEglfsKmsDebug) << "Stream producer format is" << m_format;
+
+ const int w = m_integration->screenSize().width();
+ const int h = m_integration->screenSize().height();
+ qCDebug(qLcEglfsKmsDebug, "Creating stream producer surface of size %dx%d", w, h);
+
+ const EGLint stream_producer_attribs[] = {
+ EGL_WIDTH, w,
+ EGL_HEIGHT, h,
+ EGL_NONE
+ };
+
+ m_surface = m_integration->m_create_stream_producer_surface(display, m_config, m_egl_stream, stream_producer_attribs);
+ if (m_surface == EGL_NO_SURFACE)
+ return;
+
+ qCDebug(qLcEglfsKmsDebug, "Created stream producer surface %p", m_surface);
+}
+
+QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
+{
+ QEglJetsonTK1Window *eglWindow = new QEglJetsonTK1Window(window, this);
+
+ if (!const_cast<QEglFSKmsEglDeviceIntegration *>(this)->query_egl_extensions(eglWindow->screen()->display()))
+ qFatal("Required extensions missing!");
+
+ return eglWindow;
+}
+
+bool QEglFSKmsEglDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case QPlatformIntegration::ThreadedPixmaps:
+ case QPlatformIntegration::OpenGL:
+ case QPlatformIntegration::ThreadedOpenGL:
+ case QPlatformIntegration::BufferQueueingOpenGL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void QEglFSKmsEglDeviceIntegration::waitForVSync(QPlatformSurface *) const
+{
+ static bool mode_set = false;
+
+ if (!mode_set) {
+ mode_set = true;
+
+ drmModeCrtcPtr currentMode = drmModeGetCrtc(m_dri_fd, m_drm_crtc);
+ const bool alreadySet = currentMode
+ && currentMode->width == m_drm_mode.hdisplay
+ && currentMode->height == m_drm_mode.vdisplay;
+ if (currentMode)
+ drmModeFreeCrtc(currentMode);
+ if (alreadySet) {
+ qCDebug(qLcEglfsKmsDebug, "Mode already set");
+ return;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Setting mode");
+ int ret = drmModeSetCrtc(m_dri_fd, m_drm_crtc,
+ -1, 0, 0,
+ &m_drm_connector->connector_id, 1,
+ const_cast<const drmModeModeInfoPtr>(&m_drm_mode));
+ if (ret)
+ qFatal("drmModeSetCrtc failed");
+ }
+}
+
+qreal QEglFSKmsEglDeviceIntegration::refreshRate() const
+{
+ quint32 refresh = m_drm_mode.vrefresh;
+ return refresh > 0 ? refresh : 60;
+}
+
+bool QEglFSKmsEglDeviceIntegration::supportsSurfacelessContexts() const
+{
+ // Returning false disables the usage of EGL_KHR_surfaceless_context even when the
+ // extension is available. This is just what we need since, at least with NVIDIA
+ // 352.00 making a null surface current with a context breaks.
+ return false;
+}
+
+bool QEglFSKmsEglDeviceIntegration::setup_kms()
+{
+ drmModeRes *resources;
+ drmModeConnector *connector;
+ drmModeEncoder *encoder;
+ quint32 crtc = 0;
+ int i;
+
+ resources = drmModeGetResources(m_dri_fd);
+ if (!resources) {
+ qWarning("drmModeGetResources failed");
+ return false;
+ }
+
+ for (i = 0; i < resources->count_connectors; i++) {
+ connector = drmModeGetConnector(m_dri_fd, resources->connectors[i]);
+ if (!connector)
+ continue;
+
+ if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0)
+ break;
+
+ drmModeFreeConnector(connector);
+ }
+
+ if (i == resources->count_connectors) {
+ qWarning("No currently active connector found.");
+ return false;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Using connector with type %d", connector->connector_type);
+
+ for (i = 0; i < resources->count_encoders; i++) {
+ encoder = drmModeGetEncoder(m_dri_fd, resources->encoders[i]);
+ if (!encoder)
+ continue;
+
+ if (encoder->encoder_id == connector->encoder_id)
+ break;
+
+ drmModeFreeEncoder(encoder);
+ }
+
+ for (int j = 0; j < resources->count_crtcs; j++) {
+ if ((encoder->possible_crtcs & (1 << j))) {
+ crtc = resources->crtcs[j];
+ break;
+ }
+ }
+
+ if (crtc == 0)
+ qFatal("No suitable CRTC available");
+
+ m_drm_connector = connector;
+ m_drm_encoder = encoder;
+ m_drm_mode = connector->modes[0];
+ m_drm_crtc = crtc;
+
+ qCDebug(qLcEglfsKmsDebug).noquote() << "Using crtc" << m_drm_crtc
+ << "with mode" << m_drm_mode.hdisplay << "x" << m_drm_mode.vdisplay
+ << "@" << m_drm_mode.vrefresh;
+
+ drmModeFreeResources(resources);
+
+ return true;
+}
+
+bool QEglFSKmsEglDeviceIntegration::query_egl_device()
+{
+ const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning("eglQueryString failed");
+ return false;
+ }
+
+ m_has_egl_device_base = strstr(extensions, "EGL_EXT_device_base");
+ m_query_devices = reinterpret_cast<PFNEGLQUERYDEVICESEXTPROC>(eglGetProcAddress("eglQueryDevicesEXT"));
+ m_query_device_string = reinterpret_cast<PFNEGLQUERYDEVICESTRINGEXTPROC>(eglGetProcAddress("eglQueryDeviceStringEXT"));
+
+ if (!m_has_egl_device_base || !m_query_devices || !m_query_device_string)
+ qFatal("EGL_EXT_device_base missing");
+
+ EGLint num_devices = 0;
+ if (m_query_devices(1, &m_egl_device, &num_devices) != EGL_TRUE) {
+ qWarning("eglQueryDevicesEXT failed: eglError: %x", eglGetError());
+ return false;
+ }
+
+ qCDebug(qLcEglfsKmsDebug, "Found %d EGL devices", num_devices);
+
+ if (num_devices < 1 || m_egl_device == EGL_NO_DEVICE_EXT) {
+ qWarning("eglQueryDevicesEXT could not find any EGL devices");
+ return false;
+ }
+
+ return true;
+}
+
+bool QEglFSKmsEglDeviceIntegration::query_egl_extensions(EGLDisplay display)
+{
+ if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ qWarning() << Q_FUNC_INFO << "failed to bind EGL_OPENGL_ES_API";
+ return false;
+ }
+
+ m_create_stream = reinterpret_cast<PFNEGLCREATESTREAMKHRPROC>(eglGetProcAddress("eglCreateStreamKHR"));
+ m_destroy_stream = reinterpret_cast<PFNEGLDESTROYSTREAMKHRPROC>(eglGetProcAddress("eglDestroyStreamKHR"));
+ m_stream_attrib = reinterpret_cast<PFNEGLSTREAMATTRIBKHRPROC>(eglGetProcAddress("eglStreamAttribKHR"));
+ m_query_stream = reinterpret_cast<PFNEGLQUERYSTREAMKHRPROC>(eglGetProcAddress("eglQueryStreamKHR"));
+ m_query_stream_u64 = reinterpret_cast<PFNEGLQUERYSTREAMU64KHRPROC>(eglGetProcAddress("eglQueryStreamu64KHR"));
+ m_create_stream_producer_surface = reinterpret_cast<PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC>(eglGetProcAddress("eglCreateStreamProducerSurfaceKHR"));
+ m_stream_consumer_output = reinterpret_cast<PFNEGLSTREAMCONSUMEROUTPUTEXTPROC>(eglGetProcAddress("eglStreamConsumerOutputEXT"));
+ m_get_output_layers = reinterpret_cast<PFNEGLGETOUTPUTLAYERSEXTPROC>(eglGetProcAddress("eglGetOutputLayersEXT"));
+ m_get_output_ports = reinterpret_cast<PFNEGLGETOUTPUTPORTSEXTPROC>(eglGetProcAddress("eglGetOutputPortsEXT"));
+ m_output_layer_attrib = reinterpret_cast<PFNEGLOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglOutputLayerAttribEXT"));
+ m_query_output_layer_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputLayerAttribEXT"));
+ m_query_output_layer_string = reinterpret_cast<PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputLayerStringEXT"));
+ m_query_output_port_attrib = reinterpret_cast<PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC>(eglGetProcAddress("eglQueryOutputPortAttribEXT"));
+ m_query_output_port_string = reinterpret_cast<PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC>(eglGetProcAddress("eglQueryOutputPortStringEXT"));
+ m_get_stream_file_descriptor = reinterpret_cast<PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglGetStreamFileDescriptorKHR"));
+ m_create_stream_from_file_descriptor = reinterpret_cast<PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC>(eglGetProcAddress("eglCreateStreamFromFileDescriptorKHR"));
+ m_stream_consumer_gltexture = reinterpret_cast<PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC>(eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR"));
+ m_stream_consumer_acquire = reinterpret_cast<PFNEGLSTREAMCONSUMERACQUIREKHRPROC>(eglGetProcAddress("eglStreamConsumerAcquireKHR"));
+
+ const char *extensions = eglQueryString(display, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning() << Q_FUNC_INFO << "eglQueryString failed";
+ return false;
+ }
+
+ m_has_egl_stream = strstr(extensions, "EGL_KHR_stream");
+ m_has_egl_stream_producer_eglsurface = strstr(extensions, "EGL_KHR_stream_producer_eglsurface");
+ m_has_egl_stream_consumer_egloutput = strstr(extensions, "EGL_EXT_stream_consumer_egloutput");
+ m_has_egl_output_drm = strstr(extensions, "EGL_EXT_output_drm");
+ m_has_egl_output_base = strstr(extensions, "EGL_EXT_output_base");
+ m_has_egl_stream_cross_process_fd = strstr(extensions, "EGL_KHR_stream_cross_process_fd");
+ m_has_egl_stream_consumer_gltexture = strstr(extensions, "EGL_KHR_stream_consumer_gltexture");
+
+ return m_has_egl_output_base &&
+ m_has_egl_output_drm &&
+ m_has_egl_stream &&
+ m_has_egl_stream_producer_eglsurface &&
+ m_has_egl_stream_consumer_egloutput;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
new file mode 100644
index 0000000000..c6132354a8
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldeviceintegration.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QEGLFSKMSEGLDEVICEINTEGRATION_H
+#define QEGLFSKMSEGLDEVICEINTEGRATION_H
+
+#include "qeglfsdeviceintegration.h"
+#include "qeglfswindow.h"
+#include "qeglfsintegration.h"
+
+#include <QtPlatformSupport/private/qdevicediscovery_p.h>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
+#include <QtCore/private/qcore_unix_p.h>
+#include <QtCore/QScopedPointer>
+#include <QtGui/qpa/qplatformwindow.h>
+#include <QtGui/qguiapplication.h>
+#include <QDebug>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsEglDeviceIntegration : public QEGLDeviceIntegration
+{
+public:
+ QEglFSKmsEglDeviceIntegration();
+
+ void platformInit() Q_DECL_OVERRIDE;
+ void platformDestroy() Q_DECL_OVERRIDE;
+ EGLNativeDisplayType platformDisplay() const Q_DECL_OVERRIDE;
+ EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) Q_DECL_OVERRIDE;
+ QSizeF physicalScreenSize() const Q_DECL_OVERRIDE;
+ QSize screenSize() const Q_DECL_OVERRIDE;
+ int screenDepth() const Q_DECL_OVERRIDE;
+ qreal refreshRate() const Q_DECL_OVERRIDE;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
+ EGLint surfaceType() const Q_DECL_OVERRIDE;
+ QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
+ bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
+ void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE;
+ bool supportsSurfacelessContexts() const Q_DECL_OVERRIDE;
+
+ bool setup_kms();
+
+ bool query_egl_device();
+ bool query_egl_extensions(EGLDisplay display);
+
+ // device bits
+ QByteArray m_device;
+ int m_dri_fd;
+ EGLDeviceEXT m_egl_device;
+ EGLDisplay m_egl_display;
+
+ // KMS bits
+ drmModeConnector *m_drm_connector;
+ drmModeEncoder *m_drm_encoder;
+ drmModeModeInfo m_drm_mode;
+ quint32 m_drm_crtc;
+
+ // EGLStream infrastructure
+ PFNEGLGETPLATFORMDISPLAYEXTPROC m_get_platform_display;
+ bool m_has_egl_platform_device;
+
+ PFNEGLQUERYDEVICESEXTPROC m_query_devices;
+ PFNEGLQUERYDEVICESTRINGEXTPROC m_query_device_string;
+ bool m_has_egl_device_base;
+
+ PFNEGLCREATESTREAMKHRPROC m_create_stream;
+ PFNEGLDESTROYSTREAMKHRPROC m_destroy_stream;
+ PFNEGLSTREAMATTRIBKHRPROC m_stream_attrib;
+ PFNEGLQUERYSTREAMKHRPROC m_query_stream;
+ PFNEGLQUERYSTREAMU64KHRPROC m_query_stream_u64;
+ bool m_has_egl_stream;
+
+ PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC m_create_stream_producer_surface;
+ bool m_has_egl_stream_producer_eglsurface;
+
+ PFNEGLSTREAMCONSUMEROUTPUTEXTPROC m_stream_consumer_output;
+ bool m_has_egl_stream_consumer_egloutput;
+
+ bool m_has_egl_output_drm;
+
+ PFNEGLGETOUTPUTLAYERSEXTPROC m_get_output_layers;
+ PFNEGLGETOUTPUTPORTSEXTPROC m_get_output_ports;
+ PFNEGLOUTPUTLAYERATTRIBEXTPROC m_output_layer_attrib;
+ PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC m_query_output_layer_attrib;
+ PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC m_query_output_layer_string;
+ PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC m_query_output_port_attrib;
+ PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC m_query_output_port_string;
+ bool m_has_egl_output_base;
+
+ PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC m_get_stream_file_descriptor;
+ PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC m_create_stream_from_file_descriptor;
+ bool m_has_egl_stream_cross_process_fd;
+
+ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC m_stream_consumer_gltexture;
+ PFNEGLSTREAMCONSUMERACQUIREKHRPROC m_stream_consumer_acquire;
+ bool m_has_egl_stream_consumer_gltexture;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
new file mode 100644
index 0000000000..f987ae38a6
--- /dev/null
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms_egldevice/qeglfskmsegldevicemain.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the qmake spec of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** 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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfskmsegldeviceintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSKmsEglDeviceIntegrationPlugin : public QEGLDeviceIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms_egldevice.json")
+
+public:
+ QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsEglDeviceIntegration; }
+};
+
+QT_END_NAMESPACE
+
+#include "qeglfskmsegldevicemain.moc"