Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/drm/drm_output.cpp
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Line(s) | |||||
42 | // KF5 | 42 | // KF5 | ||
43 | #include <KConfigGroup> | 43 | #include <KConfigGroup> | ||
44 | #include <KLocalizedString> | 44 | #include <KLocalizedString> | ||
45 | #include <KSharedConfig> | 45 | #include <KSharedConfig> | ||
46 | // Qt | 46 | // Qt | ||
47 | #include <QMatrix4x4> | 47 | #include <QMatrix4x4> | ||
48 | #include <QCryptographicHash> | 48 | #include <QCryptographicHash> | ||
49 | #include <QPainter> | 49 | #include <QPainter> | ||
50 | #include <QFile> | ||||
50 | // drm | 51 | // drm | ||
51 | #include <xf86drm.h> | 52 | #include <xf86drm.h> | ||
52 | #include <xf86drmMode.h> | 53 | #include <xf86drmMode.h> | ||
53 | #include <libdrm/drm_mode.h> | 54 | #include <libdrm/drm_mode.h> | ||
54 | 55 | | |||
55 | 56 | | |||
56 | namespace KWin | 57 | namespace KWin | ||
57 | { | 58 | { | ||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Line(s) | |||||
379 | { | 380 | { | ||
380 | if (!m_waylandOutputDevice.isNull()) { | 381 | if (!m_waylandOutputDevice.isNull()) { | ||
381 | delete m_waylandOutputDevice.data(); | 382 | delete m_waylandOutputDevice.data(); | ||
382 | m_waylandOutputDevice.clear(); | 383 | m_waylandOutputDevice.clear(); | ||
383 | } | 384 | } | ||
384 | m_waylandOutputDevice = waylandServer()->display()->createOutputDevice(); | 385 | m_waylandOutputDevice = waylandServer()->display()->createOutputDevice(); | ||
385 | m_waylandOutputDevice->setUuid(m_uuid); | 386 | m_waylandOutputDevice->setUuid(m_uuid); | ||
386 | 387 | | |||
387 | if (!m_edid.eisaId.isEmpty()) { | 388 | if (!m_edid.vendor.isEmpty()) { | ||
388 | m_waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId)); | 389 | m_waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.vendor)); | ||
389 | } else { | 390 | } else { | ||
390 | m_waylandOutputDevice->setManufacturer(i18n("unknown")); | 391 | m_waylandOutputDevice->setManufacturer(i18n("unknown")); | ||
391 | } | 392 | } | ||
392 | 393 | | |||
393 | QString connectorName = s_connectorNames.value(connector->connector_type, QByteArrayLiteral("Unknown")); | 394 | QString connectorName = s_connectorNames.value(connector->connector_type); | ||
394 | QString modelName; | 395 | QString modelName; | ||
395 | 396 | | |||
396 | if (!m_edid.monitorName.isEmpty()) { | 397 | if (!m_edid.monitorName.isEmpty()) { | ||
397 | QString model = QString::fromLatin1(m_edid.monitorName); | 398 | modelName = QString::fromLatin1(m_edid.monitorName); | ||
398 | if (!m_edid.serialNumber.isEmpty()) { | 399 | } else if (!connectorName.isEmpty()) { | ||
399 | model.append('/'); | 400 | modelName = connectorName; | ||
400 | model.append(QString::fromLatin1(m_edid.serialNumber)); | | |||
401 | } | | |||
402 | modelName = model; | | |||
403 | } else if (!m_edid.serialNumber.isEmpty()) { | | |||
404 | modelName = QString::fromLatin1(m_edid.serialNumber); | | |||
405 | } else { | 401 | } else { | ||
406 | modelName = i18n("unknown"); | 402 | modelName = i18n("unknown"); | ||
407 | } | 403 | } | ||
408 | 404 | | |||
409 | m_waylandOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName); | 405 | m_waylandOutputDevice->setSerialNumber(m_edid.serialNumber); | ||
410 | 406 | m_waylandOutputDevice->setEisaId(m_edid.eisaId); | |||
407 | m_waylandOutputDevice->setModel(modelName); | ||||
411 | m_waylandOutputDevice->setPhysicalSize(m_physicalSize); | 408 | m_waylandOutputDevice->setPhysicalSize(m_physicalSize); | ||
412 | 409 | | |||
413 | // read in mode information | 410 | // read in mode information | ||
414 | for (int i = 0; i < connector->count_modes; ++i) { | 411 | for (int i = 0; i < connector->count_modes; ++i) { | ||
415 | // TODO: in AMS here we could read and store for later every mode's blob_id | 412 | // TODO: in AMS here we could read and store for later every mode's blob_id | ||
416 | // would simplify isCurrentMode(..) and presentAtomically(..) in case of mode set | 413 | // would simplify isCurrentMode(..) and presentAtomically(..) in case of mode set | ||
417 | auto *m = &connector->modes[i]; | 414 | auto *m = &connector->modes[i]; | ||
418 | KWayland::Server::OutputDeviceInterface::ModeFlags deviceflags; | 415 | KWayland::Server::OutputDeviceInterface::ModeFlags deviceflags; | ||
▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Line(s) | |||||
577 | } | 574 | } | ||
578 | 575 | | |||
579 | static QSize extractPhysicalSize(drmModePropertyBlobPtr edid) | 576 | static QSize extractPhysicalSize(drmModePropertyBlobPtr edid) | ||
580 | { | 577 | { | ||
581 | const uint8_t *data = reinterpret_cast<uint8_t*>(edid->data); | 578 | const uint8_t *data = reinterpret_cast<uint8_t*>(edid->data); | ||
582 | return QSize(data[0x15], data[0x16]) * 10; | 579 | return QSize(data[0x15], data[0x16]) * 10; | ||
583 | } | 580 | } | ||
584 | 581 | | |||
582 | static QByteArray extractVendorName(drmModePropertyBlobPtr edid) | ||||
583 | { | ||||
584 | // see section 3.4 | ||||
585 | const uint8_t *data = reinterpret_cast<uint8_t*>(edid->data); | ||||
586 | static const uint offset = 0x08; | ||||
587 | | ||||
588 | /* decode the PNP ID from three 5 bit words packed into 2 bytes | ||||
589 | * /--08--\/--09--\ | ||||
590 | * 7654321076543210 | ||||
591 | * |\---/\---/\---/ | ||||
592 | * R C1 C2 C3 */ | ||||
593 | char pnpId[3]; | ||||
594 | pnpId[0] = 'A' + ((data[offset] & 0x7c) / 4) - 1; | ||||
595 | pnpId[1] = 'A' + ((data[offset] & 0x3) * 8) + ((data[offset + 1] & 0xe0) / 32) - 1; | ||||
596 | pnpId[2] = 'A' + (data[offset + 1] & 0x1f) - 1; | ||||
597 | | ||||
598 | // Map to PNP | ||||
599 | QFile pnpFile(QStringLiteral("/usr/share/hwdata/pnp.ids")); | ||||
graesslin: Can we be sure this path is the same on all distros? Should we runtime depend on it? E.g. a… | |||||
The path is somewhat standardized between all distros. There are some distros (like Arch) that simply don't have this file because they use different upstream source (gentoo vs. fedora) that is missing that but from I can tell they still use /usr/share/hwdata for all distros I checked. I can add a cmake check if you want. dvratil: The path is somewhat standardized between all distros. There are some distros (like Arch) that… | |||||
Yep, I would prefer this. Just to also make clear at compile time that it's missing. I don't like hidden dependencies which fail on some distros. graesslin: > I can add a cmake check if you want.
Yep, I would prefer this. Just to also make clear at… | |||||
600 | if (pnpFile.exists() && pnpFile.open(QIODevice::ReadOnly)) { | ||||
601 | while (!pnpFile.atEnd()) { | ||||
602 | const auto line = pnpFile.readLine(); | ||||
603 | if (qstrncmp(line.constData(), pnpId, 3) == 0) { | ||||
604 | return line.mid(4).trimmed(); | ||||
605 | } | ||||
606 | } | ||||
607 | } | ||||
608 | | ||||
609 | return {}; | ||||
610 | } | ||||
611 | | ||||
585 | void DrmOutput::initEdid(drmModeConnector *connector) | 612 | void DrmOutput::initEdid(drmModeConnector *connector) | ||
586 | { | 613 | { | ||
587 | ScopedDrmPointer<_drmModePropertyBlob, &drmModeFreePropertyBlob> edid; | 614 | ScopedDrmPointer<_drmModePropertyBlob, &drmModeFreePropertyBlob> edid; | ||
588 | for (int i = 0; i < connector->count_props; ++i) { | 615 | for (int i = 0; i < connector->count_props; ++i) { | ||
589 | ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> property(drmModeGetProperty(m_backend->fd(), connector->props[i])); | 616 | ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> property(drmModeGetProperty(m_backend->fd(), connector->props[i])); | ||
590 | if (!property) { | 617 | if (!property) { | ||
591 | continue; | 618 | continue; | ||
592 | } | 619 | } | ||
593 | if ((property->flags & DRM_MODE_PROP_BLOB) && qstrcmp(property->name, "EDID") == 0) { | 620 | if ((property->flags & DRM_MODE_PROP_BLOB) && qstrcmp(property->name, "EDID") == 0) { | ||
594 | edid.reset(drmModeGetPropertyBlob(m_backend->fd(), connector->prop_values[i])); | 621 | edid.reset(drmModeGetPropertyBlob(m_backend->fd(), connector->prop_values[i])); | ||
595 | } | 622 | } | ||
596 | } | 623 | } | ||
597 | if (!edid) { | 624 | if (!edid) { | ||
598 | return; | 625 | return; | ||
599 | } | 626 | } | ||
600 | 627 | | |||
601 | // for documentation see: http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf | 628 | // for documentation see: http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf | ||
602 | if (edid->length < 128) { | 629 | if (edid->length < 128) { | ||
603 | return; | 630 | return; | ||
604 | } | 631 | } | ||
605 | if (!verifyEdidHeader(edid.data())) { | 632 | if (!verifyEdidHeader(edid.data())) { | ||
606 | return; | 633 | return; | ||
607 | } | 634 | } | ||
635 | m_edid.vendor = extractVendorName(edid.data()); | ||||
608 | m_edid.eisaId = extractEisaId(edid.data()); | 636 | m_edid.eisaId = extractEisaId(edid.data()); | ||
609 | m_edid.serialNumber = extractSerialNumber(edid.data()); | 637 | m_edid.serialNumber = extractSerialNumber(edid.data()); | ||
610 | 638 | | |||
611 | // parse monitor descriptor description | 639 | // parse monitor descriptor description | ||
612 | extractMonitorDescriptorDescription(edid.data(), m_edid); | 640 | extractMonitorDescriptorDescription(edid.data(), m_edid); | ||
613 | 641 | | |||
614 | m_edid.physicalSize = extractPhysicalSize(edid.data()); | 642 | m_edid.physicalSize = extractPhysicalSize(edid.data()); | ||
615 | } | 643 | } | ||
▲ Show 20 Lines • Show All 683 Lines • Show Last 20 Lines |
Can we be sure this path is the same on all distros? Should we runtime depend on it? E.g. a cmake check whether it's available?