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

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     SPDX-FileCopyrightText: 2021-2022 Xaver Hugl <xaver.hugl@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "drm_property.h"
0012 #include "drm_gpu.h"
0013 #include "drm_logging.h"
0014 #include "drm_object.h"
0015 #include <cerrno>
0016 
0017 namespace KWin
0018 {
0019 
0020 DrmProperty::DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames)
0021     : m_propId(prop->prop_id)
0022     , m_propName(prop->name)
0023     , m_pending(val)
0024     , m_next(val)
0025     , m_current(val)
0026     , m_immutable(prop->flags & DRM_MODE_PROP_IMMUTABLE)
0027     , m_isBlob(prop->flags & DRM_MODE_PROP_BLOB)
0028     , m_isBitmask(prop->flags & DRM_MODE_PROP_BITMASK)
0029     , m_obj(obj)
0030 {
0031     if (!enumNames.isEmpty()) {
0032         m_enumNames = enumNames;
0033         initEnumMap(prop);
0034     }
0035     if (prop->flags & DRM_MODE_PROP_RANGE) {
0036         Q_ASSERT(prop->count_values > 1);
0037         m_minValue = prop->values[0];
0038         m_maxValue = prop->values[1];
0039     }
0040     updateBlob();
0041 }
0042 
0043 void DrmProperty::commit()
0044 {
0045     if (m_immutable || m_current == m_pending) {
0046         return;
0047     }
0048     setCurrent(m_pending);
0049 }
0050 
0051 void DrmProperty::commitPending()
0052 {
0053     if (m_immutable || m_next == m_pending) {
0054         return;
0055     }
0056     m_next = m_pending;
0057 }
0058 
0059 void DrmProperty::rollbackPending()
0060 {
0061     if (m_immutable || m_next == m_pending) {
0062         return;
0063     }
0064     m_pending = m_next;
0065 }
0066 
0067 bool DrmProperty::setPropertyLegacy(uint64_t value)
0068 {
0069     if (drmModeObjectSetProperty(m_obj->gpu()->fd(), m_obj->id(), m_obj->type(), m_propId, value) == 0) {
0070         m_current = m_next = m_pending = value;
0071         return true;
0072     } else {
0073         return false;
0074     }
0075 }
0076 
0077 void DrmProperty::initEnumMap(drmModePropertyRes *prop)
0078 {
0079     for (int i = 0; i < prop->count_enums; i++) {
0080         struct drm_mode_property_enum *en = &prop->enums[i];
0081         int j = m_enumNames.indexOf(QByteArray(en->name));
0082         if (j >= 0) {
0083             if (m_isBitmask) {
0084                 m_enumToPropertyMap[1 << j] = 1 << en->value;
0085                 m_propertyToEnumMap[1 << en->value] = 1 << j;
0086             } else {
0087                 m_enumToPropertyMap[j] = en->value;
0088                 m_propertyToEnumMap[en->value] = j;
0089             }
0090         } else {
0091             qCWarning(KWIN_DRM, "%s has unrecognized enum '%s'", qPrintable(m_propName), en->name);
0092         }
0093     }
0094 }
0095 
0096 void DrmProperty::setPending(uint64_t value)
0097 {
0098     m_pending = value;
0099 }
0100 
0101 uint64_t DrmProperty::pending() const
0102 {
0103     return m_pending;
0104 }
0105 
0106 bool DrmProperty::needsCommit() const
0107 {
0108     return m_pending != m_current;
0109 }
0110 
0111 void DrmProperty::setCurrent(uint64_t value)
0112 {
0113     m_current = value;
0114     updateBlob();
0115 }
0116 
0117 uint64_t DrmProperty::current() const
0118 {
0119     return m_current;
0120 }
0121 
0122 bool DrmProperty::hasAllEnums() const
0123 {
0124     return m_enumToPropertyMap.count() == m_enumNames.count();
0125 }
0126 
0127 uint32_t DrmProperty::propId() const
0128 {
0129     return m_propId;
0130 }
0131 
0132 const QByteArray &DrmProperty::name() const
0133 {
0134     return m_propName;
0135 }
0136 
0137 bool DrmProperty::isImmutable() const
0138 {
0139     return m_immutable;
0140 }
0141 
0142 bool DrmProperty::isBitmask() const
0143 {
0144     return m_isBitmask;
0145 }
0146 
0147 bool DrmProperty::isLegacy() const
0148 {
0149     return m_legacy;
0150 }
0151 
0152 void DrmProperty::setLegacy()
0153 {
0154     m_legacy = true;
0155 }
0156 
0157 uint64_t DrmProperty::minValue() const
0158 {
0159     return m_minValue;
0160 }
0161 
0162 uint64_t DrmProperty::maxValue() const
0163 {
0164     return m_maxValue;
0165 }
0166 
0167 void DrmProperty::updateBlob()
0168 {
0169     if (m_immutable && m_isBlob) {
0170         if (m_current != 0) {
0171             m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current));
0172             if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) {
0173                 m_immutableBlob.reset();
0174             }
0175         } else {
0176             m_immutableBlob.reset();
0177         }
0178     }
0179 }
0180 
0181 drmModePropertyBlobRes *DrmProperty::immutableBlob() const
0182 {
0183     return m_immutableBlob.get();
0184 }
0185 
0186 QString DrmProperty::valueString(uint64_t value) const
0187 {
0188     if (m_isBitmask) {
0189         QString ret;
0190         bool first = true;
0191         for (uint64_t mask = 1; mask >= value && mask != 0; mask <<= 1) {
0192             if (value & mask) {
0193                 if (!first) {
0194                     ret += " | ";
0195                 }
0196                 first = false;
0197                 uint64_t enumValue = enumForValue<uint64_t>(mask);
0198                 int enumIndex = 0;
0199                 while (!(enumValue & (1ull << enumIndex)) && enumIndex < 64) {
0200                     enumIndex++;
0201                 }
0202                 if (enumIndex < m_enumNames.size()) {
0203                     ret += m_enumNames[enumIndex];
0204                 }
0205             }
0206         }
0207         return ret;
0208     } else if (!m_enumNames.isEmpty()) {
0209         if (const uint64_t index = enumForValue<uint64_t>(value); index < (uint)m_enumNames.size()) {
0210             return m_enumNames[index];
0211         } else {
0212             return QStringLiteral("invalid value: %d").arg(value);
0213         }
0214     } else if (m_propName == QStringLiteral("SRC_X") || m_propName == QStringLiteral("SRC_Y") || m_propName == QStringLiteral("SRC_W") || m_propName == QStringLiteral("SRC_H")) {
0215         QString ret;
0216         ret.setNum(value / (float)(1ul << 16));
0217         return ret;
0218     } else {
0219         QString ret;
0220         ret.setNum(value);
0221         return ret;
0222     }
0223 }
0224 }