kwin/plugins/platforms/drm/drm_object.cpp
Roman Gilg 7eafab7304 [platforms/drm] Return when property found
When initializing a property we loop through the drmModeObjectProperties
object and search for the property by its name.

Once found we create the Property object and there should be not another one
with the same name afterwards. In any case we would leak memory. Therefore just
directly return once the property was found.

This gives us the added benefit that we can put out a warning in case the
property was not found in the loop, what should not happen with the properties
we use.
2019-12-11 18:38:21 +01:00

186 lines
5.7 KiB
C++

/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2016 Roman Gilg <subdiff@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "drm_object.h"
#include "drm_pointer.h"
#include "logging.h"
namespace KWin
{
/*
* Definitions for class DrmObject
*/
DrmObject::DrmObject(uint32_t object_id, int fd)
: m_fd(fd)
, m_id(object_id)
{
}
DrmObject::~DrmObject()
{
for (auto *p : m_props) {
delete p;
}
}
void DrmObject::setPropertyNames(QVector<QByteArray> &&vector)
{
m_propsNames = std::move(vector);
m_props.fill(nullptr, m_propsNames.size());
}
void DrmObject::initProp(int n, drmModeObjectProperties *properties, QVector<QByteArray> enumNames)
{
for (unsigned int i = 0; i < properties->count_props; ++i) {
DrmScopedPointer<drmModePropertyRes> prop( drmModeGetProperty(fd(), properties->props[i]) );
if (!prop) {
qCWarning(KWIN_DRM) << "Getting property" << i << "failed";
continue;
}
if (prop->name == m_propsNames[n]) {
qCDebug(KWIN_DRM).nospace() << m_id << ": " << prop->name << "' (id " << prop->prop_id
<< "): " << properties->prop_values[i];
m_props[n] = new Property(prop.data(), properties->prop_values[i], enumNames);
return;
}
}
qCWarning(KWIN_DRM) << "Initializing property" << m_propsNames[n] << "failed";
}
bool DrmObject::atomicPopulate(drmModeAtomicReq *req) const
{
return doAtomicPopulate(req, 0);
}
bool DrmObject::doAtomicPopulate(drmModeAtomicReq *req, int firstProperty) const
{
bool ret = true;
for (int i = firstProperty; i < m_props.size(); i++) {
auto property = m_props.at(i);
if (!property) {
continue;
}
ret &= atomicAddProperty(req, property);
}
if (!ret) {
qCWarning(KWIN_DRM) << "Failed to populate atomic object" << m_id;
return false;
}
return true;
}
void DrmObject::setValue(int prop, uint64_t new_value)
{
Q_ASSERT(prop < m_props.size());
auto property = m_props.at(prop);
if (property) {
property->setValue(new_value);
}
}
bool DrmObject::propHasEnum(int prop, uint64_t value) const
{
auto property = m_props.at(prop);
return property ? property->hasEnum(value) : false;
}
bool DrmObject::atomicAddProperty(drmModeAtomicReq *req, Property *property) const
{
if (drmModeAtomicAddProperty(req, m_id, property->propId(), property->value()) <= 0) {
qCWarning(KWIN_DRM) << "Adding property" << property->name()
<< "to atomic commit failed for object" << this;
return false;
}
return true;
}
/*
* Definitions for struct Prop
*/
DrmObject::Property::Property(drmModePropertyRes *prop, uint64_t val, QVector<QByteArray> enumNames)
: m_propId(prop->prop_id)
, m_propName(prop->name)
, m_value(val)
{
if (!enumNames.isEmpty()) {
qCDebug(KWIN_DRM) << m_propName << " can have enums:" << enumNames;
m_enumNames = enumNames;
initEnumMap(prop);
}
}
DrmObject::Property::~Property() = default;
void DrmObject::Property::initEnumMap(drmModePropertyRes *prop)
{
if ( ( !(prop->flags & DRM_MODE_PROP_ENUM) && !(prop->flags & DRM_MODE_PROP_BITMASK) )
|| prop->count_enums < 1 ) {
qCWarning(KWIN_DRM) << "Property '" << prop->name << "' ( id ="
<< m_propId << ") should be enum valued, but it is not.";
return;
}
const int nameCount = m_enumNames.size();
m_enumMap.resize(nameCount);
qCDebug(KWIN_DRM).nospace() << "Available are " << prop->count_enums <<
" enums. Query their runtime values:";
for (int i = 0; i < prop->count_enums; i++) {
struct drm_mode_property_enum *en = &prop->enums[i];
int j = 0;
while (QByteArray(en->name) != m_enumNames[j]) {
j++;
if (j == nameCount) {
qCWarning(KWIN_DRM).nospace() << m_propName << " has unrecognized enum '"
<< en->name << "'";
break;
}
}
if (j < nameCount) {
qCDebug(KWIN_DRM).nospace() << "Enum '" << en->name
<< "': runtime-value = " << en->value;
m_enumMap[j] = en->value;
}
}
if (KWIN_DRM().isDebugEnabled()) {
for (int i = 0; i < m_enumMap.size(); i++) {
if (m_value == m_enumMap[i]) {
// TODO: This does not work with bitmask properties, because from kernel we get the
// values for some reason as the shift distance instead of the full value.
// See: https://github.com/torvalds/linux/blob/6794862a/drivers/
// gpu/drm/drm_blend.c#L267
qCDebug(KWIN_DRM) << "=>" << m_propName
<< "with mapped enum value" << m_enumNames[i];
}
}
}
}
}