summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmintegration.cpp
blob: eb61de3c5346d8ab97e4cd29f691919c660be9e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (C) 2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Pelagicore AG
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

#include "qeglfskmsgbmintegration_p.h"
#include "qeglfskmsgbmdevice_p.h"
#include "qeglfskmsgbmscreen_p.h"
#include "qeglfskmsgbmcursor_p.h"
#include "qeglfskmsgbmwindow_p.h"
#include "private/qeglfscursor_p.h"

#include <QtCore/QLoggingCategory>
#include <QtCore/QFileSystemWatcher>
#include <QtGui/QScreen>
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>

#include <gbm.h>

QT_BEGIN_NAMESPACE

QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
{
    qCDebug(qLcEglfsKmsDebug, "New DRM/KMS via GBM integration created");
}

QEglFSKmsGbmIntegration::~QEglFSKmsGbmIntegration()
{
}

#ifndef EGL_EXT_platform_base
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
#endif

#ifndef EGL_PLATFORM_GBM_KHR
#define EGL_PLATFORM_GBM_KHR 0x31D7
#endif

EGLDisplay QEglFSKmsGbmIntegration::createDisplay(EGLNativeDisplayType nativeDisplay)
{
    qCDebug(qLcEglfsKmsDebug, "Querying EGLDisplay");
    EGLDisplay display;

    PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = nullptr;
    const char *extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (extensions && (strstr(extensions, "EGL_KHR_platform_gbm") || strstr(extensions, "EGL_MESA_platform_gbm"))) {
        getPlatformDisplay = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(
            eglGetProcAddress("eglGetPlatformDisplayEXT"));
    }

    if (getPlatformDisplay) {
        display = getPlatformDisplay(EGL_PLATFORM_GBM_KHR, nativeDisplay, nullptr);
    } else {
        qCDebug(qLcEglfsKmsDebug, "No eglGetPlatformDisplay for GBM, falling back to eglGetDisplay");
        display = eglGetDisplay(nativeDisplay);
    }

    return display;
}

EGLNativeWindowType QEglFSKmsGbmIntegration::createNativeOffscreenWindow(const QSurfaceFormat &format)
{
    Q_UNUSED(format);
    Q_ASSERT(device());

    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 QT_CONFIG(opengl)
    if (!screenConfig()->hwCursor()) {
        qCDebug(qLcEglfsKmsDebug, "Using plain OpenGL mouse cursor");
        return new QEglFSCursor(screen);
    }
#else
    Q_UNUSED(screen);
#endif
    return nullptr;
}

void QEglFSKmsGbmIntegration::presentBuffer(QPlatformSurface *surface)
{
    QWindow *window = static_cast<QWindow *>(surface->surface());
    QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(window->screen()->handle());
    screen->flip();
}

QKmsDevice *QEglFSKmsGbmIntegration::createDevice()
{

    m_deviceDiscovery = std::unique_ptr<QDeviceDiscovery>(QDeviceDiscovery::create(QDeviceDiscovery::Device_VideoMask));
    m_kmsConfigWatcher = std::unique_ptr<QFileSystemWatcher>(new QFileSystemWatcher());

    QString path = screenConfig()->devicePath();
    if (!path.isEmpty()) {
        qCDebug(qLcEglfsKmsDebug) << "GBM: Using DRM device" << path << "specified in config file";
    } else {
        const QStringList devices = m_deviceDiscovery->scanConnectedDevices();
        qCDebug(qLcEglfsKmsDebug) << "Found the following video devices:" << devices;

        if (Q_UNLIKELY(devices.isEmpty()))
            qFatal("Could not find DRM device!");

        path = devices.first();
        qCDebug(qLcEglfsKmsDebug) << "Using" << path;
    }

    bool hotreload = !qEnvironmentVariable("QT_QPA_EGLFS_HOTPLUG_ENABLED").isEmpty();
    if (hotreload) {
        qCWarning(qLcEglfsKmsDebug) << "EGLFS/KMS: Hot-Reload on KMS-events enabled, be aware that"
                                    << "this requires actions in UI code for proper functionallity"
                                    << "(e.g. close/open windows on screen's disconnect/connect)";
        QObject::connect(m_deviceDiscovery.get(), &QDeviceDiscovery::deviceChanged,
                         m_deviceDiscovery.get(), [this](const QString &deviceNode) {
                             qCDebug(qLcEglfsKmsDebug) << "KMS device changed:" << deviceNode;
                             m_device->checkConnectedScreens();
                         });
    }

    QString json = qEnvironmentVariable("QT_QPA_EGLFS_KMS_CONFIG");
    if (json.isEmpty())
        json = qEnvironmentVariable("QT_QPA_KMS_CONFIG");

    if (!json.isEmpty()) {
        m_kmsConfigWatcher->addPath(json);
        QObject::connect(m_kmsConfigWatcher.get(), &QFileSystemWatcher::fileChanged,
                         m_kmsConfigWatcher.get(), [this, json]() {
                             qCDebug(qLcEglfsKmsDebug) << "KMS config-file has changed! path:"
                                                       << json;
                             m_screenConfig->refreshConfig();
                             m_device->updateScreens();
                             m_kmsConfigWatcher->addPath(json); // as per QFileSystemWatcher doc we have to re-add
                                                                // the path in case it's a new file
                         });
    }

    return new QEglFSKmsGbmDevice(screenConfig(), path);
}

QEglFSWindow *QEglFSKmsGbmIntegration::createWindow(QWindow *window) const
{
    return new QEglFSKmsGbmWindow(window, this);
}

QT_END_NAMESPACE