backends/drm: fetch immutable blobs in DrmProperty

If the blob is fetched while there is no kernel-visible reference to it,
the driver may re-use the blob ID. When DrmProperty is created or updated,
KWin holds a reference on the blob via drmModeObjectProperties, so this
should prevent any possible issues.

CCBUG: 449285
This commit is contained in:
Xaver Hugl 2022-04-04 20:19:05 +02:00
parent d6af43763c
commit 34616520c2
4 changed files with 53 additions and 31 deletions

View file

@ -312,16 +312,11 @@ bool DrmConnector::updateProperties()
}
// parse edid
auto edidProp = getProp(PropertyIndex::Edid);
if (edidProp) {
DrmScopedPointer<drmModePropertyBlobRes> blob(drmModeGetPropertyBlob(gpu()->fd(), edidProp->current()));
if (blob && blob->data) {
m_edid = Edid(blob->data, blob->length);
if (!m_edid.isValid()) {
qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this;
}
if (const auto edidProp = getProp(PropertyIndex::Edid); edidProp && edidProp->immutableBlob()) {
m_edid = Edid(edidProp->immutableBlob()->data, edidProp->immutableBlob()->length);
if (!m_edid.isValid()) {
qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this;
}
deleteProp(PropertyIndex::Edid);
} else {
qCDebug(KWIN_DRM) << "Could not find edid for connector" << this;
}

View file

@ -67,29 +67,26 @@ bool DrmPlane::init()
checkSupport(5, Transformation::ReflectY);
// read formats from blob if available and if modifiers are supported, and from the plane object if not
if (auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && gpu()->addFB2ModifiersSupported()) {
DrmScopedPointer<drmModePropertyBlobRes> propertyBlob(drmModeGetPropertyBlob(gpu()->fd(), formatProp->current()));
if (propertyBlob && propertyBlob->data) {
auto blob = static_cast<drm_format_modifier_blob *>(propertyBlob->data);
auto modifiers = reinterpret_cast<drm_format_modifier *>(reinterpret_cast<uint8_t *>(blob) + blob->modifiers_offset);
uint32_t *formatarr = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(blob) + blob->formats_offset);
if (const auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && formatProp->immutableBlob() && gpu()->addFB2ModifiersSupported()) {
auto blob = static_cast<drm_format_modifier_blob *>(formatProp->immutableBlob()->data);
auto modifiers = reinterpret_cast<drm_format_modifier *>(reinterpret_cast<uint8_t *>(blob) + blob->modifiers_offset);
uint32_t *formatarr = reinterpret_cast<uint32_t *>(reinterpret_cast<uint8_t *>(blob) + blob->formats_offset);
for (uint32_t f = 0; f < blob->count_formats; f++) {
auto format = formatarr[f];
QVector<uint64_t> mods;
for (uint32_t m = 0; m < blob->count_modifiers; m++) {
auto modifier = &modifiers[m];
// The modifier advertisement blob is partitioned into groups of 64 formats
if (m < modifier->offset || m > modifier->offset + 63) {
continue;
}
if (!(modifier->formats & (1 << (f - modifier->offset)))) {
continue;
}
mods << modifier->modifier;
for (uint32_t f = 0; f < blob->count_formats; f++) {
auto format = formatarr[f];
QVector<uint64_t> mods;
for (uint32_t m = 0; m < blob->count_modifiers; m++) {
auto modifier = &modifiers[m];
// The modifier advertisement blob is partitioned into groups of 64 formats
if (m < modifier->offset || m > modifier->offset + 63) {
continue;
}
m_supportedFormats.insert(format, mods);
if (!(modifier->formats & (1 << (f - modifier->offset)))) {
continue;
}
mods << modifier->modifier;
}
m_supportedFormats.insert(format, mods);
}
} else {
for (uint32_t i = 0; i < p->count_formats; i++) {

View file

@ -24,6 +24,7 @@ DrmProperty::DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val,
, m_next(val)
, m_current(val)
, m_immutable(prop->flags & DRM_MODE_PROP_IMMUTABLE)
, m_isBlob(prop->flags & DRM_MODE_PROP_BLOB)
, m_obj(obj)
{
if (!enumNames.isEmpty()) {
@ -35,6 +36,7 @@ DrmProperty::DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val,
m_minValue = prop->values[0];
m_maxValue = prop->values[1];
}
updateBlob();
}
DrmProperty::~DrmProperty() = default;
@ -110,7 +112,10 @@ bool DrmProperty::needsCommit() const
void DrmProperty::setCurrent(uint64_t value)
{
m_current = value;
if (m_current != value) {
updateBlob();
m_current = value;
}
}
uint64_t DrmProperty::current() const
@ -122,10 +127,12 @@ QVector<QByteArray> DrmProperty::enumNames() const
{
return m_enumNames;
}
bool DrmProperty::hasEnum(uint64_t value) const
{
return m_enumMap.contains(value);
}
bool DrmProperty::hasAllEnums() const
{
return m_enumMap.count() == m_enumNames.count();
@ -166,4 +173,22 @@ uint64_t DrmProperty::maxValue() const
return m_maxValue;
}
void DrmProperty::updateBlob()
{
if (m_immutable && m_isBlob) {
if (m_current != 0) {
m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current));
if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) {
m_immutableBlob.reset();
}
} else {
m_immutableBlob.reset();
}
}
}
drmModePropertyBlobRes *DrmProperty::immutableBlob() const
{
return m_immutableBlob.get();
}
}

View file

@ -9,9 +9,9 @@
*/
#pragma once
#include "drm_pointer.h"
#include <xf86drmMode.h>
#include <QByteArray>
#include <QMap>
#include <QVector>
@ -61,6 +61,7 @@ public:
void setCurrent(uint64_t value);
uint64_t current() const;
drmModePropertyBlobRes *immutableBlob() const;
uint64_t minValue() const;
uint64_t maxValue() const;
@ -81,6 +82,8 @@ public:
}
private:
void updateBlob();
uint32_t m_propId = 0;
QByteArray m_propName;
@ -92,6 +95,7 @@ private:
uint64_t m_next = 0;
// the value currently set for or by the kernel
uint64_t m_current = 0;
DrmScopedPointer<drmModePropertyBlobRes> m_immutableBlob;
uint64_t m_minValue = -1;
uint64_t m_maxValue = -1;
@ -99,6 +103,7 @@ private:
QMap<uint32_t, uint64_t> m_enumMap;
QVector<QByteArray> m_enumNames;
const bool m_immutable;
const bool m_isBlob;
bool m_legacy = false;
const DrmObject *m_obj;
};