Multi-screen handling for the eglfs_kms_egldevice backend

Separates the generic kms classes into a own kms static lib
called QtEglFsKmsSupport. The eglfs_kms plugin was changed
to use these base classes and got renamed accordingly to
QEglFSKmsGbm*.

The eglfs_kms_egldevice plugin got extended to also derive
from the kms base classed and by this provides multi-screen
support

Change-Id: I6de6a754e94cb8d52cf8e658b03c6bd6637674a1
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
This commit is contained in:
Dominik Holland 2016-03-24 15:38:05 +01:00
parent 920fc1a523
commit 224f31c0b5
25 changed files with 1252 additions and 615 deletions

View File

@ -1,9 +1,12 @@
TEMPLATE = subdirs
contains(QT_CONFIG, egl_x11): SUBDIRS += eglfs_x11
contains(QT_CONFIG, eglfs_gbm): SUBDIRS += eglfs_kms
contains(QT_CONFIG, eglfs_egldevice): SUBDIRS += eglfs_kms_egldevice
contains(QT_CONFIG, eglfs_gbm): SUBDIRS += eglfs_kms_support eglfs_kms
contains(QT_CONFIG, eglfs_egldevice): SUBDIRS += eglfs_kms_support 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
contains(QT_CONFIG, eglfs_viv_wl): SUBDIRS += eglfs_viv_wl
eglfs_kms_egldevice.depends = eglfs_kms_support
eglfs_kms.depends = eglfs_kms_support

View File

@ -1,31 +1,35 @@
TARGET = qeglfs-kms-integration
QT += core-private gui-private platformsupport-private eglfs_device_lib-private
PLUGIN_TYPE = egldeviceintegrations
PLUGIN_CLASS_NAME = QEglFSKmsIntegrationPlugin
load(qt_plugin)
INCLUDEPATH += $$PWD/../..
QT += core-private gui-private platformsupport-private eglfs_device_lib-private eglfs_kms_support-private
INCLUDEPATH += $$PWD/../.. $$PWD/../eglfs_kms_support
# Avoid X11 header collision
DEFINES += MESA_EGL_NO_X11_HEADERS
CONFIG += link_pkgconfig
PKGCONFIG += libdrm gbm
!contains(QT_CONFIG, no-pkg-config) {
PKGCONFIG += libdrm gbm
} else {
LIBS += -ldrm -lgbm
}
CONFIG += egl
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsmain.cpp \
$$PWD/qeglfskmsintegration.cpp \
$$PWD/qeglfskmsdevice.cpp \
$$PWD/qeglfskmsscreen.cpp \
$$PWD/qeglfskmscursor.cpp
SOURCES += $$PWD/qeglfskmsgbmmain.cpp \
$$PWD/qeglfskmsgbmintegration.cpp \
$$PWD/qeglfskmsgbmdevice.cpp \
$$PWD/qeglfskmsgbmscreen.cpp \
$$PWD/qeglfskmsgbmcursor.cpp
HEADERS += $$PWD/qeglfskmsintegration.h \
$$PWD/qeglfskmsdevice.h \
$$PWD/qeglfskmsscreen.h \
$$PWD/qeglfskmscursor.h
HEADERS += $$PWD/qeglfskmsgbmintegration.h \
$$PWD/qeglfskmsgbmdevice.h \
$$PWD/qeglfskmsgbmscreen.h \
$$PWD/qeglfskmsgbmcursor.h
OTHER_FILES += $$PWD/eglfs_kms.json
PLUGIN_TYPE = egldeviceintegrations
PLUGIN_CLASS_NAME = QEglFSKmsIntegrationPlugin
load(qt_plugin)

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -38,9 +39,9 @@
**
****************************************************************************/
#include "qeglfskmscursor.h"
#include "qeglfskmsscreen.h"
#include "qeglfskmsdevice.h"
#include "qeglfskmsgbmcursor.h"
#include "qeglfskmsgbmscreen.h"
#include "qeglfskmsgbmdevice.h"
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
@ -63,7 +64,7 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
QEglFSKmsGbmCursor::QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen)
: m_screen(screen)
, m_cursorSize(64, 64) // 64x64 is the old standard size, we now try to query the real size below
, m_bo(Q_NULLPTR)
@ -83,7 +84,7 @@ QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
m_cursorSize.setHeight(height);
}
m_bo = gbm_bo_create(m_screen->device()->device(), m_cursorSize.width(), m_cursorSize.height(),
m_bo = gbm_bo_create(static_cast<QEglFSKmsGbmDevice *>(m_screen->device())->gbmDevice(), m_cursorSize.width(), m_cursorSize.height(),
GBM_FORMAT_ARGB8888, GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_WRITE);
if (!m_bo) {
qWarning("Could not create buffer for cursor!");
@ -98,7 +99,7 @@ QEglFSKmsCursor::QEglFSKmsCursor(QEglFSKmsScreen *screen)
setPos(QPoint(0, 0));
}
QEglFSKmsCursor::~QEglFSKmsCursor()
QEglFSKmsGbmCursor::~QEglFSKmsGbmCursor()
{
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
@ -110,13 +111,13 @@ QEglFSKmsCursor::~QEglFSKmsCursor()
m_bo = Q_NULLPTR;
}
void QEglFSKmsCursor::pointerEvent(const QMouseEvent &event)
void QEglFSKmsGbmCursor::pointerEvent(const QMouseEvent &event)
{
setPos(event.screenPos().toPoint());
}
#ifndef QT_NO_CURSOR
void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
void QEglFSKmsGbmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_UNUSED(window);
@ -171,12 +172,12 @@ void QEglFSKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
}
#endif // QT_NO_CURSOR
QPoint QEglFSKmsCursor::pos() const
QPoint QEglFSKmsGbmCursor::pos() const
{
return m_pos;
}
void QEglFSKmsCursor::setPos(const QPoint &pos)
void QEglFSKmsGbmCursor::setPos(const QPoint &pos)
{
Q_FOREACH (QPlatformScreen *screen, m_screen->virtualSiblings()) {
QEglFSKmsScreen *kmsScreen = static_cast<QEglFSKmsScreen *>(screen);
@ -192,7 +193,7 @@ void QEglFSKmsCursor::setPos(const QPoint &pos)
}
}
void QEglFSKmsCursor::initCursorAtlas()
void QEglFSKmsGbmCursor::initCursorAtlas()
{
static QByteArray json = qgetenv("QT_QPA_EGLFS_CURSOR");
if (json.isEmpty())

View File

@ -37,8 +37,8 @@
**
****************************************************************************/
#ifndef QEGLFSKMSCURSOR_H
#define QEGLFSKMSCURSOR_H
#ifndef QEGLFSKMSGBMCURSOR_H
#define QEGLFSKMSGBMCURSOR_H
#include <qpa/qplatformcursor.h>
#include <QtCore/QList>
@ -48,15 +48,15 @@
QT_BEGIN_NAMESPACE
class QEglFSKmsScreen;
class QEglFSKmsGbmScreen;
class QEglFSKmsCursor : public QPlatformCursor
class QEglFSKmsGbmCursor : public QPlatformCursor
{
Q_OBJECT
public:
QEglFSKmsCursor(QEglFSKmsScreen *screen);
~QEglFSKmsCursor();
QEglFSKmsGbmCursor(QEglFSKmsGbmScreen *screen);
~QEglFSKmsGbmCursor();
// input methods
void pointerEvent(const QMouseEvent & event) Q_DECL_OVERRIDE;
@ -69,7 +69,7 @@ public:
private:
void initCursorAtlas();
QEglFSKmsScreen *m_screen;
QEglFSKmsGbmScreen *m_screen;
QSize m_cursorSize;
gbm_bo *m_bo;
QPoint m_pos;
@ -89,4 +89,4 @@ private:
QT_END_NAMESPACE
#endif
#endif // QEGLFSKMSGBMCURSOR_H

View File

@ -0,0 +1,158 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 "qeglfskmsgbmdevice.h"
#include "qeglfskmsgbmscreen.h"
#include "qeglfsintegration.h"
#include <QtCore/QLoggingCategory>
#include <QtCore/private/qcore_unix_p.h>
#include <QtGui/private/qguiapplication_p.h>
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
void QEglFSKmsGbmDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
Q_UNUSED(fd);
Q_UNUSED(sequence);
Q_UNUSED(tv_sec);
Q_UNUSED(tv_usec);
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data);
screen->flipFinished();
}
QEglFSKmsGbmDevice::QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path)
: QEglFSKmsDevice(integration, path)
, m_gbm_device(Q_NULLPTR)
, m_globalCursor(Q_NULLPTR)
{
}
bool QEglFSKmsGbmDevice::open()
{
Q_ASSERT(fd() == -1);
Q_ASSERT(m_gbm_device == Q_NULLPTR);
qCDebug(qLcEglfsKmsDebug) << "Opening device" << devicePath();
int fd = qt_safe_open(devicePath().toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
if (fd == -1) {
qErrnoWarning("Could not open DRM device %s", qPrintable(devicePath()));
return false;
}
qCDebug(qLcEglfsKmsDebug) << "Creating GBM device for file descriptor" << fd
<< "obtained from" << devicePath();
m_gbm_device = gbm_create_device(fd);
if (!m_gbm_device) {
qErrnoWarning("Could not create GBM device");
qt_safe_close(fd);
fd = -1;
return false;
}
setFd(fd);
return true;
}
void QEglFSKmsGbmDevice::close()
{
if (m_gbm_device) {
gbm_device_destroy(m_gbm_device);
m_gbm_device = Q_NULLPTR;
}
if (fd() != -1) {
qt_safe_close(fd());
setFd(-1);
}
if (m_globalCursor)
m_globalCursor->deleteLater();
m_globalCursor = Q_NULLPTR;
}
EGLNativeDisplayType QEglFSKmsGbmDevice::device() const
{
return 0;
}
gbm_device * QEglFSKmsGbmDevice::gbmDevice() const
{
return m_gbm_device;
}
QPlatformCursor *QEglFSKmsGbmDevice::globalCursor() const
{
return m_globalCursor;
}
void QEglFSKmsGbmDevice::handleDrmEvent()
{
drmEventContext drmEvent = {
DRM_EVENT_CONTEXT_VERSION,
Q_NULLPTR, // vblank handler
pageFlipHandler // page flip handler
};
drmHandleEvent(fd(), &drmEvent);
}
QEglFSKmsScreen *QEglFSKmsGbmDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
{
static bool firstScreen = true;
QEglFSKmsGbmScreen *screen = new QEglFSKmsGbmScreen(integration, device, output, position);
if (firstScreen && integration->hwCursor()) {
m_globalCursor = new QEglFSKmsGbmCursor(screen);
firstScreen = false;
}
return screen;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,90 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 QEGLFSKMSGBMDEVICE_H
#define QEGLFSKMSGBMDEVICE_H
#include "qeglfskmsgbmcursor.h"
#include "qeglfskmsdevice.h"
#include <gbm.h>
QT_BEGIN_NAMESPACE
class QEglFSKmsScreen;
class QEglFSKmsGbmDevice: public QEglFSKmsDevice
{
public:
QEglFSKmsGbmDevice(QEglFSKmsIntegration *integration, const QString &path);
bool open() Q_DECL_OVERRIDE;
void close() Q_DECL_OVERRIDE;
EGLNativeDisplayType device() const Q_DECL_OVERRIDE;
gbm_device *gbmDevice() const;
QPlatformCursor *globalCursor() const;
void handleDrmEvent();
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position) Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(QEglFSKmsGbmDevice)
gbm_device *m_gbm_device;
QEglFSKmsGbmCursor *m_globalCursor;
static void pageFlipHandler(int fd,
unsigned int sequence,
unsigned int tv_sec,
unsigned int tv_usec,
void *user_data);
};
QT_END_NAMESPACE
#endif // QEGLFSKMSGBMDEVICE_H

View File

@ -0,0 +1,143 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 "qeglfskmsgbmintegration.h"
#include "qeglfskmsgbmdevice.h"
#include "qeglfskmsgbmscreen.h"
#include "qeglfskmsgbmcursor.h"
#include "qeglfscursor.h"
#include <QtPlatformSupport/private/qdevicediscovery_p.h>
#include <QtCore/QLoggingCategory>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
#include <QtGui/qpa/qplatformwindow.h>
#include <QtGui/qpa/qplatformcursor.h>
#include <QtGui/QScreen>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
QT_BEGIN_NAMESPACE
QMutex QEglFSKmsGbmScreen::m_waitForFlipMutex;
QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
: QEglFSKmsIntegration()
{}
EGLNativeWindowType QEglFSKmsGbmIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format)
{
Q_UNUSED(size);
Q_UNUSED(format);
QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(platformWindow->screen());
if (screen->surface()) {
qWarning("Only single window per screen supported!");
return 0;
}
return reinterpret_cast<EGLNativeWindowType>(screen->createSurface());
}
EGLNativeWindowType QEglFSKmsGbmIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
{
Q_UNUSED(format);
Q_ASSERT(device());
qCDebug(qLcEglfsKmsDebug) << "Creating native off screen window";
gbm_surface *surface = gbm_surface_create(static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice(),
1, 1,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_RENDERING);
return reinterpret_cast<EGLNativeWindowType>(surface);
}
void QEglFSKmsGbmIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
gbm_surface *surface = reinterpret_cast<gbm_surface *>(window);
gbm_surface_destroy(surface);
}
QPlatformCursor *QEglFSKmsGbmIntegration::createCursor(QPlatformScreen *screen) const
{
if (hwCursor())
return Q_NULLPTR;
else
return new QEglFSCursor(screen);
}
void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface)
{
QWindow *window = static_cast<QWindow *>(surface->surface());
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(window->screen()->handle());
screen->flip();
}
QEglFSKmsDevice *QEglFSKmsGbmIntegration::createDevice(const QString &devicePath)
{
QString path = devicePath;
if (!devicePath.isEmpty()) {
qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << path << "specified in config file";
} else {
QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask);
QStringList devices = d->scanConnectedDevices();
qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices;
d->deleteLater();
if (Q_UNLIKELY(devices.isEmpty()))
qFatal("Could not find DRM device!");
path = devices.first();
qCDebug(qLcEglfsKmsDebug) << "Using" << path;
}
return new QEglFSKmsGbmDevice(this, path);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,75 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 QEGLFSKMSGBMINTEGRATION_H
#define QEGLFSKMSGBMINTEGRATION_H
#include "qeglfskmsintegration.h"
#include <QtCore/QMap>
#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
class QEglFSKmsDevice;
class QEglFSKmsGbmIntegration : public QEglFSKmsIntegration
{
public:
QEglFSKmsGbmIntegration();
EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format) Q_DECL_OVERRIDE;
EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) Q_DECL_OVERRIDE;
void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE;
void presentBuffer(QPlatformSurface *surface) Q_DECL_OVERRIDE;
protected:
QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE;
private:
};
QT_END_NAMESPACE
#endif // QEGLFSKMSGBMINTEGRATION_H

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the qmake spec of the Qt Toolkit.
@ -38,19 +39,19 @@
****************************************************************************/
#include "qeglfsdeviceintegration.h"
#include "qeglfskmsintegration.h"
#include "qeglfskmsgbmintegration.h"
QT_BEGIN_NAMESPACE
class QEglFSKmsIntegrationPlugin : public QEGLDeviceIntegrationPlugin
class QEglFSKmsGbmIntegrationPlugin : public QEGLDeviceIntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QEGLDeviceIntegrationFactoryInterface_iid FILE "eglfs_kms.json")
public:
QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsIntegration; }
QEGLDeviceIntegration *create() Q_DECL_OVERRIDE { return new QEglFSKmsGbmIntegration; }
};
QT_END_NAMESPACE
#include "qeglfskmsmain.moc"
#include "qeglfskmsgbmmain.moc"

View File

@ -0,0 +1,223 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 "qeglfskmsgbmscreen.h"
#include "qeglfskmsgbmdevice.h"
#include "qeglfskmsgbmcursor.h"
#include "qeglfsintegration.h"
#include <QtCore/QLoggingCategory>
#include <QtGui/private/qguiapplication_p.h>
#include <QtPlatformSupport/private/qfbvthandler_p.h>
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
void QEglFSKmsGbmScreen::bufferDestroyedHandler(gbm_bo *bo, void *data)
{
FrameBuffer *fb = static_cast<FrameBuffer *>(data);
if (fb->fb) {
gbm_device *device = gbm_bo_get_device(bo);
drmModeRmFB(gbm_device_get_fd(device), fb->fb);
}
delete fb;
}
QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(gbm_bo *bo)
{
{
FrameBuffer *fb = static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
if (fb)
return fb;
}
uint32_t width = gbm_bo_get_width(bo);
uint32_t height = gbm_bo_get_height(bo);
uint32_t stride = gbm_bo_get_stride(bo);
uint32_t handle = gbm_bo_get_handle(bo).u32;
QScopedPointer<FrameBuffer> fb(new FrameBuffer);
int ret = drmModeAddFB(device()->fd(), width, height, 24, 32,
stride, handle, &fb->fb);
if (ret) {
qWarning("Failed to create KMS FB!");
return Q_NULLPTR;
}
gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
return fb.take();
}
QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position)
: QEglFSKmsScreen(integration, device, output, position)
, m_gbm_surface(Q_NULLPTR)
, m_gbm_bo_current(Q_NULLPTR)
, m_gbm_bo_next(Q_NULLPTR)
, m_cursor(Q_NULLPTR)
{
}
QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen()
{
}
QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
{
if (integration()->hwCursor()) {
if (!integration()->separateScreens())
return static_cast<QEglFSKmsGbmDevice *>(device())->globalCursor();
if (m_cursor.isNull()) {
QEglFSKmsGbmScreen *that = const_cast<QEglFSKmsGbmScreen *>(this);
that->m_cursor.reset(new QEglFSKmsGbmCursor(that));
}
return m_cursor.data();
} else {
return QEglFSScreen::cursor();
}
}
gbm_surface *QEglFSKmsGbmScreen::createSurface()
{
if (!m_gbm_surface) {
qCDebug(qLcEglfsKmsDebug) << "Creating window for screen" << name();
m_gbm_surface = gbm_surface_create(static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice(),
geometry().width(),
geometry().height(),
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
}
return m_gbm_surface;
}
void QEglFSKmsGbmScreen::destroySurface()
{
if (m_gbm_bo_current) {
gbm_bo_destroy(m_gbm_bo_current);
m_gbm_bo_current = Q_NULLPTR;
}
if (m_gbm_bo_next) {
gbm_bo_destroy(m_gbm_bo_next);
m_gbm_bo_next = Q_NULLPTR;
}
if (m_gbm_surface) {
gbm_surface_destroy(m_gbm_surface);
m_gbm_surface = Q_NULLPTR;
}
}
void QEglFSKmsGbmScreen::waitForFlip()
{
// Don't lock the mutex unless we actually need to
if (!m_gbm_bo_next)
return;
QMutexLocker lock(&m_waitForFlipMutex);
while (m_gbm_bo_next)
static_cast<QEglFSKmsGbmDevice *>(device())->handleDrmEvent();
}
void QEglFSKmsGbmScreen::flip()
{
if (!m_gbm_surface) {
qWarning("Cannot sync before platform init!");
return;
}
m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
if (!m_gbm_bo_next) {
qWarning("Could not lock GBM surface front buffer!");
return;
}
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
if (!output().mode_set) {
int ret = drmModeSetCrtc(device()->fd(),
output().crtc_id,
fb->fb,
0, 0,
&output().connector_id, 1,
&output().modes[output().mode]);
if (ret) {
qErrnoWarning("Could not set DRM mode!");
} else {
output().mode_set = true;
setPowerState(PowerStateOn);
}
}
int ret = drmModePageFlip(device()->fd(),
output().crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
this);
if (ret) {
qErrnoWarning("Could not queue DRM page flip!");
gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
m_gbm_bo_next = Q_NULLPTR;
}
}
void QEglFSKmsGbmScreen::flipFinished()
{
if (m_gbm_bo_current)
gbm_surface_release_buffer(m_gbm_surface,
m_gbm_bo_current);
m_gbm_bo_current = m_gbm_bo_next;
m_gbm_bo_next = Q_NULLPTR;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,93 @@
/****************************************************************************
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** 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 QEGLFSKMSGBMSCREEN_H
#define QEGLFSKMSGBMSCREEN_H
#include "qeglfskmsscreen.h"
#include <QtCore/QMutex>
#include <gbm.h>
QT_BEGIN_NAMESPACE
class QEglFSKmsGbmCursor;
class QEglFSKmsGbmScreen : public QEglFSKmsScreen
{
public:
QEglFSKmsGbmScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position);
~QEglFSKmsGbmScreen();
QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
gbm_surface *surface() const { return m_gbm_surface; }
gbm_surface *createSurface();
void destroySurface();
void waitForFlip() Q_DECL_OVERRIDE;
void flip() Q_DECL_OVERRIDE;
void flipFinished() Q_DECL_OVERRIDE;
private:
gbm_surface *m_gbm_surface;
gbm_bo *m_gbm_bo_current;
gbm_bo *m_gbm_bo_next;
QScopedPointer<QEglFSKmsGbmCursor> m_cursor;
struct FrameBuffer {
FrameBuffer() : fb(0) {}
uint32_t fb;
};
static void bufferDestroyedHandler(gbm_bo *bo, void *data);
FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
static QMutex m_waitForFlipMutex;
};
QT_END_NAMESPACE
#endif // QEGLFSKMSGBMSCREEN_H

View File

@ -1,23 +1,32 @@
TARGET = qeglfs-kms-egldevice-integration
QT += core-private gui-private platformsupport-private eglfs_device_lib-private
QT += core-private gui-private platformsupport-private eglfs_device_lib-private eglfs_kms_support-private
INCLUDEPATH += $$PWD/../..
INCLUDEPATH += $$PWD/../.. $$PWD/../eglfs_kms_support
DEFINES += MESA_EGL_NO_X11_HEADERS
CONFIG += link_pkgconfig
!contains(QT_CONFIG, no-pkg-config) {
PKGCONFIG += libdrm
} else {
LIBS += -ldrm
}
CONFIG += egl
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsegldevicemain.cpp \
$$PWD/qeglfskmsegldeviceintegration.cpp
$$PWD/qeglfskmsegldeviceintegration.cpp \
qeglfskmsegldevice.cpp \
qeglfskmsegldevicescreen.cpp
HEADERS += $$PWD/qeglfskmsegldeviceintegration.h
HEADERS += $$PWD/qeglfskmsegldeviceintegration.h \
qeglfskmsegldevice.h \
qeglfskmsegldevicescreen.h
OTHER_FILES += $$PWD/eglfs_kms_egldevice.json
LIBS += -ldrm
PLUGIN_TYPE = egldeviceintegrations
PLUGIN_CLASS_NAME = QEglFSKmsEglDeviceIntegrationPlugin
load(qt_plugin)

View File

@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2016 Pelagicore AG
** 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 "qeglfskmsegldevice.h"
#include "qeglfskmsegldevicescreen.h"
#include <QtCore/private/qcore_unix_p.h>
QEglFSKmsEglDevice::QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path)
: QEglFSKmsDevice(integration, path)
{
}
bool QEglFSKmsEglDevice::open()
{
Q_ASSERT(fd() == -1);
int fd = drmOpen(devicePath().toLocal8Bit().constData(), Q_NULLPTR);
if (Q_UNLIKELY(fd < 0))
qFatal("Could not open DRM device");
setFd(fd);
return true;
}
void QEglFSKmsEglDevice::close()
{
if (qt_safe_close(fd()) == -1)
qErrnoWarning("Could not close DRM device");
setFd(-1);
}
EGLNativeDisplayType QEglFSKmsEglDevice::device() const
{
return 0;
}
QEglFSKmsScreen *QEglFSKmsEglDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
{
return new QEglFSKmsEglDeviceScreen(integration, device, output, position);
}

View File

@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2016 Pelagicore AG
** 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 QEGLFSKMSEGLDEVICE_H
#define QEGLFSKMSEGLDEVICE_H
#include <qeglfskmsdevice.h>
class QEglFSKmsEglDevice: public QEglFSKmsDevice
{
public:
QEglFSKmsEglDevice(QEglFSKmsIntegration *integration, const QString &path);
virtual bool open() Q_DECL_OVERRIDE;
virtual void close() Q_DECL_OVERRIDE;
virtual EGLNativeDisplayType device() const Q_DECL_OVERRIDE;
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position) Q_DECL_OVERRIDE;
};
#endif // QEGLFSKMSEGLDEVICE_H

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -38,60 +39,26 @@
****************************************************************************/
#include "qeglfskmsegldeviceintegration.h"
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include "qeglfswindow.h"
#include "qeglfskmsegldevice.h"
#include "qeglfskmsscreen.h"
#include <QLoggingCategory>
#include <private/qmath_p.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
QEglFSKmsEglDeviceIntegration::QEglFSKmsEglDeviceIntegration()
: m_dri_fd(-1)
: QEglFSKmsIntegration()
, 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)
, m_funcs(Q_NULLPTR)
{
qCDebug(qLcEglfsKmsDebug, "New DRM/KMS on EGLDevice integration created");
}
void QEglFSKmsEglDeviceIntegration::platformInit()
EGLint QEglFSKmsEglDeviceIntegration::surfaceType() const
{
if (Q_UNLIKELY(!query_egl_device()))
qFatal("Could not set up EGL device!");
const char *deviceName = m_funcs->query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT);
if (Q_UNLIKELY(!deviceName))
qFatal("Failed to query device name from EGLDevice");
qCDebug(qLcEglfsKmsDebug, "Opening %s", deviceName);
m_dri_fd = drmOpen(deviceName, Q_NULLPTR);
if (Q_UNLIKELY(m_dri_fd < 0))
qFatal("Could not open DRM device");
if (Q_UNLIKELY(!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;
delete m_funcs;
m_funcs = Q_NULLPTR;
}
EGLNativeDisplayType QEglFSKmsEglDeviceIntegration::platformDisplay() const
{
return static_cast<EGLNativeDisplayType>(m_egl_device);
return EGL_STREAM_BIT_KHR;
}
EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
@ -120,46 +87,17 @@ EGLDisplay QEglFSKmsEglDeviceIntegration::createDisplay(EGLNativeDisplayType nat
return display;
}
QSizeF QEglFSKmsEglDeviceIntegration::physicalScreenSize() const
bool QEglFSKmsEglDeviceIntegration::supportsSurfacelessContexts() const
{
const int defaultPhysicalDpi = 100;
static const int width = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_WIDTH");
static const int height = qEnvironmentVariableIntValue("QT_QPA_EGLFS_PHYSICAL_HEIGHT");
QSizeF size(width, height);
if (size.isEmpty()) {
size = QSizeF(m_drm_connector->mmWidth, m_drm_connector->mmHeight);
if (size.isEmpty()) {
const float pixelsPerMm = Q_MM_PER_INCH / defaultPhysicalDpi;
size = QSizeF(screenSize().width() * pixelsPerMm, screenSize().height() * pixelsPerMm);
}
}
return size;
// 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;
}
QSize QEglFSKmsEglDeviceIntegration::screenSize() const
bool QEglFSKmsEglDeviceIntegration::supportsPBuffers() 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;
return true;
}
class QEglJetsonTK1Window : public QEglFSWindow
@ -216,11 +154,15 @@ void QEglJetsonTK1Window::resetSurface()
return;
}
QEglFSKmsScreen *cur_screen = static_cast<QEglFSKmsScreen*>(screen());
Q_ASSERT(cur_screen);
qCDebug(qLcEglfsKmsDebug, "Searching for id: %d", cur_screen->output().crtc_id);
for (int i = 0; i < actualCount; ++i) {
EGLAttrib id;
if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_CRTC_EXT, &id)) {
qCDebug(qLcEglfsKmsDebug, " [%d] layer %p - crtc %d", i, layers[i], (int) id);
if (id == EGLAttrib(m_integration->m_drm_crtc))
if (id == EGLAttrib(cur_screen->output().crtc_id))
layer = layers[i];
} else if (m_integration->m_funcs->query_output_layer_attrib(display, layers[i], EGL_DRM_PLANE_EXT, &id)) {
// Not used yet, just for debugging.
@ -251,8 +193,8 @@ void QEglJetsonTK1Window::resetSurface()
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();
const int w = cur_screen->geometry().width();
const int h = cur_screen->geometry().height();
qCDebug(qLcEglfsKmsDebug, "Creating stream producer surface of size %dx%d", w, h);
const EGLint stream_producer_attribs[] = {
@ -280,133 +222,25 @@ QEglFSWindow *QEglFSKmsEglDeviceIntegration::createWindow(QWindow *window) const
return eglWindow;
}
bool QEglFSKmsEglDeviceIntegration::hasCapability(QPlatformIntegration::Capability cap) const
bool QEglFSKmsEglDeviceIntegration::separateScreens() 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) {
// Maybe detecting the DPMS mode could help here, but there are no properties
// exposed on the connector apparently. So rely on an env var for now.
static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
if (!alwaysDoSet) {
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 (Q_UNLIKELY(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 (Q_UNLIKELY(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;
}
QEglFSKmsDevice *QEglFSKmsEglDeviceIntegration::createDevice(const QString &devicePath)
{
Q_UNUSED(devicePath)
if (Q_UNLIKELY(!query_egl_device()))
qFatal("Could not set up EGL device!");
const char *deviceName = m_funcs->query_device_string(m_egl_device, EGL_DRM_DEVICE_FILE_EXT);
if (Q_UNLIKELY(!deviceName))
qFatal("Failed to query device name from EGLDevice");
return new QEglFSKmsEglDevice(this, deviceName);
}
bool QEglFSKmsEglDeviceIntegration::query_egl_device()
{
m_funcs = new QEGLStreamConvenience;

View File

@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -40,17 +41,7 @@
#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 <qeglfskmsintegration.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
@ -59,41 +50,28 @@
QT_BEGIN_NAMESPACE
class QEglFSKmsEglDeviceIntegration : public QEGLDeviceIntegration
class QEglFSKmsEglDeviceIntegration : public QEglFSKmsIntegration
{
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;
EGLDisplay createDisplay(EGLNativeDisplayType nativeDisplay) Q_DECL_OVERRIDE;
bool supportsSurfacelessContexts() const Q_DECL_OVERRIDE;
bool supportsPBuffers() const Q_DECL_OVERRIDE;
QEglFSWindow *createWindow(QWindow *window) const Q_DECL_OVERRIDE;
virtual bool separateScreens() const Q_DECL_OVERRIDE;
protected:
QEglFSKmsDevice *createDevice(const QString &devicePath) Q_DECL_OVERRIDE;
private:
bool setup_kms();
bool query_egl_device();
// 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;
friend class QEglJetsonTK1Window;
// EGLStream infrastructure
QEGLStreamConvenience *m_funcs;
};

View File

@ -0,0 +1,78 @@
/****************************************************************************
**
** Copyright (C) 2016 Pelagicore AG
** 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 "qeglfskmsegldevicescreen.h"
#include "qeglfskmsegldevice.h"
QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
: QEglFSKmsScreen(integration, device, output, position)
{
}
void QEglFSKmsEglDeviceScreen::waitForFlip()
{
if (!output().mode_set) {
output().mode_set = true;
drmModeCrtcPtr currentMode = drmModeGetCrtc(device()->fd(), output().crtc_id);
const bool alreadySet = currentMode
&& currentMode->width == output().modes[output().mode].hdisplay
&& currentMode->height == output().modes[output().mode].vdisplay;
if (currentMode)
drmModeFreeCrtc(currentMode);
if (alreadySet) {
// Maybe detecting the DPMS mode could help here, but there are no properties
// exposed on the connector apparently. So rely on an env var for now.
static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
if (!alwaysDoSet) {
qCDebug(qLcEglfsKmsDebug, "Mode already set");
return;
}
}
qCDebug(qLcEglfsKmsDebug, "Setting mode");
int ret = drmModeSetCrtc(device()->fd(), output().crtc_id,
-1, 0, 0,
&output().connector_id, 1,
&output().modes[output().mode]);
if (ret)
qFatal("drmModeSetCrtc failed");
}
}

View File

@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2016 Pelagicore AG
** 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 QEGLFSKMSEGLDEVICESCREEN_H
#define QEGLFSKMSEGLDEVICESCREEN_H
#include <qeglfskmsscreen.h>
class QEglFSKmsEglDeviceScreen : public QEglFSKmsScreen
{
public:
QEglFSKmsEglDeviceScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position);
void waitForFlip() Q_DECL_OVERRIDE;
};
#endif // QEGLFSKMSEGLDEVICESCREEN_H

View File

@ -0,0 +1,28 @@
TARGET = QtEglFsKmsSupport
CONFIG += no_module_headers internal_module
load(qt_module)
QT += core-private gui-private platformsupport-private eglfs_device_lib-private
INCLUDEPATH += $$PWD/../..
# Avoid X11 header collision
DEFINES += MESA_EGL_NO_X11_HEADERS
CONFIG += link_pkgconfig
!contains(QT_CONFIG, no-pkg-config) {
PKGCONFIG += libdrm
} else {
LIBS += -ldrm
}
CONFIG += egl
QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
SOURCES += $$PWD/qeglfskmsintegration.cpp \
$$PWD/qeglfskmsdevice.cpp \
$$PWD/qeglfskmsscreen.cpp \
HEADERS += $$PWD/qeglfskmsintegration.h \
$$PWD/qeglfskmsdevice.h \
$$PWD/qeglfskmsscreen.h \

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -309,7 +310,7 @@ QEglFSKmsScreen *QEglFSKmsDevice::screenForConnector(drmModeResPtr resources, dr
m_crtc_allocator |= (1 << output.crtc_id);
m_connector_allocator |= (1 << output.connector_id);
return new QEglFSKmsScreen(m_integration, this, output, pos);
return createScreen(m_integration, this, output, pos);
}
drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connector, const QByteArray &name)
@ -328,68 +329,17 @@ drmModePropertyPtr QEglFSKmsDevice::connectorProperty(drmModeConnectorPtr connec
return Q_NULLPTR;
}
void QEglFSKmsDevice::pageFlipHandler(int fd, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, void *user_data)
{
Q_UNUSED(fd);
Q_UNUSED(sequence);
Q_UNUSED(tv_sec);
Q_UNUSED(tv_usec);
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(user_data);
screen->flipFinished();
}
QEglFSKmsDevice::QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path)
: m_integration(integration)
, m_path(path)
, m_dri_fd(-1)
, m_gbm_device(Q_NULLPTR)
, m_crtc_allocator(0)
, m_connector_allocator(0)
, m_globalCursor(Q_NULLPTR)
{
}
bool QEglFSKmsDevice::open()
QEglFSKmsDevice::~QEglFSKmsDevice()
{
Q_ASSERT(m_dri_fd == -1);
Q_ASSERT(m_gbm_device == Q_NULLPTR);
qCDebug(qLcEglfsKmsDebug) << "Opening device" << m_path;
m_dri_fd = qt_safe_open(m_path.toLocal8Bit().constData(), O_RDWR | O_CLOEXEC);
if (m_dri_fd == -1) {
qErrnoWarning("Could not open DRM device %s", qPrintable(m_path));
return false;
}
qCDebug(qLcEglfsKmsDebug) << "Creating GBM device for file descriptor" << m_dri_fd
<< "obtained from" << m_path;
m_gbm_device = gbm_create_device(m_dri_fd);
if (!m_gbm_device) {
qErrnoWarning("Could not create GBM device");
qt_safe_close(m_dri_fd);
m_dri_fd = -1;
return false;
}
return true;
}
void QEglFSKmsDevice::close()
{
if (m_gbm_device) {
gbm_device_destroy(m_gbm_device);
m_gbm_device = Q_NULLPTR;
}
if (m_dri_fd != -1) {
qt_safe_close(m_dri_fd);
m_dri_fd = -1;
}
if (m_globalCursor)
m_globalCursor->deleteLater();
m_globalCursor = Q_NULLPTR;
}
void QEglFSKmsDevice::createScreens()
@ -428,36 +378,27 @@ void QEglFSKmsDevice::createScreens()
if (!m_integration->separateScreens()) {
Q_FOREACH (QPlatformScreen *screen, siblings)
static_cast<QEglFSKmsScreen *>(screen)->setVirtualSiblings(siblings);
if (primaryScreen && m_integration->hwCursor())
m_globalCursor = new QEglFSKmsCursor(primaryScreen);
}
}
gbm_device *QEglFSKmsDevice::device() const
{
return m_gbm_device;
}
int QEglFSKmsDevice::fd() const
{
return m_dri_fd;
}
QPlatformCursor *QEglFSKmsDevice::globalCursor() const
QString QEglFSKmsDevice::devicePath() const
{
return m_globalCursor;
return m_path;
}
void QEglFSKmsDevice::handleDrmEvent()
QEglFSKmsScreen *QEglFSKmsDevice::createScreen(QEglFSKmsIntegration *integration, QEglFSKmsDevice *device, QEglFSKmsOutput output, QPoint position)
{
drmEventContext drmEvent = {
DRM_EVENT_CONTEXT_VERSION,
Q_NULLPTR, // vblank handler
pageFlipHandler // page flip handler
};
return new QEglFSKmsScreen(integration, device, output, position);
}
drmHandleEvent(m_dri_fd, &drmEvent);
void QEglFSKmsDevice::setFd(int fd)
{
m_dri_fd = fd;
}
QT_END_NAMESPACE

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -41,33 +42,35 @@
#ifndef QEGLFSKMSDEVICE_H
#define QEGLFSKMSDEVICE_H
#include "qeglfskmscursor.h"
#include "qeglfskmsintegration.h"
#include "qeglfskmsscreen.h"
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
QT_BEGIN_NAMESPACE
class QEglFSKmsScreen;
class QEglFSKmsDevice
class Q_EGLFS_EXPORT QEglFSKmsDevice
{
public:
QEglFSKmsDevice(QEglFSKmsIntegration *integration, const QString &path);
virtual ~QEglFSKmsDevice();
bool open();
void close();
virtual bool open() = 0;
virtual void close() = 0;
void createScreens();
virtual void createScreens();
gbm_device *device() const;
virtual EGLNativeDisplayType device() const = 0;
int fd() const;
QString devicePath() const;
QPlatformCursor *globalCursor() const;
void handleDrmEvent();
protected:
virtual QEglFSKmsScreen *createScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
QPoint position);
void setFd(int fd);
private:
Q_DISABLE_COPY(QEglFSKmsDevice)
@ -75,13 +78,10 @@ private:
QEglFSKmsIntegration *m_integration;
QString m_path;
int m_dri_fd;
gbm_device *m_gbm_device;
quint32 m_crtc_allocator;
quint32 m_connector_allocator;
QEglFSKmsCursor *m_globalCursor;
int crtcForConnector(drmModeResPtr resources, drmModeConnectorPtr connector);
QEglFSKmsScreen *screenForConnector(drmModeResPtr resources, drmModeConnectorPtr connector, QPoint pos);
drmModePropertyPtr connectorProperty(drmModeConnectorPtr connector, const QByteArray &name);

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -41,11 +42,10 @@
#include "qeglfskmsintegration.h"
#include "qeglfskmsdevice.h"
#include "qeglfskmsscreen.h"
#include "qeglfskmscursor.h"
#include "qeglfswindow.h"
#include "qeglfscursor.h"
#include <QtPlatformSupport/private/qdevicediscovery_p.h>
#include <QtCore/QLoggingCategory>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonArray>
@ -55,17 +55,14 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEglfsKmsDebug, "qt.qpa.eglfs.kms")
QMutex QEglFSKmsScreen::m_waitForFlipMutex;
QEglFSKmsIntegration::QEglFSKmsIntegration()
: m_device(Q_NULLPTR)
, m_hwCursor(true)
, m_hwCursor(false)
, m_pbuffers(false)
, m_separateScreens(false)
{}
@ -76,21 +73,9 @@ void QEglFSKmsIntegration::platformInit()
if (!m_devicePath.isEmpty()) {
qCDebug(qLcEglfsKmsDebug) << "Using DRM device" << m_devicePath << "specified in config file";
} else {
QDeviceDiscovery *d = QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask);
QStringList devices = d->scanConnectedDevices();
qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices;
d->deleteLater();
if (Q_UNLIKELY(devices.isEmpty()))
qFatal("Could not find DRM device!");
m_devicePath = devices.first();
qCDebug(qLcEglfsKmsDebug) << "Using" << m_devicePath;
}
m_device = new QEglFSKmsDevice(this, m_devicePath);
m_device = createDevice(m_devicePath);
if (Q_UNLIKELY(!m_device->open()))
qFatal("Could not open device %s - aborting!", qPrintable(m_devicePath));
}
@ -129,42 +114,6 @@ QSurfaceFormat QEglFSKmsIntegration::surfaceFormatFor(const QSurfaceFormat &inpu
return format;
}
EGLNativeWindowType QEglFSKmsIntegration::createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format)
{
Q_UNUSED(size);
Q_UNUSED(format);
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(platformWindow->screen());
if (screen->surface()) {
qWarning("Only single window per screen supported!");
return 0;
}
return reinterpret_cast<EGLNativeWindowType>(screen->createSurface());
}
EGLNativeWindowType QEglFSKmsIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
{
Q_UNUSED(format);
Q_ASSERT(m_device);
qCDebug(qLcEglfsKmsDebug) << "Creating native off screen window";
gbm_surface *surface = gbm_surface_create(m_device->device(),
1, 1,
GBM_FORMAT_XRGB8888,
GBM_BO_USE_RENDERING);
return reinterpret_cast<EGLNativeWindowType>(surface);
}
void QEglFSKmsIntegration::destroyNativeWindow(EGLNativeWindowType window)
{
gbm_surface *surface = reinterpret_cast<gbm_surface *>(window);
gbm_surface_destroy(surface);
}
bool QEglFSKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@ -177,14 +126,6 @@ bool QEglFSKmsIntegration::hasCapability(QPlatformIntegration::Capability cap) c
}
}
QPlatformCursor *QEglFSKmsIntegration::createCursor(QPlatformScreen *screen) const
{
if (m_hwCursor)
return Q_NULLPTR;
else
return new QEglFSCursor(screen);
}
void QEglFSKmsIntegration::waitForVSync(QPlatformSurface *surface) const
{
QWindow *window = static_cast<QWindow *>(surface->surface());
@ -193,14 +134,6 @@ void QEglFSKmsIntegration::waitForVSync(QPlatformSurface *surface) const
screen->waitForFlip();
}
void QEglFSKmsIntegration::presentBuffer(QPlatformSurface *surface)
{
QWindow *window = static_cast<QWindow *>(surface->surface());
QEglFSKmsScreen *screen = static_cast<QEglFSKmsScreen *>(window->screen()->handle());
screen->flip();
}
bool QEglFSKmsIntegration::supportsPBuffers() const
{
return m_pbuffers;
@ -221,6 +154,11 @@ QMap<QString, QVariantMap> QEglFSKmsIntegration::outputSettings() const
return m_outputSettings;
}
QEglFSKmsDevice *QEglFSKmsIntegration::device() const
{
return m_device;
}
void QEglFSKmsIntegration::loadConfig()
{
static QByteArray json = qgetenv("QT_QPA_EGLFS_KMS_CONFIG");

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -44,12 +45,15 @@
#include "qeglfsdeviceintegration.h"
#include <QtCore/QMap>
#include <QtCore/QVariant>
#include <QtCore/QLoggingCategory>
QT_BEGIN_NAMESPACE
class QEglFSKmsDevice;
class QEglFSKmsIntegration : public QEGLDeviceIntegration
Q_EGLFS_EXPORT Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
class Q_EGLFS_EXPORT QEglFSKmsIntegration : public QEGLDeviceIntegration
{
public:
QEglFSKmsIntegration();
@ -60,21 +64,19 @@ public:
bool usesDefaultScreen() Q_DECL_OVERRIDE;
void screenInit() Q_DECL_OVERRIDE;
QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const Q_DECL_OVERRIDE;
EGLNativeWindowType createNativeWindow(QPlatformWindow *platformWindow,
const QSize &size,
const QSurfaceFormat &format) Q_DECL_OVERRIDE;
EGLNativeWindowType createNativeOffscreenWindow(const QSurfaceFormat &format) Q_DECL_OVERRIDE;
void destroyNativeWindow(EGLNativeWindowType window) Q_DECL_OVERRIDE;
bool hasCapability(QPlatformIntegration::Capability cap) const Q_DECL_OVERRIDE;
QPlatformCursor *createCursor(QPlatformScreen *screen) const Q_DECL_OVERRIDE;
void waitForVSync(QPlatformSurface *surface) const Q_DECL_OVERRIDE;
void presentBuffer(QPlatformSurface *surface) Q_DECL_OVERRIDE;
bool supportsPBuffers() const Q_DECL_OVERRIDE;
bool hwCursor() const;
bool separateScreens() const;
virtual bool hwCursor() const;
virtual bool separateScreens() const;
QMap<QString, QVariantMap> outputSettings() const;
QEglFSKmsDevice *device() const;
protected:
virtual QEglFSKmsDevice *createDevice(const QString &devicePath) = 0;
private:
void loadConfig();

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -40,7 +41,6 @@
#include "qeglfskmsscreen.h"
#include "qeglfskmsdevice.h"
#include "qeglfskmscursor.h"
#include "qeglfsintegration.h"
#include <QtCore/QLoggingCategory>
@ -69,45 +69,6 @@ private:
QEglFSKmsScreen *m_screen;
};
void QEglFSKmsScreen::bufferDestroyedHandler(gbm_bo *bo, void *data)
{
FrameBuffer *fb = static_cast<FrameBuffer *>(data);
if (fb->fb) {
gbm_device *device = gbm_bo_get_device(bo);
drmModeRmFB(gbm_device_get_fd(device), fb->fb);
}
delete fb;
}
QEglFSKmsScreen::FrameBuffer *QEglFSKmsScreen::framebufferForBufferObject(gbm_bo *bo)
{
{
FrameBuffer *fb = static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
if (fb)
return fb;
}
uint32_t width = gbm_bo_get_width(bo);
uint32_t height = gbm_bo_get_height(bo);
uint32_t stride = gbm_bo_get_stride(bo);
uint32_t handle = gbm_bo_get_handle(bo).u32;
QScopedPointer<FrameBuffer> fb(new FrameBuffer);
int ret = drmModeAddFB(m_device->fd(), width, height, 24, 32,
stride, handle, &fb->fb);
if (ret) {
qWarning("Failed to create KMS FB!");
return Q_NULLPTR;
}
gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
return fb.take();
}
QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
QEglFSKmsDevice *device,
QEglFSKmsOutput output,
@ -115,12 +76,8 @@ QEglFSKmsScreen::QEglFSKmsScreen(QEglFSKmsIntegration *integration,
: QEglFSScreen(eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(device->device())))
, m_integration(integration)
, m_device(device)
, m_gbm_surface(Q_NULLPTR)
, m_gbm_bo_current(Q_NULLPTR)
, m_gbm_bo_next(Q_NULLPTR)
, m_output(output)
, m_pos(position)
, m_cursor(Q_NULLPTR)
, m_powerState(PowerStateOn)
, m_interruptHandler(new QEglFSKmsInterruptHandler(this))
{
@ -191,116 +148,20 @@ QString QEglFSKmsScreen::name() const
return m_output.name;
}
QPlatformCursor *QEglFSKmsScreen::cursor() const
{
if (m_integration->hwCursor()) {
if (!m_integration->separateScreens())
return m_device->globalCursor();
if (m_cursor.isNull()) {
QEglFSKmsScreen *that = const_cast<QEglFSKmsScreen *>(this);
that->m_cursor.reset(new QEglFSKmsCursor(that));
}
return m_cursor.data();
} else {
return QEglFSScreen::cursor();
}
}
gbm_surface *QEglFSKmsScreen::createSurface()
{
if (!m_gbm_surface) {
qCDebug(qLcEglfsKmsDebug) << "Creating window for screen" << name();
m_gbm_surface = gbm_surface_create(m_device->device(),
geometry().width(),
geometry().height(),
GBM_FORMAT_XRGB8888,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
}
return m_gbm_surface;
}
void QEglFSKmsScreen::destroySurface()
{
if (m_gbm_bo_current) {
gbm_bo_destroy(m_gbm_bo_current);
m_gbm_bo_current = Q_NULLPTR;
}
if (m_gbm_bo_next) {
gbm_bo_destroy(m_gbm_bo_next);
m_gbm_bo_next = Q_NULLPTR;
}
if (m_gbm_surface) {
gbm_surface_destroy(m_gbm_surface);
m_gbm_surface = Q_NULLPTR;
}
}
void QEglFSKmsScreen::waitForFlip()
{
// Don't lock the mutex unless we actually need to
if (!m_gbm_bo_next)
return;
QMutexLocker lock(&m_waitForFlipMutex);
while (m_gbm_bo_next)
m_device->handleDrmEvent();
}
void QEglFSKmsScreen::flip()
{
if (!m_gbm_surface) {
qWarning("Cannot sync before platform init!");
return;
}
m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
if (!m_gbm_bo_next) {
qWarning("Could not lock GBM surface front buffer!");
return;
}
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
if (!m_output.mode_set) {
int ret = drmModeSetCrtc(m_device->fd(),
m_output.crtc_id,
fb->fb,
0, 0,
&m_output.connector_id, 1,
&m_output.modes[m_output.mode]);
if (ret) {
qErrnoWarning("Could not set DRM mode!");
} else {
m_output.mode_set = true;
setPowerState(PowerStateOn);
}
}
int ret = drmModePageFlip(m_device->fd(),
m_output.crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
this);
if (ret) {
qErrnoWarning("Could not queue DRM page flip!");
gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
m_gbm_bo_next = Q_NULLPTR;
}
}
void QEglFSKmsScreen::flipFinished()
{
if (m_gbm_bo_current)
gbm_surface_release_buffer(m_gbm_surface,
m_gbm_bo_current);
m_gbm_bo_current = m_gbm_bo_next;
m_gbm_bo_next = Q_NULLPTR;
}
void QEglFSKmsScreen::restoreMode()

View File

@ -2,6 +2,7 @@
**
** Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -48,12 +49,10 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <gbm.h>
QT_BEGIN_NAMESPACE
class QEglFSKmsDevice;
class QEglFSKmsCursor;
class QEglFSKmsInterruptHandler;
struct QEglFSKmsOutput
@ -70,7 +69,7 @@ struct QEglFSKmsOutput
drmModePropertyPtr dpms_prop;
};
class QEglFSKmsScreen : public QEglFSScreen
class Q_EGLFS_EXPORT QEglFSKmsScreen : public QEglFSScreen
{
public:
QEglFSKmsScreen(QEglFSKmsIntegration *integration,
@ -90,8 +89,6 @@ public:
QString name() const Q_DECL_OVERRIDE;
QPlatformCursor *cursor() const Q_DECL_OVERRIDE;
qreal refreshRate() const Q_DECL_OVERRIDE;
QList<QPlatformScreen *> virtualSiblings() const Q_DECL_OVERRIDE { return m_siblings; }
@ -100,13 +97,11 @@ public:
QEglFSKmsIntegration *integration() const { return m_integration; }
QEglFSKmsDevice *device() const { return m_device; }
gbm_surface *surface() const { return m_gbm_surface; }
gbm_surface *createSurface();
void destroySurface();
void waitForFlip();
void flip();
void flipFinished();
virtual void waitForFlip();
virtual void flip();
virtual void flipFinished();
QEglFSKmsOutput &output() { return m_output; }
void restoreMode();
@ -119,28 +114,14 @@ public:
private:
QEglFSKmsIntegration *m_integration;
QEglFSKmsDevice *m_device;
gbm_surface *m_gbm_surface;
gbm_bo *m_gbm_bo_current;
gbm_bo *m_gbm_bo_next;
QEglFSKmsOutput m_output;
QPoint m_pos;
QScopedPointer<QEglFSKmsCursor> m_cursor;
QList<QPlatformScreen *> m_siblings;
PowerState m_powerState;
struct FrameBuffer {
FrameBuffer() : fb(0) {}
uint32_t fb;
};
static void bufferDestroyedHandler(gbm_bo *bo, void *data);
FrameBuffer *framebufferForBufferObject(gbm_bo *bo);
static QMutex m_waitForFlipMutex;
QEglFSKmsInterruptHandler *m_interruptHandler;
};