11#include <private/qeglfsintegration_p.h>
12#include <private/qeglfskmsintegration_p.h>
14#include <QtCore/QLoggingCategory>
16#include <QtGui/private/qguiapplication_p.h>
17#include <QtGui/private/qtguiglobal_p.h>
18#include <QtFbSupport/private/qfbvthandler_p.h>
24QMutex QEglFSKmsGbmScreen::s_nonThreadedFlipMutex;
28 Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
34 Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
38void QEglFSKmsGbmScreen::bufferDestroyedHandler(gbm_bo *bo,
void *data)
40 FrameBuffer *fb =
static_cast<FrameBuffer *>(data);
43 gbm_device *device = gbm_bo_get_device(bo);
44 drmModeRmFB(gbm_device_get_fd(device), fb->fb);
50QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(gbm_bo *bo)
53 FrameBuffer *fb =
static_cast<FrameBuffer *>(gbm_bo_get_user_data(bo));
58 uint32_t width = gbm_bo_get_width(bo);
59 uint32_t height = gbm_bo_get_height(bo);
60 uint32_t handles[4] = { gbm_bo_get_handle(bo).u32 };
61 uint32_t strides[4] = { gbm_bo_get_stride(bo) };
62 uint32_t offsets[4] = { 0 };
63 uint32_t pixelFormat = gbmFormatToDrmFormat(gbm_bo_get_format(bo));
65 auto fb = std::make_unique<FrameBuffer>();
66 qCDebug(qLcEglfsKmsDebug,
"Adding FB, size %ux%u, DRM format 0x%x, stride %u, handle %u",
67 width, height, pixelFormat, strides[0], handles[0]);
69 int ret = drmModeAddFB2(device()->fd(), width, height, pixelFormat,
70 handles, strides, offsets, &fb->fb, 0);
73 qWarning(
"Failed to create KMS FB!");
78 gbm_bo_set_user_data(bo, fb.release(), bufferDestroyedHandler);
82QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QEglFSKmsDevice *device,
const QKmsOutput &output,
bool headless)
83 : QEglFSKmsScreen(device, output, headless)
84 , m_gbm_surface(
nullptr)
85 , m_gbm_bo_current(
nullptr)
86 , m_gbm_bo_next(
nullptr)
87 , m_flipPending(
false)
89 , m_cloneSource(
nullptr)
93QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen()
95 const int remainingScreenCount = qGuiApp->screens().count();
96 qCDebug(qLcEglfsKmsDebug,
"Screen dtor. %p Remaining screens: %d",
this, remainingScreenCount);
97 if (!remainingScreenCount && !device()->screenConfig()->separateScreens())
98 static_cast<QEglFSKmsGbmDevice *>(device())->destroyGlobalCursor();
102 QList<CloneDestination> &dests = m_cloneSource->m_cloneDests;
103 auto newEnd = std::remove_if(dests.begin(), dests.end(),
104 [
this](CloneDestination &dest) {
105 return dest.screen ==
this;
107 dests.erase(newEnd, dests.end());
111 for (CloneDestination &dest : m_cloneDests) {
112 dest.screen->m_cloneSource =
nullptr;
114 dest.screen->m_output.mode_set =
false;
118QPlatformCursor *QEglFSKmsGbmScreen::cursor()
const
120 QKmsScreenConfig *config = device()->screenConfig();
121 if (config->headless())
123 if (config->hwCursor()) {
124 if (!config->separateScreens())
125 return static_cast<QEglFSKmsGbmDevice *>(device())->globalCursor();
127 if (m_cursor.isNull()) {
128 QEglFSKmsGbmScreen *that =
const_cast<QEglFSKmsGbmScreen *>(
this);
129 that->m_cursor.reset(
new QEglFSKmsGbmCursor(that));
132 return m_cursor.data();
134 return QEglFSScreen::cursor();
138gbm_surface *QEglFSKmsGbmScreen::createSurface(EGLConfig eglConfig)
140 if (!m_gbm_surface) {
141 qCDebug(qLcEglfsKmsDebug,
"Creating gbm_surface for screen %s", qPrintable(name()));
143 const auto gbmDevice =
static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice();
146 const bool queryFromEgl = !m_output.drm_format_requested_by_user;
148 EGLint native_format = -1;
149 EGLBoolean success = eglGetConfigAttrib(display(), eglConfig, EGL_NATIVE_VISUAL_ID, &native_format);
150 qCDebug(qLcEglfsKmsDebug) <<
"Got native format" << Qt::hex << native_format << Qt::dec
151 <<
"from eglGetConfigAttrib() with return code" <<
bool(success);
154 m_gbm_surface = gbm_surface_create(gbmDevice,
155 rawGeometry().width(),
156 rawGeometry().height(),
160 m_output.drm_format = gbmFormatToDrmFormat(native_format);
164 const uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
169 if (!m_gbm_surface) {
171 qCDebug(qLcEglfsKmsDebug,
"Could not create surface with EGL_NATIVE_VISUAL_ID, falling back to format %x", gbmFormat);
172 m_gbm_surface = gbm_surface_create(gbmDevice,
173 rawGeometry().width(),
174 rawGeometry().height(),
181 if (!m_gbm_surface) {
182 uint64_t modifier = DRM_FORMAT_MOD_LINEAR;
184 m_gbm_surface = gbm_surface_create_with_modifiers(gbmDevice,
185 rawGeometry().width(),
186 rawGeometry().height(),
193 qFatal(
"Could not create GBM surface!");
195 return m_gbm_surface;
198void QEglFSKmsGbmScreen::resetSurface()
200 m_flipPending =
false;
201 m_gbm_bo_current =
nullptr;
202 m_gbm_surface =
nullptr;
211 if (!device()->hasAtomicSupport())
212 needsNewModeSetForNextFb =
true;
215void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
216 const QList<QPlatformScreen *> &screensCloningThisScreen)
219 const bool clonesAnother = screenThisScreenClones !=
nullptr;
220 if (clonesAnother && !screensCloningThisScreen.isEmpty()) {
221 qWarning(
"QEglFSKmsGbmScreen %s cannot be clone source and destination at the same time", qPrintable(name()));
225 m_cloneSource =
static_cast<QEglFSKmsGbmScreen *>(screenThisScreenClones);
226 qCDebug(qLcEglfsKmsDebug,
"Screen %s clones %s", qPrintable(name()), qPrintable(m_cloneSource->name()));
228 m_cloneSource =
nullptr;
232 m_cloneDests.clear();
233 for (QPlatformScreen *s : screensCloningThisScreen) {
235 d.screen =
static_cast<QEglFSKmsGbmScreen *>(s);
236 m_cloneDests.append(d);
240void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
242 QKmsOutput &op(output());
243 const int fd = device()->fd();
245 if (!op.mode_set || needsNewModeSetForNextFb) {
247 needsNewModeSetForNextFb =
false;
249 bool doModeSet =
true;
250 drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
251 const bool alreadySet = currentMode && currentMode->buffer_id == fb && !memcmp(¤tMode->mode, &op.modes[op.mode],
sizeof(drmModeModeInfo));
253 drmModeFreeCrtc(currentMode);
258 qCDebug(qLcEglfsKmsDebug,
"Setting mode for screen %s", qPrintable(name()));
260 if (device()->hasAtomicSupport()) {
261#if QT_CONFIG(drm_atomic)
262 drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
264 drmModeAtomicAddProperty(request, op.connector_id, op.crtcIdPropertyId, op.crtc_id);
265 drmModeAtomicAddProperty(request, op.crtc_id, op.modeIdPropertyId, op.mode_blob_id);
266 drmModeAtomicAddProperty(request, op.crtc_id, op.activePropertyId, 1);
270 int ret = drmModeSetCrtc(fd,
278 setPowerState(PowerStateOn);
280 qErrnoWarning(errno,
"Could not set DRM mode for screen %s", qPrintable(name()));
286void QEglFSKmsGbmScreen::nonThreadedPageFlipHandler(
int fd,
287 unsigned int sequence,
289 unsigned int tv_usec,
294 QEglFSKmsGbmScreen *screen =
static_cast<QEglFSKmsGbmScreen *>(user_data);
296 if (QEglFSKmsScreen::isScreenKnown(screen)) {
297 screen->flipFinished();
298 screen->pageFlipped(sequence, tv_sec, tv_usec);
302void QEglFSKmsGbmScreen::waitForFlipWithEventReader(QEglFSKmsGbmScreen *screen)
305 QEglFSKmsGbmDevice *dev =
static_cast<QEglFSKmsGbmDevice *>(device());
306 dev->eventReader()->startWaitFlip(screen, &m_flipMutex, &m_flipCond);
313 succ = m_flipCond.wait(&m_flipMutex);
315 succ = m_flipCond.wait(&m_flipMutex, 300);
318 qCWarning(qLcEglfsKmsDebug) <<
"timeout on waitForFlipWithEventReader, screen to wait for:"
319 << screen <<
", screen waiting (shouldn't be the same screen):"
322 m_flipMutex.unlock();
323 screen->flipFinished();
326void QEglFSKmsGbmScreen::waitForFlip()
328 if (m_headless || m_cloneSource)
335 QEglFSKmsGbmDevice *dev =
static_cast<QEglFSKmsGbmDevice *>(device());
336 if (dev->usesEventReader()) {
337 waitForFlipWithEventReader(
this);
342 for (CloneDestination &d : m_cloneDests) {
343 if (d.screen !=
this)
344 waitForFlipWithEventReader(d.screen);
347 QMutexLocker lock(&s_nonThreadedFlipMutex);
348 while (m_gbm_bo_next) {
349 drmEventContext drmEvent;
350 memset(&drmEvent, 0,
sizeof(drmEvent));
351 drmEvent.version = 2;
352 drmEvent.vblank_handler =
nullptr;
353 drmEvent.page_flip_handler = nonThreadedPageFlipHandler;
354 drmHandleEvent(device()->fd(), &drmEvent);
358#if QT_CONFIG(drm_atomic)
359 device()->threadLocalAtomicReset();
363#if QT_CONFIG(drm_atomic)
364static void addAtomicFlip(drmModeAtomicReq *request,
const QKmsOutput &output, uint32_t fb)
366 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
367 output.eglfs_plane->framebufferPropertyId, fb);
369 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
370 output.eglfs_plane->crtcPropertyId, output.crtc_id);
372 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
373 output.eglfs_plane->srcwidthPropertyId, output.size.width() << 16);
375 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
376 output.eglfs_plane->srcXPropertyId, 0);
378 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
379 output.eglfs_plane->srcYPropertyId, 0);
381 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
382 output.eglfs_plane->srcheightPropertyId, output.size.height() << 16);
384 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
385 output.eglfs_plane->crtcXPropertyId, 0);
387 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
388 output.eglfs_plane->crtcYPropertyId, 0);
390 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
391 output.eglfs_plane->crtcwidthPropertyId, output.modes[output.mode].hdisplay);
393 drmModeAtomicAddProperty(request, output.eglfs_plane->id,
394 output.eglfs_plane->crtcheightPropertyId, output.modes[output.mode].vdisplay);
398void QEglFSKmsGbmScreen::flip()
402 if (m_headless || m_cloneSource)
405 if (!m_gbm_surface) {
406 qWarning(
"Cannot sync before platform init!");
410 m_gbm_bo_next = gbm_surface_lock_front_buffer(m_gbm_surface);
411 if (!m_gbm_bo_next) {
412 qWarning(
"Could not lock GBM surface front buffer for screen %s", qPrintable(name()));
416 auto gbmRelease = qScopeGuard([
this]{
417 m_flipPending =
false;
418 gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
419 m_gbm_bo_next =
nullptr;
422 FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
424 qWarning(
"FrameBuffer not available. Cannot flip");
427 ensureModeSet(fb->fb);
429 const QKmsOutput &thisOutput(output());
430 const int fd = device()->fd();
431 m_flipPending =
true;
433 if (device()->hasAtomicSupport()) {
434#if QT_CONFIG(drm_atomic)
435 drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
437 addAtomicFlip(request, thisOutput, fb->fb);
438 static int zpos = qEnvironmentVariableIntValue(
"QT_QPA_EGLFS_KMS_ZPOS");
440 drmModeAtomicAddProperty(request, thisOutput.eglfs_plane->id,
441 thisOutput.eglfs_plane->zposPropertyId, zpos);
443 static uint blendOp = uint(qEnvironmentVariableIntValue(
"QT_QPA_EGLFS_KMS_BLEND_OP"));
445 drmModeAtomicAddProperty(request, thisOutput.eglfs_plane->id,
446 thisOutput.eglfs_plane->blendOpPropertyId, blendOp);
451 int ret = drmModePageFlip(fd,
454 DRM_MODE_PAGE_FLIP_EVENT,
457 qErrnoWarning(
"Could not queue DRM page flip on screen %s", qPrintable(name()));
462 for (CloneDestination &d : m_cloneDests) {
463 if (d.screen !=
this) {
464 d.screen->ensureModeSet(fb->fb);
465 d.cloneFlipPending =
true;
466 const QKmsOutput &destOutput(d.screen->output());
468 if (device()->hasAtomicSupport()) {
469#if QT_CONFIG(drm_atomic)
470 drmModeAtomicReq *request = device()->threadLocalAtomicRequest();
472 addAtomicFlip(request, destOutput, fb->fb);
482 int ret = drmModePageFlip(fd,
485 DRM_MODE_PAGE_FLIP_EVENT,
488 qErrnoWarning(
"Could not queue DRM page flip for screen %s (clones screen %s)",
489 qPrintable(d.screen->name()),
491 d.cloneFlipPending =
false;
497 if (device()->hasAtomicSupport()) {
498#if QT_CONFIG(drm_atomic)
499 if (!device()->threadLocalAtomicCommit(
this)) {
505 gbmRelease.dismiss();
508void QEglFSKmsGbmScreen::flipFinished()
511 m_cloneSource->cloneDestFlipFinished(
this);
515 m_flipPending =
false;
519void QEglFSKmsGbmScreen::cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScreen)
521 for (CloneDestination &d : m_cloneDests) {
522 if (d.screen == cloneDestScreen) {
523 d.cloneFlipPending =
false;
530void QEglFSKmsGbmScreen::updateFlipStatus()
540 for (
const CloneDestination &d : std::as_const(m_cloneDests)) {
541 if (d.cloneFlipPending)
545 if (m_gbm_bo_current) {
546 gbm_surface_release_buffer(m_gbm_surface,
550 m_gbm_bo_current = m_gbm_bo_next;
551 m_gbm_bo_next =
nullptr;
static uint32_t gbmFormatToDrmFormat(uint32_t gbmFormat)
static uint32_t drmFormatToGbmFormat(uint32_t drmFormat)