platforms/drm: update properties on VT switch and failing commits

This commit is contained in:
Xaver Hugl 2021-06-03 15:50:37 +02:00
parent 586efe94d4
commit 5ad0d18476
8 changed files with 137 additions and 97 deletions

View file

@ -142,6 +142,7 @@ void DrmBackend::reactivate()
m_active = true;
for (const auto &output : qAsConst(m_outputs)) {
output->pipeline()->updateProperties();
if (output->isEnabled()) {
output->renderLoop()->uninhibit();
output->showCursor();

View file

@ -19,10 +19,13 @@ namespace KWin
* Definitions for class DrmObject
*/
DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId)
DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType)
: m_gpu(gpu)
, m_id(objectId)
, m_objectType(objectType)
, m_propertyDefinitions(vector)
{
m_props.resize(m_propertyDefinitions.count());
}
DrmObject::~DrmObject()
@ -30,37 +33,15 @@ DrmObject::~DrmObject()
qDeleteAll(m_props);
}
bool DrmObject::initProps(const QVector<PropertyDefinition> &&vector, uint32_t objectType)
bool DrmObject::initProps()
{
DrmScopedPointer<drmModeObjectProperties> properties(drmModeObjectGetProperties(m_gpu->fd(), m_id, objectType));
if (!properties) {
qCWarning(KWIN_DRM) << "Failed to get properties for object" << m_id;
if (!updateProperties()) {
return false;
}
m_props.resize(vector.count());
for (uint32_t i = 0; i < properties->count_props; i++) {
DrmScopedPointer<drmModePropertyRes> prop(drmModeGetProperty(m_gpu->fd(), properties->props[i]));
if (!prop) {
qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", i, m_id);
continue;
}
for (int j = 0; j < vector.count(); j++) {
const PropertyDefinition &def = vector[j];
if (def.name == prop->name) {
drmModePropertyBlobRes *blob = nullptr;
if (prop->flags & DRM_MODE_PROP_BLOB) {
blob = drmModeGetPropertyBlob(m_gpu->fd(), properties->prop_values[i]);
}
qCDebug(KWIN_DRM, "Found property %s with value %lu", def.name.data(), properties->prop_values[i]);
m_props[j] = new Property(m_gpu, prop.data(), properties->prop_values[i], def.enumNames, blob);
break;
}
}
}
if (KWIN_DRM().isDebugEnabled()) {
for (int i = 0; i < vector.count(); i++) {
if (KWIN_DRM().isDebugEnabled() && m_gpu->atomicModeSetting()) {
for (int i = 0; i < m_propertyDefinitions.count(); i++) {
if (!m_props[i]) {
qCDebug(KWIN_DRM) << "Could not find property" << vector[i].name;
qCDebug(KWIN_DRM) << "Could not find property" << m_propertyDefinitions[i].name;
}
}
}
@ -123,8 +104,50 @@ bool DrmObject::needsCommit() const
return false;
}
bool DrmObject::updateProperties()
{
DrmScopedPointer<drmModeObjectProperties> 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 i = 0; i < m_propertyDefinitions.count(); i++) {
const PropertyDefinition &def = m_propertyDefinitions[i];
bool found = false;
for (uint32_t j = 0; j < properties->count_props; j++) {
DrmScopedPointer<drmModePropertyRes> prop(drmModeGetProperty(m_gpu->fd(), properties->props[j]));
if (!prop) {
qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", j, m_id);
continue;
}
if (def.name == prop->name) {
drmModePropertyBlobRes *blob = nullptr;
if (prop->flags & DRM_MODE_PROP_BLOB) {
blob = drmModeGetPropertyBlob(m_gpu->fd(), properties->prop_values[j]);
}
if (m_props[i]) {
if (prop->flags & DRM_MODE_PROP_BLOB) {
m_props[i]->setCurrentBlob(blob);
} else {
m_props[i]->setCurrent(properties->prop_values[i]);
}
} else {
qCDebug(KWIN_DRM, "Found property %s with value %lu", def.name.data(), properties->prop_values[j]);
m_props[i] = new Property(m_gpu, prop.data(), properties->prop_values[j], def.enumNames, blob);
}
found = true;
break;
}
}
if (!found) {
deleteProp(i);
}
}
return true;
}
/*
* Definitions for struct Prop
* Definitions for DrmObject::Property
*/
DrmObject::Property::Property(DrmGpu *gpu, drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames, drmModePropertyBlobRes *blob)

View file

@ -26,12 +26,6 @@ class DrmOutput;
class DrmObject
{
public:
/**
* Create DRM object representation.
* @param object_id provided by the kernel
* @param fd of the DRM device
*/
DrmObject(DrmGpu *gpu, uint32_t objectId);
virtual ~DrmObject();
/**
@ -182,6 +176,8 @@ public:
bool needsCommit() const;
virtual bool needsModeset() const = 0;
virtual bool updateProperties();
protected:
struct PropertyDefinition
{
@ -192,13 +188,10 @@ protected:
QByteArray name;
QVector<QByteArray> enumNames;
};
/**
* Initialize properties of object. Only derived classes know names and quantities of
* properties.
*
* @return true when properties have been initialized successfully
*/
bool initProps(const QVector<PropertyDefinition> &&vector, uint32_t objectType);
DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType);
bool initProps();
template <typename T>
void deleteProp(T prop)
@ -207,12 +200,13 @@ protected:
m_props[static_cast<uint32_t>(prop)] = nullptr;
}
// for comparison with received name of DRM object
QVector<Property *> m_props;
private:
DrmGpu *m_gpu;
const uint32_t m_id;
const uint32_t m_objectType;
const QVector<PropertyDefinition> m_propertyDefinitions;
};
}

View file

@ -22,7 +22,21 @@ namespace KWin
{
DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
: DrmObject(gpu, connectorId)
: DrmObject(gpu, connectorId, {
PropertyDefinition(QByteArrayLiteral("CRTC_ID")),
PropertyDefinition(QByteArrayLiteral("non-desktop")),
PropertyDefinition(QByteArrayLiteral("DPMS")),
PropertyDefinition(QByteArrayLiteral("EDID")),
PropertyDefinition(QByteArrayLiteral("overscan")),
PropertyDefinition(QByteArrayLiteral("vrr_capable")),
PropertyDefinition(QByteArrayLiteral("underscan"), {
QByteArrayLiteral("off"),
QByteArrayLiteral("on"),
QByteArrayLiteral("auto")
}),
PropertyDefinition(QByteArrayLiteral("underscan vborder")),
PropertyDefinition(QByteArrayLiteral("underscan hborder")),
}, DRM_MODE_OBJECT_CONNECTOR)
, m_conn(drmModeGetConnector(gpu->fd(), connectorId))
{
if (m_conn) {
@ -62,21 +76,7 @@ bool DrmConnector::init()
}
qCDebug(KWIN_DRM) << "Creating connector" << id();
if (!initProps({
PropertyDefinition(QByteArrayLiteral("CRTC_ID")),
PropertyDefinition(QByteArrayLiteral("non-desktop")),
PropertyDefinition(QByteArrayLiteral("DPMS")),
PropertyDefinition(QByteArrayLiteral("EDID")),
PropertyDefinition(QByteArrayLiteral("overscan")),
PropertyDefinition(QByteArrayLiteral("vrr_capable")),
PropertyDefinition(QByteArrayLiteral("underscan"), {
QByteArrayLiteral("off"),
QByteArrayLiteral("on"),
QByteArrayLiteral("auto")
}),
PropertyDefinition(QByteArrayLiteral("underscan vborder")),
PropertyDefinition(QByteArrayLiteral("underscan hborder")),
}, DRM_MODE_OBJECT_CONNECTOR)) {
if (!initProps()) {
return false;
}

View file

@ -18,7 +18,13 @@ namespace KWin
{
DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex)
: DrmObject(gpu, crtcId)
: DrmObject(gpu, crtcId, {
PropertyDefinition(QByteArrayLiteral("MODE_ID")),
PropertyDefinition(QByteArrayLiteral("ACTIVE")),
PropertyDefinition(QByteArrayLiteral("VRR_ENABLED")),
PropertyDefinition(QByteArrayLiteral("GAMMA_LUT")),
PropertyDefinition(QByteArrayLiteral("GAMMA_LUT_SIZE")),
}, DRM_MODE_OBJECT_CRTC)
, m_crtc(drmModeGetCrtc(gpu->fd(), crtcId))
, m_pipeIndex(pipeIndex)
{
@ -30,13 +36,7 @@ bool DrmCrtc::init()
return false;
}
qCDebug(KWIN_DRM) << "Init for CRTC:" << pipeIndex() << "id:" << id();
return initProps({
PropertyDefinition(QByteArrayLiteral("MODE_ID")),
PropertyDefinition(QByteArrayLiteral("ACTIVE")),
PropertyDefinition(QByteArrayLiteral("VRR_ENABLED")),
PropertyDefinition(QByteArrayLiteral("GAMMA_LUT")),
PropertyDefinition(QByteArrayLiteral("GAMMA_LUT_SIZE")),
}, DRM_MODE_OBJECT_CRTC);
return initProps();
}
void DrmCrtc::flipBuffer()

View file

@ -16,29 +16,7 @@ namespace KWin
{
DrmPlane::DrmPlane(DrmGpu *gpu, uint32_t planeId)
: DrmObject(gpu, planeId)
{
}
bool DrmPlane::init()
{
qCDebug(KWIN_DRM) << "Atomic init for plane:" << id();
DrmScopedPointer<drmModePlane> p(drmModeGetPlane(gpu()->fd(), id()));
if (!p) {
qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id();
return false;
}
m_possibleCrtcs = p->possible_crtcs;
int count_formats = p->count_formats;
m_formats.resize(count_formats);
for (int i = 0; i < count_formats; i++) {
m_formats[i] = p->formats[i];
}
bool success = initProps({
: DrmObject(gpu, planeId, {
PropertyDefinition(QByteArrayLiteral("type"), {
QByteArrayLiteral("Overlay"),
QByteArrayLiteral("Primary"),
@ -60,8 +38,29 @@ bool DrmPlane::init()
QByteArrayLiteral("rotate-270"),
QByteArrayLiteral("reflect-x"),
QByteArrayLiteral("reflect-y")}),
}, DRM_MODE_OBJECT_PLANE
);
}, DRM_MODE_OBJECT_PLANE)
{
}
bool DrmPlane::init()
{
qCDebug(KWIN_DRM) << "Atomic init for plane:" << id();
DrmScopedPointer<drmModePlane> p(drmModeGetPlane(gpu()->fd(), id()));
if (!p) {
qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id();
return false;
}
m_possibleCrtcs = p->possible_crtcs;
int count_formats = p->count_formats;
m_formats.resize(count_formats);
for (int i = 0; i < count_formats; i++) {
m_formats[i] = p->formats[i];
}
bool success = initProps();
if (success) {
m_supportedTransformations = Transformations();
auto checkSupport = [this] (uint64_t value, Transformation t) {

View file

@ -83,12 +83,23 @@ bool DrmPipeline::present(const QSharedPointer<DrmBuffer> &buffer)
return true;
}
}
bool result = m_gpu->atomicModeSetting() ? atomicCommit() : presentLegacy();
if (!result) {
qCWarning(KWIN_DRM) << "Present failed!" << strerror(errno);
printDebugInfo();
if (m_gpu->atomicModeSetting()) {
if (!atomicCommit()) {
// update properties and try again
updateProperties();
if (!atomicCommit()) {
qCWarning(KWIN_DRM) << "Atomic present failed!" << strerror(errno);
printDebugInfo();
return false;
}
}
} else {
if (!presentLegacy()) {
qCWarning(KWIN_DRM) << "Present failed!" << strerror(errno);
return false;
}
}
return result;
return true;
}
bool DrmPipeline::atomicCommit()
@ -333,6 +344,10 @@ bool DrmPipeline::setActive(bool active)
m_primaryPlane->setPending(DrmPlane::PropertyIndex::CrtcId, active ? m_crtc->id() : 0);
if (active) {
success = test();
if (!success) {
updateProperties();
success = test();
}
} else {
// immediately commit if disabling as there will be no present
success = atomicCommit();
@ -497,6 +512,13 @@ void DrmPipeline::setUserData(DrmOutput *data)
m_pageflipUserData = data;
}
void DrmPipeline::updateProperties()
{
for (const auto &obj : qAsConst(m_allObjects)) {
obj->updateProperties();
}
}
static void printProps(DrmObject *object)
{
auto list = object->properties();

View file

@ -71,6 +71,7 @@ public:
void printDebugInfo() const;
void setUserData(DrmOutput *data);
QSize sourceSize() const;
void updateProperties();
private:
bool atomicCommit();