You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
5.7 KiB
186 lines
5.7 KiB
/******************************************************************** |
|
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]; |
|
} |
|
} |
|
} |
|
} |
|
|
|
}
|
|
|