Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeglfskmsegldevicescreen.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Pelagicore AG
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <private/qeglfskmsintegration_p.h>
9
10#include <QGuiApplication>
11#include <QLoggingCategory>
12#include <errno.h>
13
14QT_BEGIN_NAMESPACE
15
16QEglFSKmsEglDeviceScreen::QEglFSKmsEglDeviceScreen(QEglFSKmsDevice *device, const QKmsOutput &output)
17 : QEglFSKmsScreen(device, output)
18 , m_default_fb_handle(uint32_t(-1))
19 , m_default_fb_id(uint32_t(-1))
20{
21 const int fd = device->fd();
22
23 struct drm_mode_create_dumb createRequest;
24 createRequest.width = output.size.width();
25 createRequest.height = output.size.height();
26 createRequest.bpp = 32;
27 createRequest.flags = 0;
28
29 qCDebug(qLcEglfsKmsDebug, "Creating dumb fb %dx%d", createRequest.width, createRequest.height);
30
31 int ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &createRequest);
32 if (ret < 0)
33 qFatal("Unable to create dumb buffer.\n");
34
35 m_default_fb_handle = createRequest.handle;
36
37 uint32_t handles[4] = { 0, 0, 0, 0 };
38 uint32_t pitches[4] = { 0, 0, 0, 0 };
39 uint32_t offsets[4] = { 0, 0, 0, 0 };
40
41 handles[0] = createRequest.handle;
42 pitches[0] = createRequest.pitch;
43 offsets[0] = 0;
44
45 ret = drmModeAddFB2(fd, createRequest.width, createRequest.height, DRM_FORMAT_ARGB8888, handles,
46 pitches, offsets, &m_default_fb_id, 0);
47 if (ret)
48 qFatal("Unable to add fb\n");
49
50 qCDebug(qLcEglfsKmsDebug, "Added dumb fb %dx%d handle:%u pitch:%d id:%u", createRequest.width, createRequest.height,
51 createRequest.handle, createRequest.pitch, m_default_fb_id);
52}
53
55{
56 int ret;
57 const int fd = device()->fd();
58
59 if (m_default_fb_id != uint32_t(-1)) {
60 ret = drmModeRmFB(fd, m_default_fb_id);
61 if (ret)
62 qErrnoWarning("drmModeRmFB failed");
63 }
64
65 if (m_default_fb_handle != uint32_t(-1)) {
66 struct drm_mode_destroy_dumb destroyRequest;
67 destroyRequest.handle = m_default_fb_handle;
68
69 ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroyRequest);
70 if (ret)
71 qErrnoWarning("DRM_IOCTL_MODE_DESTROY_DUMB failed");
72 }
73
74 const int remainingScreenCount = qGuiApp->screens().size();
75 qCDebug(qLcEglfsKmsDebug, "Screen dtor. %p Remaining screens: %d", this, remainingScreenCount);
76 if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
77 static_cast<QEglFSKmsEglDevice *>(device())->destroyGlobalCursor();
78}
79
80QPlatformCursor *QEglFSKmsEglDeviceScreen::cursor() const
81{
82 // The base class creates a cursor via integration->createCursor()
83 // in its ctor. With separateScreens just use that. Otherwise
84 // there's a virtual desktop and the device has a global cursor
85 // and the base class has no dedicated cursor at all.
86 // config->hwCursor() is ignored for now, just use the standard OpenGL cursor.
87 return device()->screenConfig()->separateScreens()
88 ? QEglFSScreen::cursor()
89 : static_cast<QEglFSKmsEglDevice *>(device())->globalCursor();
90}
91
93{
94 QKmsOutput &op(output());
95 const int fd = device()->fd();
96 const uint32_t w = op.modes[op.mode].hdisplay;
97 const uint32_t h = op.modes[op.mode].vdisplay;
98
99 if (!op.mode_set) {
100 op.mode_set = true;
101
102 drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
103 const bool alreadySet = currentMode && currentMode->width == w && currentMode->height == h;
104 if (currentMode)
105 drmModeFreeCrtc(currentMode);
106 if (alreadySet) {
107 // Maybe detecting the DPMS mode could help here, but there are no properties
108 // exposed on the connector apparently. So rely on an env var for now.
109 // Note that typically, we need to set crtc with the default fb even if the
110 // mode did not change, unless QT_QPA_EGLFS_ALWAYS_SET_MODE is explicitly specified.
111 static bool envVarSet = false;
112 static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE", &envVarSet);
113 if (envVarSet && !alwaysDoSet) {
114 qCDebug(qLcEglfsKmsDebug, "Mode already set");
115 return;
116 }
117 }
118
119 qCDebug(qLcEglfsKmsDebug, "Setting mode");
120 int ret = drmModeSetCrtc(fd, op.crtc_id,
121 m_default_fb_id, 0, 0,
122 &op.connector_id, 1,
123 &op.modes[op.mode]);
124 if (ret)
125 qErrnoWarning(errno, "drmModeSetCrtc failed");
126 }
127
128 if (!op.forced_plane_set) {
129 op.forced_plane_set = true;
130
131 if (op.wants_forced_plane) {
132 qCDebug(qLcEglfsKmsDebug, "Setting plane %u", op.forced_plane_id);
133 int ret = drmModeSetPlane(fd, op.forced_plane_id, op.crtc_id, m_default_fb_id, 0,
134 0, 0, w, h,
135 0 << 16, 0 << 16, op.size.width() << 16, op.size.height() << 16);
136 if (ret == -1)
137 qErrnoWarning(errno, "drmModeSetPlane failed");
138 }
139 }
140}
141
142QT_END_NAMESPACE
QPlatformCursor * cursor() const override
Reimplement this function in subclass to return the cursor of the screen.