File indexing completed on 2025-04-20 10:57:35

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "drm_object.h"
0010 
0011 #include <errno.h>
0012 
0013 #include "drm_gpu.h"
0014 #include "drm_logging.h"
0015 #include "drm_pointer.h"
0016 
0017 namespace KWin
0018 {
0019 
0020 DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType)
0021     : m_gpu(gpu)
0022     , m_id(objectId)
0023     , m_objectType(objectType)
0024     , m_propertyDefinitions(vector)
0025 {
0026     m_props.resize(m_propertyDefinitions.count());
0027 }
0028 
0029 bool DrmObject::initProps()
0030 {
0031     if (!updateProperties()) {
0032         return false;
0033     }
0034     if (KWIN_DRM().isDebugEnabled()) {
0035         auto debug = QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC, KWIN_DRM().categoryName()).debug().nospace().noquote();
0036         switch (m_objectType) {
0037         case DRM_MODE_OBJECT_CONNECTOR:
0038             debug << "Connector ";
0039             break;
0040         case DRM_MODE_OBJECT_CRTC:
0041             debug << "Crtc ";
0042             break;
0043         case DRM_MODE_OBJECT_PLANE:
0044             debug << "Plane ";
0045             break;
0046         default:
0047             Q_UNREACHABLE();
0048         }
0049         debug << m_id << " has properties ";
0050         for (size_t i = 0; i < m_props.size(); i++) {
0051             if (i > 0) {
0052                 debug << ", ";
0053             }
0054             const auto &prop = m_props[i];
0055             if (prop) {
0056                 debug << prop->name() << "=" << prop->valueString(prop->current());
0057             } else {
0058                 debug << m_propertyDefinitions[i].name << " not found";
0059             }
0060         }
0061     }
0062     return true;
0063 }
0064 
0065 bool DrmObject::atomicPopulate(drmModeAtomicReq *req) const
0066 {
0067     for (const auto &property : std::as_const(m_props)) {
0068         if (property && !property->isImmutable() && !property->isLegacy() && property->needsCommit()) {
0069             if (drmModeAtomicAddProperty(req, m_id, property->propId(), property->pending()) <= 0) {
0070                 qCWarning(KWIN_DRM) << "Adding property" << property->name() << "->" << property->pending()
0071                                     << "to atomic commit failed for object" << this << "with error" << strerror(errno);
0072                 return false;
0073             }
0074         }
0075     }
0076     return true;
0077 }
0078 
0079 void DrmObject::commit()
0080 {
0081     for (const auto &prop : std::as_const(m_props)) {
0082         if (prop) {
0083             prop->commit();
0084         }
0085     }
0086 }
0087 
0088 void DrmObject::commitPending()
0089 {
0090     for (const auto &prop : std::as_const(m_props)) {
0091         if (prop) {
0092             prop->commitPending();
0093         }
0094     }
0095 }
0096 
0097 void DrmObject::rollbackPending()
0098 {
0099     for (const auto &prop : std::as_const(m_props)) {
0100         if (prop) {
0101             prop->rollbackPending();
0102         }
0103     }
0104 }
0105 
0106 bool DrmObject::needsCommit() const
0107 {
0108     for (const auto &prop : std::as_const(m_props)) {
0109         if (prop && prop->needsCommit()) {
0110             return true;
0111         }
0112     }
0113     return false;
0114 }
0115 
0116 bool DrmObject::updateProperties()
0117 {
0118     DrmUniquePtr<drmModeObjectProperties> properties(drmModeObjectGetProperties(m_gpu->fd(), m_id, m_objectType));
0119     if (!properties) {
0120         qCWarning(KWIN_DRM) << "Failed to get properties for object" << m_id;
0121         return false;
0122     }
0123     for (int propIndex = 0; propIndex < m_propertyDefinitions.count(); propIndex++) {
0124         const PropertyDefinition &def = m_propertyDefinitions[propIndex];
0125         bool found = false;
0126         for (uint32_t drmPropIndex = 0; drmPropIndex < properties->count_props; drmPropIndex++) {
0127             DrmUniquePtr<drmModePropertyRes> prop(drmModeGetProperty(m_gpu->fd(), properties->props[drmPropIndex]));
0128             if (!prop) {
0129                 qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", drmPropIndex, m_id);
0130                 continue;
0131             }
0132             if (def.name == prop->name) {
0133                 if (m_props[propIndex]) {
0134                     m_props[propIndex]->setCurrent(properties->prop_values[drmPropIndex]);
0135                 } else {
0136                     m_props[propIndex] = std::make_unique<DrmProperty>(this, prop.get(), properties->prop_values[drmPropIndex], def.enumNames);
0137                 }
0138                 found = true;
0139                 break;
0140             }
0141         }
0142         if (!found) {
0143             m_props[propIndex].reset();
0144         }
0145     }
0146     for (int i = 0; i < m_propertyDefinitions.count(); i++) {
0147         bool required = m_gpu->atomicModeSetting() ? m_propertyDefinitions[i].requirement == Requirement::Required
0148                                                    : m_propertyDefinitions[i].requirement == Requirement::RequiredForLegacy;
0149         if (!m_props[i] && required) {
0150             qCWarning(KWIN_DRM, "Required property %s for object %d not found!", qPrintable(m_propertyDefinitions[i].name), m_id);
0151             return false;
0152         }
0153     }
0154     return true;
0155 }
0156 
0157 uint32_t DrmObject::id() const
0158 {
0159     return m_id;
0160 }
0161 
0162 DrmGpu *DrmObject::gpu() const
0163 {
0164     return m_gpu;
0165 }
0166 
0167 uint32_t DrmObject::type() const
0168 {
0169     return m_objectType;
0170 }
0171 
0172 QString DrmObject::typeName() const
0173 {
0174     switch (m_objectType) {
0175     case DRM_MODE_OBJECT_CONNECTOR:
0176         return QStringLiteral("connector");
0177     case DRM_MODE_OBJECT_CRTC:
0178         return QStringLiteral("crtc");
0179     case DRM_MODE_OBJECT_PLANE:
0180         return QStringLiteral("plane");
0181     default:
0182         return QStringLiteral("unknown?");
0183     }
0184 }
0185 
0186 void DrmObject::printProps(PrintMode mode)
0187 {
0188     bool any = mode == PrintMode::All || std::any_of(m_props.begin(), m_props.end(), [](const auto &prop) {
0189                    return prop && !prop->isImmutable() && prop->needsCommit();
0190                });
0191     if (!any) {
0192         return;
0193     }
0194     qCDebug(KWIN_DRM) << typeName() << id();
0195     for (const auto &prop : m_props) {
0196         if (prop) {
0197             uint64_t current = prop->name().startsWith("SRC_") ? prop->current() >> 16 : prop->current();
0198             if (prop->isImmutable() || !prop->needsCommit()) {
0199                 if (mode == PrintMode::All) {
0200                     qCDebug(KWIN_DRM).nospace() << "\t" << prop->name() << ": " << current;
0201                 }
0202             } else {
0203                 uint64_t pending = prop->name().startsWith("SRC_") ? prop->pending() >> 16 : prop->pending();
0204                 qCDebug(KWIN_DRM).nospace() << "\t" << prop->name() << ": " << current << "->" << pending;
0205             }
0206         }
0207     }
0208 }
0209 }
0210 
0211 QDebug operator<<(QDebug s, const KWin::DrmObject *obj)
0212 {
0213     QDebugStateSaver saver(s);
0214     if (obj) {
0215         s.nospace() << "DrmObject(id=" << obj->id() << ", gpu=" << obj->gpu() << ')';
0216     } else {
0217         s << "DrmObject(0x0)";
0218     }
0219     return s;
0220 }