Commit c0c3ec09 authored by Xaver Hugl's avatar Xaver Hugl
Browse files

Refactor DrmObject

parent e262c8df
......@@ -4,9 +4,6 @@ add_subdirectory(libkwineffects)
add_subdirectory(libxrenderutils)
add_subdirectory(integration)
add_subdirectory(libinput)
if (HAVE_DRM)
add_subdirectory(drm)
endif()
add_subdirectory(tabbox)
########################################################
......
include_directories(${Libdrm_INCLUDE_DIRS})
set(mockDRM_SRCS
mock_drm.cpp
../../src/plugins/platforms/drm/drm_buffer.cpp
../../src/plugins/platforms/drm/drm_object.cpp
../../src/plugins/platforms/drm/drm_object_connector.cpp
../../src/plugins/platforms/drm/drm_object_plane.cpp
../../src/plugins/platforms/drm/logging.cpp
)
add_library(mockDrm STATIC ${mockDRM_SRCS})
target_link_libraries(mockDrm Qt::Gui)
ecm_mark_as_test(mockDrm)
function(drmTest)
set(oneValueArgs NAME)
set(multiValueArgs SRCS )
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
add_executable(${ARGS_NAME} ${ARGS_SRCS})
target_link_libraries(${ARGS_NAME} mockDrm Qt::Test)
add_test(NAME kwin-drm-${ARGS_NAME} COMMAND ${ARGS_NAME})
ecm_mark_as_test(${ARGS_NAME})
endfunction()
drmTest(NAME objecttest SRCS objecttest.cpp)
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mock_drm.h"
#include <QMap>
static QMap<int, QVector<_drmModeProperty>> s_drmProperties{};
namespace MockDrm
{
void addDrmModeProperties(int fd, const QVector<_drmModeProperty> &properties)
{
s_drmProperties.insert(fd, properties);
}
}
int drmModeAtomicAddProperty(drmModeAtomicReqPtr req, uint32_t object_id, uint32_t property_id, uint64_t value)
{
Q_UNUSED(req)
Q_UNUSED(object_id)
Q_UNUSED(property_id)
Q_UNUSED(value)
return 0;
}
drmModePropertyPtr drmModeGetProperty(int fd, uint32_t propertyId)
{
auto it = s_drmProperties.find(fd);
if (it == s_drmProperties.end()) {
return nullptr;
}
auto it2 = std::find_if(it->constBegin(), it->constEnd(),
[propertyId] (const auto &property) {
return property.prop_id == propertyId;
}
);
if (it2 == it->constEnd()) {
return nullptr;
}
auto *property = new _drmModeProperty;
property->prop_id = it2->prop_id;
property->flags = it2->flags;
strcpy(property->name, it2->name);
property->count_values = it2->count_values;
property->values = it2->values;
property->count_enums = it2->count_enums;
property->enums = it2->enums;
property->count_blobs = it2->count_blobs;
property->blob_ids = it2->blob_ids;
return property;
}
void drmModeFreeProperty(drmModePropertyPtr ptr)
{
delete ptr;
}
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include <xf86drmMode.h>
#include <QVector>
namespace MockDrm
{
void addDrmModeProperties(int fd, const QVector<_drmModeProperty> &properties);
}
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "mock_drm.h"
#include "../../src/plugins/platforms/drm/drm_object.h"
#include <QtTest>
class MockDrmObject : public KWin::DrmObject
{
public:
MockDrmObject(uint32_t id, int fd)
: DrmObject(id, fd)
{
}
~MockDrmObject() override {}
bool init() override;
bool initProps() override;
void setProperties(uint32_t count, uint32_t *props, uint64_t *values) {
m_count = count;
m_props = props;
m_values = values;
}
QByteArray name(int prop) const {
auto property = DrmObject::m_props.at(prop);
if (!property) {
return QByteArray();
}
return property->name();
}
uint32_t propertyId(int prop) const {
auto property = DrmObject::m_props.at(prop);
if (!property) {
return 0xFFFFFFFFu;
}
return property->propId();
}
private:
uint32_t m_count = 0;
uint32_t *m_props = nullptr;
uint64_t *m_values = nullptr;
};
bool MockDrmObject::init()
{
return initProps();
}
bool MockDrmObject::initProps()
{
setPropertyNames({"foo", "bar", "baz"});
drmModeObjectProperties properties{m_count, m_props, m_values};
for (int i = 0; i < 3; i++) {
initProp(i, &properties);
}
return false;
}
class ObjectTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testId_data();
void testId();
void testFd_data();
void testFd();
void testInitProperties();
};
void ObjectTest::testId_data()
{
QTest::addColumn<quint32>("id");
QTest::newRow("0") << 0u;
QTest::newRow("1") << 1u;
QTest::newRow("10") << 10u;
QTest::newRow("uint max") << 0xFFFFFFFFu;
}
void ObjectTest::testId()
{
QFETCH(quint32, id);
MockDrmObject object{id, -1};
QCOMPARE(object.id(), id);
}
void ObjectTest::testFd_data()
{
QTest::addColumn<int>("fd");
QTest::newRow("-1") << -1;
QTest::newRow("0") << 0;
QTest::newRow("1") << 1;
QTest::newRow("2") << 2;
QTest::newRow("100") << 100;
QTest::newRow("int max") << 0x7FFFFFFF;
}
void ObjectTest::testFd()
{
QFETCH(int, fd);
MockDrmObject object{0, fd};
QCOMPARE(object.fd(), fd);
}
namespace KWin
{
class DrmOutput {
public:
int foo;
};
}
void ObjectTest::testInitProperties()
{
MockDrmObject object{0, 20};
uint32_t propertiesIds[] = { 0, 1, 2, 3};
uint64_t values[] = { 0, 2, 10, 20 };
object.setProperties(4, propertiesIds, values);
MockDrm::addDrmModeProperties(20, QVector<_drmModeProperty>{
_drmModeProperty{
0,
0,
"foo\0",
0,
nullptr,
0,
nullptr,
0,
nullptr
},
_drmModeProperty{
1,
0,
"foobar\0",
0,
nullptr,
0,
nullptr,
0,
nullptr
},
_drmModeProperty{
2,
0,
"baz\0",
0,
nullptr,
0,
nullptr,
0,
nullptr
},
_drmModeProperty{
3,
0,
"foobarbaz\0",
0,
nullptr,
0,
nullptr,
0,
nullptr
}
});
object.init();
// verify the names
QCOMPARE(object.name(0), QByteArrayLiteral("foo"));
QCOMPARE(object.name(1), QByteArray());
QCOMPARE(object.name(2), QByteArrayLiteral("baz"));
// verify the property ids
QCOMPARE(object.propertyId(0), 0u);
QCOMPARE(object.propertyId(1), 0xFFFFFFFFu);
QCOMPARE(object.propertyId(2), 2u);
// doesn't have enums
QCOMPARE(object.propHasEnum(0, 0), false);
QCOMPARE(object.propHasEnum(1, 0), false);
QCOMPARE(object.propHasEnum(2, 0), false);
}
QTEST_GUILESS_MAIN(ObjectTest)
#include "objecttest.moc"
......@@ -31,46 +31,49 @@ DrmObject::~DrmObject()
}
}
void DrmObject::setPropertyNames(QVector<QByteArray> &&vector)
bool DrmObject::initProps(const QVector<PropertyDefinition> &&vector, uint32_t objectType)
{
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]) );
DrmScopedPointer<drmModeObjectProperties> properties(drmModeObjectGetProperties(fd(), m_id, objectType));
if (!properties) {
qCWarning(KWIN_DRM) << "Failed to get properties for object" << m_id;
return false;
}
m_props.resize(vector.count());
for (uint32_t i = 0; i < properties->count_props; i++) {
DrmScopedPointer<drmModePropertyRes> prop(drmModeGetProperty(fd(), properties->props[i]));
if (!prop) {
qCWarning(KWIN_DRM) << "Getting property" << i << "failed";
qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", i, m_id);
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;
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(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(prop.data(), properties->prop_values[i], def.enumNames, blob);
break;
}
}
}
qCWarning(KWIN_DRM) << "Initializing property" << m_propsNames[n] << "failed";
for (int i = 0; i < vector.count(); i++) {
if (!m_props[i]) {
qCWarning(KWIN_DRM) << "Could not find property" << vector[i].name;
}
}
return true;
}
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 || property->isImmutable()) {
continue;
for (const auto &property : qAsConst(m_props)) {
if (property && !property->isImmutable()) {
ret &= atomicAddProperty(req, property);
}
ret &= atomicAddProperty(req, property);
}
if (!ret) {
......@@ -80,21 +83,6 @@ bool DrmObject::doAtomicPopulate(drmModeAtomicReq *req, int firstProperty) const
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) {
......@@ -109,11 +97,12 @@ bool DrmObject::atomicAddProperty(drmModeAtomicReq *req, Property *property) con
* Definitions for struct Prop
*/
DrmObject::Property::Property(drmModePropertyRes *prop, uint64_t val, QVector<QByteArray> enumNames)
DrmObject::Property::Property(drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames, drmModePropertyBlobRes *blob)
: m_propId(prop->prop_id)
, m_propName(prop->name)
, m_value(val)
, m_immutable(prop->flags & DRM_MODE_PROP_IMMUTABLE)
, m_blob(blob)
{
if (!enumNames.isEmpty()) {
qCDebug(KWIN_DRM) << m_propName << " can have enums:" << enumNames;
......@@ -175,7 +164,7 @@ void DrmObject::Property::initEnumMap(drmModePropertyRes *prop)
}
QDebug& operator<<(QDebug& s, const KWin::DrmObject* obj)
QDebug& operator<<(QDebug& s, const KWin::DrmObject *obj)
{
return s.nospace() << "DrmObject(" << obj->id() << ", fd: "<< obj->fd() << ')';
}
......@@ -14,6 +14,7 @@
// drm
#include <xf86drmMode.h>
#include "drm_pointer.h"
namespace KWin
{
......@@ -51,25 +52,47 @@ public:
* @param req the atomic request
* @return true when the request was successfully populated
*/
virtual bool atomicPopulate(drmModeAtomicReq *req) const;
bool atomicPopulate(drmModeAtomicReq *req) const;
void setValue(int prop, uint64_t new_value);
bool propHasEnum(int prop, uint64_t value) const;
template <typename T>
void setValue(T prop, uint64_t new_value)
{
if (auto &property = m_props.at(static_cast<uint32_t>(prop))) {
property->setValue(new_value);
}
}
template <typename T>
bool propHasEnum(T prop, uint64_t value) const
{
const auto &property = m_props.at(static_cast<uint32_t>(prop));
return property ? property->hasEnum(value) : false;
}
protected:
struct PropertyDefinition
{
PropertyDefinition(const QByteArray &name, const QVector<QByteArray> &&enumNames = {})
: name(name), enumNames(enumNames)
{
}
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
*/
virtual bool initProps() = 0;
void setPropertyNames(QVector<QByteArray> &&vector);
void initProp(int n, drmModeObjectProperties *properties,
QVector<QByteArray> enumNames = QVector<QByteArray>(0));
bool initProps(const QVector<PropertyDefinition> &&vector, uint32_t objectType);
bool doAtomicPopulate(drmModeAtomicReq *req, int firstProperty) const;
template <typename T>
void deleteProp(T prop)
{
delete m_props[static_cast<uint32_t>(prop)];
m_props[static_cast<uint32_t>(prop)] = nullptr;
}
class Property;
bool atomicAddProperty(drmModeAtomicReq *req, Property *property) const;
......@@ -83,7 +106,7 @@ protected:
class Property
{
public:
Property(drmModePropertyRes *prop, uint64_t val, QVector<QByteArray> enumNames);
Property(drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames, drmModePropertyBlobRes *blob);
virtual ~Property();
void initEnumMap(drmModePropertyRes *prop);
......@@ -117,6 +140,9 @@ protected:
bool isImmutable() const {
return m_immutable;
}
drmModePropertyBlobRes *blob() const {
return m_blob.data();
}
private:
uint32_t m_propId = 0;
......@@ -126,6 +152,7 @@ protected:
QVector<uint64_t> m_enumMap;
QVector<QByteArray> m_enumNames;
bool m_immutable = false;
DrmScopedPointer<drmModePropertyBlobRes> m_blob;
};
private:
......
......@@ -31,32 +31,10 @@ bool DrmConnector::init()
{
qCDebug(KWIN_DRM) << "Creating connector" << m_id;
if (!initProps()) {
return false;
}
return true;
}
bool DrmConnector::initProps()
{
setPropertyNames( {
QByteArrayLiteral("CRTC_ID"),
QByteArrayLiteral("non-desktop")
});
DrmScopedPointer<drmModeObjectProperties> properties(
drmModeObjectGetProperties(fd(), m_id, DRM_MODE_OBJECT_CONNECTOR));
if (!properties) {
qCWarning(KWIN_DRM) << "Failed to get properties for connector " << m_id ;
return false;
}
int propCount = int(PropertyIndex::Count);
for (int j = 0; j < propCount; ++j) {
initProp(j, properties.data());
}
return true;
return initProps({
PropertyDefinition(QByteArrayLiteral("CRTC_ID")),
PropertyDefinition(QByteArrayLiteral("non-desktop")),
}, DRM_MODE_OBJECT_CONNECTOR);
}
bool DrmConnector::isConnected()
......
......@@ -23,7 +23,7 @@ public:
bool init() override;
enum class PropertyIndex {
enum class PropertyIndex : uint32_t {
CrtcId = 0,
NonDesktop = 1,
Count
......@@ -33,17 +33,17 @@ public:
return m_encoders;
}
bool initProps() override;
bool isConnected();
bool isNonDesktop() const {
auto prop = m_props.at(static_cast<int>(PropertyIndex::NonDesktop));
auto prop = m_props.at(static_cast<uint32_t>(PropertyIndex::NonDesktop));
if (!prop) {
return false;
}
return prop->value();
}
private:
DrmScopedPointer<drmModeConnector> m_conn;
QVector<uint32_t> m_encoders;
};
......
......@@ -19,50 +19,23 @@ namespace KWin
DrmCrtc::DrmCrtc(uint32_t crtc_id, DrmBackend *backend, DrmGpu *gpu, int resIndex)
: DrmObject