/* KWin - the KDE window manager This file is part of the KDE project. SPDX-FileCopyrightText: 2016 Roman Gilg SPDX-License-Identifier: GPL-2.0-or-later */ #include "drm_object.h" #include #include "drm_gpu.h" #include "drm_logging.h" #include "drm_pointer.h" namespace KWin { DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector &&vector, uint32_t objectType) : m_gpu(gpu) , m_id(objectId) , m_objectType(objectType) , m_propertyDefinitions(vector) { m_props.resize(m_propertyDefinitions.count()); } bool DrmObject::initProps() { if (!updateProperties()) { return false; } if (KWIN_DRM().isDebugEnabled()) { auto debug = QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, KWIN_DRM().categoryName()).debug().nospace(); switch (m_objectType) { case DRM_MODE_OBJECT_CONNECTOR: debug << "Connector "; break; case DRM_MODE_OBJECT_CRTC: debug << "Crtc "; break; case DRM_MODE_OBJECT_PLANE: debug << "Plane "; break; default: Q_UNREACHABLE(); } debug << m_id << " has properties "; for (size_t i = 0; i < m_props.size(); i++) { if (i > 0) { debug << ", "; } const auto &prop = m_props[i]; if (prop) { debug << prop->name() << "="; if (m_propertyDefinitions[i].enumNames.isEmpty()) { debug << prop->current(); } else { if (prop->hasEnum(prop->current())) { debug << prop->enumNames().at(prop->enumForValue(prop->current())); } else { debug << "invalid value: " << prop->current(); } } } else { debug << m_propertyDefinitions[i].name << " not found"; } } } return true; } bool DrmObject::atomicPopulate(drmModeAtomicReq *req) const { for (const auto &property : qAsConst(m_props)) { if (property && !property->isImmutable() && !property->isLegacy() && property->needsCommit()) { if (drmModeAtomicAddProperty(req, m_id, property->propId(), property->pending()) <= 0) { qCWarning(KWIN_DRM) << "Adding property" << property->name() << "->" << property->pending() << "to atomic commit failed for object" << this << "with error" << strerror(errno); return false; } } } return true; } void DrmObject::commit() { for (const auto &prop : qAsConst(m_props)) { if (prop) { prop->commit(); } } } void DrmObject::commitPending() { for (const auto &prop : qAsConst(m_props)) { if (prop) { prop->commitPending(); } } } void DrmObject::rollbackPending() { for (const auto &prop : qAsConst(m_props)) { if (prop) { prop->rollbackPending(); } } } bool DrmObject::needsCommit() const { for (const auto &prop : qAsConst(m_props)) { if (prop && prop->needsCommit()) { return true; } } return false; } bool DrmObject::updateProperties() { DrmUniquePtr properties(drmModeObjectGetProperties(m_gpu->fd(), m_id, m_objectType)); if (!properties) { qCWarning(KWIN_DRM) << "Failed to get properties for object" << m_id; return false; } for (int propIndex = 0; propIndex < m_propertyDefinitions.count(); propIndex++) { const PropertyDefinition &def = m_propertyDefinitions[propIndex]; bool found = false; for (uint32_t drmPropIndex = 0; drmPropIndex < properties->count_props; drmPropIndex++) { DrmUniquePtr prop(drmModeGetProperty(m_gpu->fd(), properties->props[drmPropIndex])); if (!prop) { qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", drmPropIndex, m_id); continue; } if (def.name == prop->name) { if (m_props[propIndex]) { m_props[propIndex]->setCurrent(properties->prop_values[drmPropIndex]); } else { m_props[propIndex] = std::make_unique(this, prop.get(), properties->prop_values[drmPropIndex], def.enumNames); } found = true; break; } } if (!found) { m_props[propIndex].reset(); } } for (int i = 0; i < m_propertyDefinitions.count(); i++) { bool required = m_gpu->atomicModeSetting() ? m_propertyDefinitions[i].requirement == Requirement::Required : m_propertyDefinitions[i].requirement == Requirement::RequiredForLegacy; if (!m_props[i] && required) { qCWarning(KWIN_DRM, "Required property %s for object %d not found!", qPrintable(m_propertyDefinitions[i].name), m_id); return false; } } return true; } uint32_t DrmObject::id() const { return m_id; } DrmGpu *DrmObject::gpu() const { return m_gpu; } uint32_t DrmObject::type() const { return m_objectType; } QString DrmObject::typeName() const { switch (m_objectType) { case DRM_MODE_OBJECT_CONNECTOR: return QStringLiteral("connector"); case DRM_MODE_OBJECT_CRTC: return QStringLiteral("crtc"); case DRM_MODE_OBJECT_PLANE: return QStringLiteral("plane"); default: return QStringLiteral("unknown?"); } } void DrmObject::printProps(PrintMode mode) { bool any = mode == PrintMode::All || std::any_of(m_props.begin(), m_props.end(), [](const auto &prop) { return prop && !prop->isImmutable() && prop->needsCommit(); }); if (!any) { return; } qCDebug(KWIN_DRM) << typeName() << id(); for (const auto &prop : m_props) { if (prop) { uint64_t current = prop->name().startsWith("SRC_") ? prop->current() >> 16 : prop->current(); if (prop->isImmutable() || !prop->needsCommit()) { if (mode == PrintMode::All) { qCDebug(KWIN_DRM).nospace() << "\t" << prop->name() << ": " << current; } } else { uint64_t pending = prop->name().startsWith("SRC_") ? prop->pending() >> 16 : prop->pending(); qCDebug(KWIN_DRM).nospace() << "\t" << prop->name() << ": " << current << "->" << pending; } } } } } QDebug operator<<(QDebug s, const KWin::DrmObject *obj) { QDebugStateSaver saver(s); if (obj) { s.nospace() << "DrmObject(id=" << obj->id() << ", gpu=" << obj->gpu() << ')'; } else { s << "DrmObject(0x0)"; } return s; }