summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp')
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp240
1 files changed, 178 insertions, 62 deletions
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 87fb3146c7..4742143121 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
+** Copyright (C) 2017 The Qt Company Ltd.
** 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/
**
@@ -55,6 +55,18 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(qLcEglfsKmsDebug)
+static inline uint32_t drmFormatToGbmFormat(uint32_t drmFormat)
+{
+ Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
+ return drmFormat;
+}
+
+static inline uint32_t gbmFormatToDrmFormat(uint32_t gbmFormat)
+{
+ Q_ASSERT(DRM_FORMAT_XRGB8888 == GBM_FORMAT_XRGB8888);
+ return gbmFormat;
+}
+
void QEglFSKmsGbmScreen::bufferDestroyedHandler(gbm_bo *bo, void *data)
{
FrameBuffer *fb = static_cast<FrameBuffer *>(data);
@@ -77,29 +89,34 @@ QEglFSKmsGbmScreen::FrameBuffer *QEglFSKmsGbmScreen::framebufferForBufferObject(
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;
+ uint32_t handles[4] = { gbm_bo_get_handle(bo).u32 };
+ uint32_t strides[4] = { gbm_bo_get_stride(bo) };
+ uint32_t offsets[4] = { 0 };
+ uint32_t pixelFormat = gbmFormatToDrmFormat(gbm_bo_get_format(bo));
QScopedPointer<FrameBuffer> fb(new FrameBuffer);
+ qCDebug(qLcEglfsKmsDebug, "Adding FB, size %ux%u, DRM format 0x%x", width, height, pixelFormat);
- int ret = drmModeAddFB(device()->fd(), width, height, 24, 32,
- stride, handle, &fb->fb);
+ int ret = drmModeAddFB2(device()->fd(), width, height, pixelFormat,
+ handles, strides, offsets, &fb->fb, 0);
if (ret) {
qWarning("Failed to create KMS FB!");
- return Q_NULLPTR;
+ return nullptr;
}
gbm_bo_set_user_data(bo, fb.data(), bufferDestroyedHandler);
return fb.take();
}
-QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output)
- : QEglFSKmsScreen(device, output)
- , m_gbm_surface(Q_NULLPTR)
- , m_gbm_bo_current(Q_NULLPTR)
- , m_gbm_bo_next(Q_NULLPTR)
- , m_cursor(Q_NULLPTR)
+QEglFSKmsGbmScreen::QEglFSKmsGbmScreen(QKmsDevice *device, const QKmsOutput &output, bool headless)
+ : QEglFSKmsScreen(device, output, headless)
+ , m_gbm_surface(nullptr)
+ , m_gbm_bo_current(nullptr)
+ , m_gbm_bo_next(nullptr)
+ , m_flipPending(false)
+ , m_cursor(nullptr)
+ , m_cloneSource(nullptr)
{
}
@@ -114,6 +131,8 @@ QEglFSKmsGbmScreen::~QEglFSKmsGbmScreen()
QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
{
QKmsScreenConfig *config = device()->screenConfig();
+ if (config->headless())
+ return nullptr;
if (config->hwCursor()) {
if (!config->separateScreens())
return static_cast<QEglFSKmsGbmDevice *>(device())->globalCursor();
@@ -132,47 +151,112 @@ QPlatformCursor *QEglFSKmsGbmScreen::cursor() const
gbm_surface *QEglFSKmsGbmScreen::createSurface()
{
if (!m_gbm_surface) {
- qCDebug(qLcEglfsKmsDebug) << "Creating window for screen" << name();
+ uint32_t gbmFormat = drmFormatToGbmFormat(m_output.drm_format);
+ qCDebug(qLcEglfsKmsDebug, "Creating gbm_surface for screen %s with format 0x%x", qPrintable(name()), gbmFormat);
m_gbm_surface = gbm_surface_create(static_cast<QEglFSKmsGbmDevice *>(device())->gbmDevice(),
rawGeometry().width(),
rawGeometry().height(),
- GBM_FORMAT_XRGB8888,
+ gbmFormat,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
}
- return m_gbm_surface;
+ return m_gbm_surface; // not owned, gets destroyed in QEglFSKmsGbmIntegration::destroyNativeWindow() via QEglFSKmsGbmWindow::invalidateSurface()
}
-void QEglFSKmsGbmScreen::destroySurface()
+void QEglFSKmsGbmScreen::resetSurface()
{
- if (m_gbm_bo_current) {
- gbm_bo_destroy(m_gbm_bo_current);
- m_gbm_bo_current = Q_NULLPTR;
- }
+ m_gbm_surface = nullptr;
+}
- if (m_gbm_bo_next) {
- gbm_bo_destroy(m_gbm_bo_next);
- m_gbm_bo_next = Q_NULLPTR;
+void QEglFSKmsGbmScreen::initCloning(QPlatformScreen *screenThisScreenClones,
+ const QVector<QPlatformScreen *> &screensCloningThisScreen)
+{
+ // clone destinations need to know the clone source
+ const bool clonesAnother = screenThisScreenClones != nullptr;
+ if (clonesAnother && !screensCloningThisScreen.isEmpty()) {
+ qWarning("QEglFSKmsGbmScreen %s cannot be clone source and destination at the same time", qPrintable(name()));
+ return;
}
+ if (clonesAnother)
+ m_cloneSource = static_cast<QEglFSKmsGbmScreen *>(screenThisScreenClones);
+
+ // clone sources need to know their additional destinations
+ for (QPlatformScreen *s : screensCloningThisScreen) {
+ CloneDestination d;
+ d.screen = static_cast<QEglFSKmsGbmScreen *>(s);
+ m_cloneDests.append(d);
+ }
+}
+
+void QEglFSKmsGbmScreen::ensureModeSet(uint32_t fb)
+{
+ QKmsOutput &op(output());
+ const int fd = device()->fd();
+
+ if (!op.mode_set) {
+ op.mode_set = true;
+
+ bool doModeSet = true;
+ drmModeCrtcPtr currentMode = drmModeGetCrtc(fd, op.crtc_id);
+ const bool alreadySet = currentMode && !memcmp(&currentMode->mode, &op.modes[op.mode], sizeof(drmModeModeInfo));
+ if (currentMode)
+ drmModeFreeCrtc(currentMode);
+ if (alreadySet) {
+ static bool alwaysDoSet = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ALWAYS_SET_MODE");
+ if (!alwaysDoSet) {
+ qCDebug(qLcEglfsKmsDebug, "Mode already set, skipping modesetting for screen %s", qPrintable(name()));
+ doModeSet = false;
+ }
+ }
- if (m_gbm_surface) {
- gbm_surface_destroy(m_gbm_surface);
- m_gbm_surface = Q_NULLPTR;
+ if (doModeSet) {
+ qCDebug(qLcEglfsKmsDebug, "Setting mode for screen %s", qPrintable(name()));
+ int ret = drmModeSetCrtc(fd,
+ op.crtc_id,
+ fb,
+ 0, 0,
+ &op.connector_id, 1,
+ &op.modes[op.mode]);
+
+ if (ret == 0)
+ setPowerState(PowerStateOn);
+ else
+ qErrnoWarning(errno, "Could not set DRM mode for screen %s", qPrintable(name()));
+ }
}
}
void QEglFSKmsGbmScreen::waitForFlip()
{
+ if (m_headless || m_cloneSource)
+ return;
+
// 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();
+ while (m_gbm_bo_next) {
+ drmEventContext drmEvent;
+ memset(&drmEvent, 0, sizeof(drmEvent));
+ drmEvent.version = 2;
+ drmEvent.vblank_handler = nullptr;
+ drmEvent.page_flip_handler = pageFlipHandler;
+ drmHandleEvent(device()->fd(), &drmEvent);
+ }
}
void QEglFSKmsGbmScreen::flip()
{
+ // For headless screen just return silently. It is not necessarily an error
+ // to end up here, so show no warnings.
+ if (m_headless)
+ return;
+
+ if (m_cloneSource) {
+ qWarning("Screen %s clones another screen. swapBuffers() not allowed.", qPrintable(name()));
+ return;
+ }
+
if (!m_gbm_surface) {
qWarning("Cannot sync before platform init!");
return;
@@ -185,60 +269,92 @@ void QEglFSKmsGbmScreen::flip()
}
FrameBuffer *fb = framebufferForBufferObject(m_gbm_bo_next);
+ ensureModeSet(fb->fb);
QKmsOutput &op(output());
const int fd = device()->fd();
- const uint32_t w = op.modes[op.mode].hdisplay;
- const uint32_t h = op.modes[op.mode].vdisplay;
-
- if (!op.mode_set) {
- int ret = drmModeSetCrtc(fd,
- op.crtc_id,
- fb->fb,
- 0, 0,
- &op.connector_id, 1,
- &op.modes[op.mode]);
-
- if (ret == -1) {
- qErrnoWarning(errno, "Could not set DRM mode!");
- } else {
- op.mode_set = true;
- setPowerState(PowerStateOn);
-
- if (!op.plane_set) {
- op.plane_set = true;
- if (op.wants_plane) {
- int ret = drmModeSetPlane(fd, op.plane_id, op.crtc_id,
- uint32_t(-1), 0,
- 0, 0, w, h,
- 0 << 16, 0 << 16, w << 16, h << 16);
- if (ret == -1)
- qErrnoWarning(errno, "drmModeSetPlane failed");
- }
- }
- }
- }
-
+ m_flipPending = true;
int ret = drmModePageFlip(fd,
op.crtc_id,
fb->fb,
DRM_MODE_PAGE_FLIP_EVENT,
this);
if (ret) {
- qErrnoWarning("Could not queue DRM page flip!");
+ qErrnoWarning("Could not queue DRM page flip on screen %s", qPrintable(name()));
+ m_flipPending = false;
gbm_surface_release_buffer(m_gbm_surface, m_gbm_bo_next);
- m_gbm_bo_next = Q_NULLPTR;
+ m_gbm_bo_next = nullptr;
+ return;
+ }
+
+ for (CloneDestination &d : m_cloneDests) {
+ if (d.screen != this) {
+ d.screen->ensureModeSet(fb->fb);
+ d.cloneFlipPending = true;
+ int ret = drmModePageFlip(fd,
+ d.screen->output().crtc_id,
+ fb->fb,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ d.screen);
+ if (ret) {
+ qErrnoWarning("Could not queue DRM page flip for clone screen %s", qPrintable(name()));
+ d.cloneFlipPending = false;
+ }
+ }
}
}
+void QEglFSKmsGbmScreen::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);
+
+ QEglFSKmsGbmScreen *screen = static_cast<QEglFSKmsGbmScreen *>(user_data);
+ screen->flipFinished();
+}
+
void QEglFSKmsGbmScreen::flipFinished()
{
+ if (m_cloneSource) {
+ m_cloneSource->cloneDestFlipFinished(this);
+ return;
+ }
+
+ m_flipPending = false;
+ updateFlipStatus();
+}
+
+void QEglFSKmsGbmScreen::cloneDestFlipFinished(QEglFSKmsGbmScreen *cloneDestScreen)
+{
+ for (CloneDestination &d : m_cloneDests) {
+ if (d.screen == cloneDestScreen) {
+ d.cloneFlipPending = false;
+ break;
+ }
+ }
+ updateFlipStatus();
+}
+
+void QEglFSKmsGbmScreen::updateFlipStatus()
+{
+ Q_ASSERT(!m_cloneSource);
+
+ if (m_flipPending)
+ return;
+
+ for (const CloneDestination &d : m_cloneDests) {
+ if (d.cloneFlipPending)
+ return;
+ }
+
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;
+ m_gbm_bo_next = nullptr;
}
QT_END_NAMESPACE