kwin/src/backends/drm/drm_object.cpp

229 lines
6.9 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2016 Roman Gilg <subdiff@gmail.com>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "drm_object.h"
#include <errno.h>
#include "drm_gpu.h"
#include "drm_logging.h"
#include "drm_pointer.h"
namespace KWin
{
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());
}
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<uint32_t>(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<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 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<drmModePropertyRes> 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<DrmProperty>(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;
}