backends/drm: store drm properties directly in drm objects

This makes it possible to ensure type safety for enums, as each drm property
object can have its own type now, and it reduces the amount of typing needed
to access properties
master
Xaver Hugl 1 year ago
parent adc5104e2a
commit e7c803b7e5

@ -272,7 +272,7 @@ void DrmTest::testModeGeneration()
mockGpu->connectors.removeAll(conn);
QVERIFY(gpu->updateOutputs());
conn->props.emplace_back(conn.get(), QStringLiteral("scaling mode"), 0, 0, QVector<QByteArray>{"None", "Full", "Center", "Full aspect"});
conn->props.emplace_back(conn.get(), QStringLiteral("scaling mode"), 0, DRM_MODE_PROP_ENUM, QVector<QByteArray>{"None", "Full", "Center", "Full aspect"});
mockGpu->connectors.push_back(conn);
QVERIFY(gpu->updateOutputs());

@ -231,7 +231,7 @@ MockPlane::MockPlane(MockGpu *gpu, PlaneType type, int crtcIndex)
, possibleCrtcs(1 << crtcIndex)
, type(type)
{
props << MockProperty(this, QStringLiteral("type"), static_cast<uint64_t>(type), DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK,
props << MockProperty(this, QStringLiteral("type"), static_cast<uint64_t>(type), DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM,
{QByteArrayLiteral("Primary"), QByteArrayLiteral("Overlay"), QByteArrayLiteral("Cursor")});
addProp("FB_ID", 0, DRM_MODE_PROP_ATOMIC);
addProp("CRTC_ID", 0, DRM_MODE_PROP_ATOMIC);

@ -107,7 +107,7 @@ public:
};
enum class PlaneType {
Primary,
Primary = 0,
Overlay,
Cursor
};

@ -21,15 +21,15 @@ DrmAtomicCommit::DrmAtomicCommit(DrmGpu *gpu)
{
}
void DrmAtomicCommit::addProperty(DrmProperty *prop, uint64_t value)
void DrmAtomicCommit::addProperty(const DrmProperty &prop, uint64_t value)
{
drmModeAtomicAddProperty(m_req.get(), prop->drmObject()->id(), prop->propId(), value);
drmModeAtomicAddProperty(m_req.get(), prop.drmObject()->id(), prop.propId(), value);
}
void DrmAtomicCommit::addBlob(DrmProperty *prop, const std::shared_ptr<DrmBlob> &blob)
void DrmAtomicCommit::addBlob(const DrmProperty &prop, const std::shared_ptr<DrmBlob> &blob)
{
addProperty(prop, blob ? blob->blobId() : 0);
m_blobs[prop] = blob;
m_blobs[&prop] = blob;
}
bool DrmAtomicCommit::test()

@ -28,12 +28,13 @@ class DrmAtomicCommit
public:
DrmAtomicCommit(DrmGpu *gpu);
void addProperty(DrmProperty *prop, uint64_t value);
void addEnum(DrmProperty *prop, auto enumValue)
void addProperty(const DrmProperty &prop, uint64_t value);
template<typename T>
void addEnum(const DrmEnumProperty<T> &prop, T enumValue)
{
addProperty(prop, prop->valueForEnum(enumValue));
addProperty(prop, prop.valueForEnum(enumValue));
}
void addBlob(DrmProperty *prop, const std::shared_ptr<DrmBlob> &blob);
void addBlob(const DrmProperty &prop, const std::shared_ptr<DrmBlob> &blob);
bool test();
bool testAllowModeset();
@ -45,7 +46,7 @@ public:
private:
DrmGpu *const m_gpu;
DrmUniquePtr<drmModeAtomicReq> m_req;
QHash<DrmProperty *, std::shared_ptr<DrmBlob>> m_blobs;
QHash<const DrmProperty *, std::shared_ptr<DrmBlob>> m_blobs;
};
}

@ -85,29 +85,50 @@ bool DrmConnectorMode::operator==(const DrmConnectorMode &otherMode)
}
DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
: DrmObject(gpu,
connectorId,
{PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("non-desktop"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("DPMS"), Requirement::RequiredForLegacy),
PropertyDefinition(QByteArrayLiteral("EDID"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("overscan"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("vrr_capable"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("underscan"), Requirement::Optional,
{QByteArrayLiteral("off"), QByteArrayLiteral("on"), QByteArrayLiteral("auto")}),
PropertyDefinition(QByteArrayLiteral("underscan vborder"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("underscan hborder"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("Broadcast RGB"), Requirement::Optional,
{QByteArrayLiteral("Automatic"), QByteArrayLiteral("Full"), QByteArrayLiteral("Limited 16:235")}),
PropertyDefinition(QByteArrayLiteral("max bpc"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("link-status"), Requirement::Optional,
{QByteArrayLiteral("Good"), QByteArrayLiteral("Bad")}),
PropertyDefinition(QByteArrayLiteral("content type"), Requirement::Optional,
{QByteArrayLiteral("No Data"), QByteArrayLiteral("Graphics"), QByteArrayLiteral("Photo"), QByteArrayLiteral("Cinema"), QByteArrayLiteral("Game")}),
PropertyDefinition(QByteArrayLiteral("panel orientation"), Requirement::Optional, {QByteArrayLiteral("Normal"), QByteArrayLiteral("Upside Down"), QByteArrayLiteral("Left Side Up"), QByteArrayLiteral("Right Side Up")}),
PropertyDefinition(QByteArrayLiteral("HDR_OUTPUT_METADATA"), Requirement::Optional),
PropertyDefinition(QByteArrayLiteral("scaling mode"), Requirement::Optional, {QByteArrayLiteral("None"), QByteArrayLiteral("Full"), QByteArrayLiteral("Center"), QByteArrayLiteral("Full aspect")})},
DRM_MODE_OBJECT_CONNECTOR)
: DrmObject(gpu, connectorId, DRM_MODE_OBJECT_CONNECTOR)
, crtcId(this, QByteArrayLiteral("CRTC_ID"))
, nonDesktop(this, QByteArrayLiteral("non-desktop"))
, dpms(this, QByteArrayLiteral("DPMS"))
, edidProp(this, QByteArrayLiteral("EDID"))
, overscan(this, QByteArrayLiteral("overscan"))
, vrrCapable(this, QByteArrayLiteral("vrr_capable"))
, underscan(this, QByteArrayLiteral("EDID"), {
QByteArrayLiteral("off"),
QByteArrayLiteral("on"),
QByteArrayLiteral("auto"),
})
, underscanVBorder(this, QByteArrayLiteral("underscan vborder"))
, underscanHBorder(this, QByteArrayLiteral("underscan hborder"))
, broadcastRGB(this, QByteArrayLiteral("Broadcast RGB"), {
QByteArrayLiteral("Automatic"),
QByteArrayLiteral("Full"),
QByteArrayLiteral("Limited 16:235"),
})
, maxBpc(this, QByteArrayLiteral("max bpc"))
, linkStatus(this, QByteArrayLiteral("link-status"), {
QByteArrayLiteral("Good"),
QByteArrayLiteral("Bad"),
})
, contentType(this, QByteArrayLiteral("content type"), {
QByteArrayLiteral("No Data"),
QByteArrayLiteral("Graphics"),
QByteArrayLiteral("Photo"),
QByteArrayLiteral("Cinema"),
QByteArrayLiteral("Game"),
})
, panelOrientation(this, QByteArrayLiteral("panel orientation"), {
QByteArrayLiteral("Normal"),
QByteArrayLiteral("Upside Down"),
QByteArrayLiteral("Left Side Up"),
QByteArrayLiteral("Right Side Up"),
})
, hdrMetadata(this, QByteArrayLiteral("HDR_OUTPUT_METADATA"))
, scalingMode(this, QByteArrayLiteral("scaling mode"), {
QByteArrayLiteral("None"),
QByteArrayLiteral("Full"),
QByteArrayLiteral("Center"),
QByteArrayLiteral("Full aspect"),
})
, m_pipeline(std::make_unique<DrmPipeline>(this))
, m_conn(drmModeGetConnector(gpu->fd(), connectorId))
{
@ -125,11 +146,6 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
}
}
bool DrmConnector::init()
{
return updateProperties();
}
bool DrmConnector::isConnected() const
{
return !m_driverModes.empty() && m_conn && m_conn->connection == DRM_MODE_CONNECTED;
@ -197,39 +213,6 @@ Output::SubPixel DrmConnector::subpixel() const
}
}
bool DrmConnector::hasOverscan() const
{
return getProp(PropertyIndex::Overscan) || getProp(PropertyIndex::Underscan);
}
uint32_t DrmConnector::overscan() const
{
if (const auto prop = getProp(PropertyIndex::Overscan)) {
return prop->current();
} else if (const auto prop = getProp(PropertyIndex::Underscan_vborder)) {
return prop->current();
}
return 0;
}
bool DrmConnector::vrrCapable() const
{
const auto prop = getProp(PropertyIndex::VrrCapable);
return prop && prop->current() == 1;
}
bool DrmConnector::hasRgbRange() const
{
const auto &rgb = getProp(PropertyIndex::Broadcast_RGB);
return rgb && rgb->hasAllEnums();
}
Output::RgbRange DrmConnector::rgbRange() const
{
const auto &rgb = getProp(PropertyIndex::Broadcast_RGB);
return rgb->enumForValue<Output::RgbRange>(rgb->current());
}
bool DrmConnector::updateProperties()
{
if (auto connector = drmModeGetConnector(gpu()->fd(), id())) {
@ -237,25 +220,31 @@ bool DrmConnector::updateProperties()
} else if (!m_conn) {
return false;
}
if (!DrmObject::updateProperties()) {
DrmPropertyList props = queryProperties();
crtcId.update(props);
nonDesktop.update(props);
dpms.update(props);
edidProp.update(props);
overscan.update(props);
vrrCapable.update(props);
underscan.update(props);
underscanVBorder.update(props);
underscanHBorder.update(props);
broadcastRGB.update(props);
maxBpc.update(props);
linkStatus.update(props);
contentType.update(props);
panelOrientation.update(props);
hdrMetadata.update(props);
scalingMode.update(props);
if (gpu()->atomicModeSetting() && !crtcId.isValid()) {
return false;
}
if (const auto &dpms = getProp(PropertyIndex::Dpms)) {
dpms->setLegacy();
}
auto &underscan = m_props[static_cast<uint32_t>(PropertyIndex::Underscan)];
auto &vborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_vborder)];
auto &hborder = m_props[static_cast<uint32_t>(PropertyIndex::Underscan_hborder)];
if (!underscan || !vborder || !hborder) {
underscan.reset();
vborder.reset();
hborder.reset();
}
// parse edid
if (const auto edidProp = getProp(PropertyIndex::Edid); edidProp && edidProp->immutableBlob()) {
m_edid = Edid(edidProp->immutableBlob()->data, edidProp->immutableBlob()->length);
if (edidProp.immutableBlob()) {
m_edid = Edid(edidProp.immutableBlob()->data, edidProp.immutableBlob()->length);
if (!m_edid.isValid()) {
qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this;
}
@ -283,7 +272,7 @@ bool DrmConnector::updateProperties()
}
m_modes.clear();
m_modes.append(m_driverModes);
if (auto scaling = getProp(PropertyIndex::ScalingMode); scaling && scaling->hasEnum(ScalingMode::Full_Aspect)) {
if (scalingMode.isValid() && scalingMode.hasEnum(ScalingMode::Full_Aspect)) {
m_modes.append(generateCommonModes());
}
if (m_pipeline->mode()) {
@ -311,8 +300,7 @@ bool DrmConnector::isCrtcSupported(DrmCrtc *crtc) const
bool DrmConnector::isNonDesktop() const
{
const auto &prop = getProp(PropertyIndex::NonDesktop);
return prop && prop->current();
return nonDesktop.isValid() && nonDesktop.value() == 1;
}
const Edid *DrmConnector::edid() const
@ -327,15 +315,7 @@ DrmPipeline *DrmConnector::pipeline() const
void DrmConnector::disable(DrmAtomicCommit *commit)
{
commit->addProperty(getProp(PropertyIndex::CrtcId), 0);
}
DrmConnector::LinkStatus DrmConnector::linkStatus() const
{
if (const auto &property = getProp(PropertyIndex::LinkStatus)) {
return property->enumForValue<LinkStatus>(property->current());
}
return LinkStatus::Good;
commit->addProperty(crtcId, 0);
}
static const QVector<QSize> s_commonModes = {
@ -413,15 +393,6 @@ std::shared_ptr<DrmConnectorMode> DrmConnector::generateMode(const QSize &size,
return std::make_shared<DrmConnectorMode>(this, mode);
}
DrmConnector::PanelOrientation DrmConnector::panelOrientation() const
{
if (const auto &property = getProp(PropertyIndex::PanelOrientation)) {
return property->enumForValue<PanelOrientation>(property->current());
} else {
return PanelOrientation::Normal;
}
}
QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj)
{
QDebugStateSaver saver(s);
@ -473,4 +444,32 @@ Output::Transform DrmConnector::toKWinTransform(PanelOrientation orientation)
Q_UNREACHABLE();
}
}
DrmConnector::BroadcastRgbOptions DrmConnector::rgbRangeToBroadcastRgb(Output::RgbRange rgbRange)
{
switch (rgbRange) {
case Output::RgbRange::Automatic:
return BroadcastRgbOptions::Automatic;
case Output::RgbRange::Full:
return BroadcastRgbOptions::Full;
case Output::RgbRange::Limited:
return BroadcastRgbOptions::Limited;
default:
Q_UNREACHABLE();
}
}
Output::RgbRange DrmConnector::broadcastRgbToRgbRange(BroadcastRgbOptions rgbRange)
{
switch (rgbRange) {
case BroadcastRgbOptions::Automatic:
return Output::RgbRange::Automatic;
case BroadcastRgbOptions::Full:
return Output::RgbRange::Full;
case BroadcastRgbOptions::Limited:
return Output::RgbRange::Limited;
default:
Q_UNREACHABLE();
}
}
}

@ -51,32 +51,36 @@ class DrmConnector : public DrmObject
public:
DrmConnector(DrmGpu *gpu, uint32_t connectorId);
enum class PropertyIndex : uint32_t {
CrtcId = 0,
NonDesktop = 1,
Dpms = 2,
Edid = 3,
Overscan = 4,
VrrCapable = 5,
Underscan = 6,
Underscan_vborder = 7,
Underscan_hborder = 8,
Broadcast_RGB = 9,
MaxBpc = 10,
LinkStatus = 11,
ContentType = 12,
PanelOrientation = 13,
HdrMetadata = 14,
ScalingMode = 15,
Count
};
bool updateProperties() override;
void disable(DrmAtomicCommit *commit) override;
bool isCrtcSupported(DrmCrtc *crtc) const;
bool isConnected() const;
bool isNonDesktop() const;
bool isInternal() const;
DrmPipeline *pipeline() const;
const Edid *edid() const;
QString connectorName() const;
QString modelName() const;
QSize physicalSize() const;
QList<std::shared_ptr<DrmConnectorMode>> modes() const;
std::shared_ptr<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const;
enum class UnderscanOptions : uint32_t {
Output::SubPixel subpixel() const;
enum class UnderscanOptions : uint64_t {
Off = 0,
On = 1,
Auto = 2,
};
enum class LinkStatus : uint32_t {
enum class BroadcastRgbOptions : uint64_t {
Automatic = 0,
Full = 1,
Limited = 2
};
enum class LinkStatus : uint64_t {
Good = 0,
Bad = 1
};
@ -87,48 +91,39 @@ public:
Cinema = 3,
Game = 4
};
enum class PanelOrientation : uint32_t {
enum class PanelOrientation : uint64_t {
Normal = 0,
UpsideDown = 1,
LeftUp = 2,
RightUp = 3
};
enum class ScalingMode : uint32_t {
enum class ScalingMode : uint64_t {
None = 0,
Full = 1,
Center = 2,
Full_Aspect = 3
};
bool init() override;
bool updateProperties() override;
void disable(DrmAtomicCommit *commit) override;
bool isCrtcSupported(DrmCrtc *crtc) const;
bool isConnected() const;
bool isNonDesktop() const;
bool isInternal() const;
DrmPipeline *pipeline() const;
const Edid *edid() const;
QString connectorName() const;
QString modelName() const;
QSize physicalSize() const;
QList<std::shared_ptr<DrmConnectorMode>> modes() const;
std::shared_ptr<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const;
Output::SubPixel subpixel() const;
bool hasOverscan() const;
uint32_t overscan() const;
bool vrrCapable() const;
bool hasRgbRange() const;
Output::RgbRange rgbRange() const;
LinkStatus linkStatus() const;
PanelOrientation panelOrientation() const;
DrmProperty crtcId;
DrmProperty nonDesktop;
DrmProperty dpms;
DrmProperty edidProp;
DrmProperty overscan;
DrmProperty vrrCapable;
DrmEnumProperty<UnderscanOptions> underscan;
DrmProperty underscanVBorder;
DrmProperty underscanHBorder;
DrmEnumProperty<BroadcastRgbOptions> broadcastRGB;
DrmProperty maxBpc;
DrmEnumProperty<LinkStatus> linkStatus;
DrmEnumProperty<DrmContentType> contentType;
DrmEnumProperty<PanelOrientation> panelOrientation;
DrmProperty hdrMetadata;
DrmEnumProperty<ScalingMode> scalingMode;
static DrmContentType kwinToDrmContentType(ContentType type);
static Output::Transform toKWinTransform(PanelOrientation orientation);
static BroadcastRgbOptions rgbRangeToBroadcastRgb(Output::RgbRange rgbRange);
static Output::RgbRange broadcastRgbToRgbRange(BroadcastRgbOptions rgbRange);
private:
QList<std::shared_ptr<DrmConnectorMode>> generateCommonModes();

@ -20,7 +20,13 @@ namespace KWin
{
DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane, DrmPlane *cursorPlane)
: DrmObject(gpu, crtcId, {PropertyDefinition(QByteArrayLiteral("MODE_ID"), Requirement::Required), PropertyDefinition(QByteArrayLiteral("ACTIVE"), Requirement::Required), PropertyDefinition(QByteArrayLiteral("VRR_ENABLED"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("GAMMA_LUT"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("GAMMA_LUT_SIZE"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("CTM"), Requirement::Optional)}, DRM_MODE_OBJECT_CRTC)
: DrmObject(gpu, crtcId, DRM_MODE_OBJECT_CRTC)
, modeId(this, QByteArrayLiteral("MODE_ID"))
, active(this, QByteArrayLiteral("ACTIVE"))
, vrrEnabled(this, QByteArrayLiteral("VRR_ENABLED"))
, gammaLut(this, QByteArrayLiteral("GAMMA_LUT"))
, gammaLutSize(this, QByteArrayLiteral("GAMMA_LUT_SIZE"))
, ctm(this, QByteArrayLiteral("CTM"))
, m_crtc(drmModeGetCrtc(gpu->fd(), crtcId))
, m_pipeIndex(pipeIndex)
, m_primaryPlane(primaryPlane)
@ -28,9 +34,20 @@ DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryP
{
}
bool DrmCrtc::init()
bool DrmCrtc::updateProperties()
{
return m_crtc && updateProperties();
if (!m_crtc) {
return false;
}
DrmPropertyList props = queryProperties();
modeId.update(props);
active.update(props);
vrrEnabled.update(props);
gammaLut.update(props);
gammaLutSize.update(props);
ctm.update(props);
return !gpu()->atomicModeSetting() || (modeId.isValid() && active.isValid());
}
void DrmCrtc::flipBuffer()
@ -74,8 +91,8 @@ int DrmCrtc::gammaRampSize() const
{
if (gpu()->atomicModeSetting()) {
// limit atomic gamma ramp to 4096 to work around https://gitlab.freedesktop.org/drm/intel/-/issues/3916
if (auto prop = getProp(PropertyIndex::Gamma_LUT_Size); prop && prop->current() <= 4096) {
return prop->current();
if (gammaLutSize.isValid() && gammaLutSize.value() <= 4096) {
return gammaLutSize.value();
}
}
return m_crtc->gamma_size;
@ -93,8 +110,8 @@ DrmPlane *DrmCrtc::cursorPlane() const
void DrmCrtc::disable(DrmAtomicCommit *commit)
{
commit->addProperty(getProp(PropertyIndex::Active), 0);
commit->addProperty(getProp(PropertyIndex::ModeId), 0);
commit->addProperty(active, 0);
commit->addProperty(modeId, 0);
}
void DrmCrtc::releaseBuffers()

@ -28,18 +28,8 @@ class DrmCrtc : public DrmObject
public:
DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane, DrmPlane *cursorPlane);
enum class PropertyIndex : uint32_t {
ModeId = 0,
Active,
VrrEnabled,
Gamma_LUT,
Gamma_LUT_Size,
CTM,
Count
};
bool init() override;
void disable(DrmAtomicCommit *commit) override;
bool updateProperties() override;
int pipeIndex() const;
int gammaRampSize() const;
@ -54,6 +44,13 @@ public:
void flipBuffer();
void releaseBuffers();
DrmProperty modeId;
DrmProperty active;
DrmProperty vrrEnabled;
DrmProperty gammaLut;
DrmProperty gammaLutSize;
DrmProperty ctm;
private:
DrmUniquePtr<drmModeCrtc> m_crtc;
std::shared_ptr<DrmFramebuffer> m_currentBuffer;

@ -173,9 +173,9 @@ void DrmGpu::initDrmResources()
QVector<DrmPlane *> cursorCandidates;
for (const auto &plane : m_planes) {
if (plane->isCrtcSupported(i) && !assignedPlanes.contains(plane.get())) {
if (plane->type() == DrmPlane::TypeIndex::Primary) {
if (plane->type.enumValue() == DrmPlane::TypeIndex::Primary) {
primaryCandidates.push_back(plane.get());
} else if (plane->type() == DrmPlane::TypeIndex::Cursor) {
} else if (plane->type.enumValue() == DrmPlane::TypeIndex::Cursor) {
cursorCandidates.push_back(plane.get());
}
}
@ -187,14 +187,14 @@ void DrmGpu::initDrmResources()
const auto findBestPlane = [crtcId](const QVector<DrmPlane *> &list) {
// if the plane is already used with this crtc, prefer it
const auto connected = std::find_if(list.begin(), list.end(), [crtcId](DrmPlane *plane) {
return plane->getProp(DrmPlane::PropertyIndex::CrtcId)->current() == crtcId;
return plane->crtcId.value() == crtcId;
});
if (connected != list.end()) {
return *connected;
}
// don't take away planes from other crtcs. The kernel currently rejects such commits
const auto notconnected = std::find_if(list.begin(), list.end(), [](DrmPlane *plane) {
return plane->getProp(DrmPlane::PropertyIndex::CrtcId)->current() == 0;
return plane->crtcId.value() == 0;
});
if (notconnected != list.end()) {
return *notconnected;
@ -375,7 +375,7 @@ DrmPipeline::Error DrmGpu::checkCrtcAssignment(QVector<DrmConnector *> connector
DrmCrtc *currentCrtc = nullptr;
if (m_atomicModeSetting) {
// try the crtc that this connector is already connected to first
const uint32_t id = connector->getProp(DrmConnector::PropertyIndex::CrtcId)->current();
const uint32_t id = connector->crtcId.value();
auto it = std::find_if(crtcs.begin(), crtcs.end(), [id](const auto &crtc) {
return id == crtc->id();
});
@ -432,7 +432,7 @@ DrmPipeline::Error DrmGpu::testPendingConfiguration()
if (m_atomicModeSetting) {
// sort outputs by being already connected (to any CRTC) so that already working outputs get preferred
std::sort(connectors.begin(), connectors.end(), [](auto c1, auto c2) {
return c1->getProp(DrmConnector::PropertyIndex::CrtcId)->current() > c2->getProp(DrmConnector::PropertyIndex::CrtcId)->current();
return c1->crtcId.value() > c2->crtcId.value();
});
}
return checkCrtcAssignment(connectors, crtcs);

@ -18,54 +18,35 @@
namespace KWin
{
DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType)
DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, uint32_t objectType)
: m_gpu(gpu)
, m_id(objectId)
, m_objectType(objectType)
, m_propertyDefinitions(vector)
{
m_props.resize(m_propertyDefinitions.count());
}
bool DrmObject::updateProperties()
bool DrmObject::init()
{
return updateProperties();
}
DrmPropertyList DrmObject::queryProperties() const
{
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;
return {};
}
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]));
DrmPropertyList ret;
for (uint32_t i = 0; i < properties->count_props; i++) {
DrmUniquePtr<drmModePropertyRes> prop(drmModeGetProperty(m_gpu->fd(), properties->props[i]));
if (!prop) {
qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", drmPropIndex, m_id);
qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", properties->props[i], 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;
ret.addProperty(std::move(prop), properties->prop_values[i]);
}
}
return true;
return ret;
}
uint32_t DrmObject::id() const
@ -96,6 +77,25 @@ QString DrmObject::typeName() const
return QStringLiteral("unknown?");
}
}
void DrmPropertyList::addProperty(DrmUniquePtr<drmModePropertyRes> &&prop, uint64_t value)
{
m_properties.push_back(std::make_pair(std::move(prop), value));
}
std::optional<std::pair<DrmUniquePtr<drmModePropertyRes>, uint64_t>> DrmPropertyList::takeProperty(const QByteArray &name)
{
const auto it = std::find_if(m_properties.begin(), m_properties.end(), [&name](const auto &pair) {
return pair.first->name == name;
});
if (it != m_properties.end()) {
auto ret = std::move(*it);
m_properties.erase(it);
return ret;
} else {
return std::nullopt;
}
}
}
QDebug operator<<(QDebug s, const KWin::DrmObject *obj)

@ -28,6 +28,16 @@ class DrmGpu;
class DrmOutput;
class DrmAtomicCommit;
class DrmPropertyList
{
public:
void addProperty(DrmUniquePtr<drmModePropertyRes> &&prop, uint64_t value);
std::optional<std::pair<DrmUniquePtr<drmModePropertyRes>, uint64_t>> takeProperty(const QByteArray &name);
private:
std::vector<std::pair<DrmUniquePtr<drmModePropertyRes>, uint64_t>> m_properties;
};
class DrmObject
{
public:
@ -38,54 +48,29 @@ public:
* Must be called to query necessary data directly after creation.
* @return true when initializing was successful
*/
virtual bool init() = 0;
bool init();
/**
* Set the properties in such a way that this resource won't be used anymore
*/
virtual void disable(DrmAtomicCommit *commit) = 0;
virtual bool updateProperties() = 0;
uint32_t id() const;
DrmGpu *gpu() const;
uint32_t type() const;
QString typeName() const;
virtual bool updateProperties();
template<typename T>
DrmProperty *getProp(T propIndex) const
{
return m_props[static_cast<uint32_t>(propIndex)].get();
}
protected:
enum class Requirement {
Required,
RequiredForLegacy,
Optional,
};
struct PropertyDefinition
{
PropertyDefinition(const QByteArray &name, Requirement requirement, const QVector<QByteArray> &&enumNames = {})
: name(name)
, requirement(requirement)
, enumNames(enumNames)
{
}
QByteArray name;
Requirement requirement;
QVector<QByteArray> enumNames;
};
DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector<PropertyDefinition> &&vector, uint32_t objectType);
std::vector<std::unique_ptr<DrmProperty>> m_props;
DrmObject(DrmGpu *gpu, uint32_t objectId, uint32_t objectType);
DrmPropertyList queryProperties() const;
private:
DrmGpu *m_gpu;
const uint32_t m_id;
const uint32_t m_objectType;
const QVector<PropertyDefinition> m_propertyDefinitions;
};
}

@ -55,17 +55,17 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
Capabilities capabilities = Capability::Dpms;
State initialState;
if (conn->hasOverscan()) {
if (conn->overscan.isValid() || conn->underscan.isValid()) {
capabilities |= Capability::Overscan;
initialState.overscan = conn->overscan();
initialState.overscan = conn->overscan.isValid() ? conn->overscan.value() : conn->underscanVBorder.value();
}
if (conn->vrrCapable()) {
if (conn->vrrCapable.isValid() && conn->vrrCapable.value()) {
capabilities |= Capability::Vrr;
setVrrPolicy(RenderLoop::VrrPolicy::Automatic);
}
if (conn->hasRgbRange()) {
if (conn->broadcastRGB.isValid()) {
capabilities |= Capability::RgbRange;
initialState.rgbRange = conn->rgbRange();
initialState.rgbRange = DrmConnector::broadcastRgbToRgbRange(conn->broadcastRGB.enumValue());
}
const Edid *edid = conn->edid();
@ -80,7 +80,7 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
.edid = *edid,
.subPixel = conn->subpixel(),
.capabilities = capabilities,
.panelOrientation = DrmConnector::toKWinTransform(conn->panelOrientation()),
.panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : Transform::Normal,
.internal = conn->isInternal(),
.nonDesktop = conn->isNonDesktop(),
});

@ -186,31 +186,31 @@ static QRect centerBuffer(const QSize &bufferSize, const QSize &modeSize)
bool DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commit)
{
if (const auto contentType = m_connector->getProp(DrmConnector::PropertyIndex::ContentType)) {
commit->addEnum(contentType, m_pending.contentType);
if (m_connector->contentType.isValid()) {
commit->addEnum(m_connector->contentType, m_pending.contentType);
}
commit->addProperty(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::VrrEnabled), m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync);
if (const auto gamma = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::Gamma_LUT)) {
commit->addBlob(gamma, m_pending.gamma ? m_pending.gamma->blob() : nullptr);
commit->addProperty(m_pending.crtc->vrrEnabled, m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync);
if (m_pending.crtc->gammaLut.isValid()) {
commit->addBlob(m_pending.crtc->gammaLut, m_pending.gamma ? m_pending.gamma->blob() : nullptr);
} else if (m_pending.gamma) {
return false;
}
if (const auto ctm = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::CTM)) {
commit->addBlob(ctm, m_pending.ctm);
if (m_pending.crtc->ctm.isValid()) {
commit->addBlob(m_pending.crtc->ctm, m_pending.ctm);
} else if (m_pending.ctm) {
return false;
}
const auto fb = m_pending.layer->currentBuffer().get();
m_pending.crtc->primaryPlane()->set(commit, QPoint(0, 0), fb->buffer()->size(), centerBuffer(fb->buffer()->size(), m_pending.mode->size()));
commit->addProperty(m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::FbId), fb->framebufferId());
commit->addProperty(m_pending.crtc->primaryPlane()->fbId, fb->framebufferId());
if (auto plane = m_pending.crtc->cursorPlane()) {
const auto layer = cursorLayer();
plane->set(commit, QPoint(0, 0), gpu()->cursorSize(), QRect(layer->position(), gpu()->cursorSize()));
commit->addProperty(plane->getProp(DrmPlane::PropertyIndex::CrtcId), layer->isVisible() ? m_pending.crtc->id() : 0);
commit->addProperty(plane->getProp(DrmPlane::PropertyIndex::FbId), layer->isVisible() ? layer->currentBuffer()->framebufferId() : 0);
commit->addProperty(plane->crtcId, layer->isVisible() ? m_pending.crtc->id() : 0);
commit->addProperty(plane->fbId, layer->isVisible() ? layer->currentBuffer()->framebufferId() : 0);
}
return true;
}
@ -229,45 +229,45 @@ void DrmPipeline::prepareAtomicDisable(DrmAtomicCommit *commit)
void DrmPipeline::prepareAtomicModeset(DrmAtomicCommit *commit)
{
commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::CrtcId), m_pending.crtc->id());
if (const auto prop = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) {
commit->addEnum(prop, m_pending.rgbRange);
commit->addProperty(m_connector->crtcId, m_pending.crtc->id());
if (m_connector->broadcastRGB.isValid()) {
commit->addEnum(m_connector->broadcastRGB, DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange));
}
if (const auto prop = m_connector->getProp(DrmConnector::PropertyIndex::LinkStatus)) {
commit->addEnum(prop, DrmConnector::LinkStatus::Good);
if (m_connector->linkStatus.isValid()) {
commit->addEnum(m_connector->linkStatus, DrmConnector::LinkStatus::Good);
}
if (const auto overscan = m_connector->getProp(DrmConnector::PropertyIndex::Overscan)) {
commit->addProperty(overscan, m_pending.overscan);
} else if (const auto underscan = m_connector->getProp(DrmConnector::PropertyIndex::Underscan)) {
if (m_connector->overscan.isValid()) {
commit->addProperty(m_connector->overscan, m_pending.overscan);
} else if (m_connector->underscan.isValid()) {
const uint32_t hborder = calculateUnderscan();
commit->addEnum(underscan, m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off);
commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::Underscan_vborder), m_pending.overscan);
commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::Underscan_hborder), hborder);
commit->addEnum(m_connector->underscan, m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off);
commit->addProperty(m_connector->underscanVBorder, m_pending.overscan);
commit->addProperty(m_connector->underscanHBorder, hborder);
}
if (const auto bpc = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc)) {
if (m_connector->maxBpc.isValid()) {
uint64_t preferred = 8;
if (auto backend = dynamic_cast<EglGbmBackend *>(gpu()->platform()->renderBackend()); backend && backend->prefer10bpc()) {
preferred = 10;
}
commit->addProperty(bpc, preferred);
commit->addProperty(m_connector->maxBpc, preferred);
}
if (const auto hdr = m_connector->getProp(DrmConnector::PropertyIndex::HdrMetadata)) {
commit->addProperty(hdr, 0);
if (m_connector->hdrMetadata.isValid()) {
commit->addProperty(m_connector->hdrMetadata, 0);
}
if (const auto scaling = m_connector->getProp(DrmConnector::PropertyIndex::ScalingMode); scaling && scaling->hasEnum(DrmConnector::ScalingMode::None)) {
commit->addEnum(scaling, DrmConnector::ScalingMode::None);
if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) {
commit->addEnum(m_connector->scalingMode, DrmConnector::ScalingMode::None);
}
commit->addProperty(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::Active), 1);
commit->addBlob(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::ModeId), m_pending.mode->blob());
commit->addProperty(m_pending.crtc->active, 1);
commit->addBlob(m_pending.crtc->modeId, m_pending.mode->blob());
commit->addProperty(m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::CrtcId), m_pending.crtc->id());
if (const auto rotation = m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::Rotation)) {
commit->addEnum(rotation, DrmPlane::Transformation::Rotate0);
commit->addProperty(m_pending.crtc->primaryPlane()->crtcId, m_pending.crtc->id());
if (const auto &rotation = m_pending.crtc->primaryPlane()->rotation; rotation.isValid()) {
commit->addEnum(rotation, {DrmPlane::Transformation::Rotate0});
}
if (m_pending.crtc->cursorPlane()) {
if (const auto rotation = m_pending.crtc->cursorPlane()->getProp(DrmPlane::PropertyIndex::Rotation)) {
commit->addEnum(rotation, DrmPlane::Transformation::Rotate0);
if (const auto &rotation = m_pending.crtc->cursorPlane()->rotation; rotation.isValid()) {
commit->addEnum(rotation, DrmPlane::Transformations(DrmPlane::Transformation::Rotate0));
}
}
}

@ -96,24 +96,24 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy()
drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0);
}
if (activePending()) {
auto vrr = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::VrrEnabled);
if (vrr && !vrr->setPropertyLegacy(m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync)) {
const bool shouldEnableVrr = m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync;
if (m_pending.crtc->vrrEnabled.isValid() && !m_pending.crtc->vrrEnabled.setPropertyLegacy(shouldEnableVrr)) {
qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno);
return errnoToError();
}
if (const auto &rgbRange = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) {
rgbRange->setEnumLegacy(m_pending.rgbRange);
if (m_connector->broadcastRGB.isValid()) {
m_connector->broadcastRGB.setEnumLegacy(DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange));
}
if (const auto overscan = m_connector->getProp(DrmConnector::PropertyIndex::Overscan)) {
overscan->setPropertyLegacy(m_pending.overscan);
} else if (const auto underscan = m_connector->getProp(DrmConnector::PropertyIndex::Underscan)) {
if (m_connector->overscan.isValid()) {
m_connector->overscan.setPropertyLegacy(m_pending.overscan);
} else if (m_connector->underscan.isValid()) {
const uint32_t hborder = calculateUnderscan();
underscan->setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off);
m_connector->getProp(DrmConnector::PropertyIndex::Underscan_vborder)->setPropertyLegacy(m_pending.overscan);
m_connector->getProp(DrmConnector::PropertyIndex::Underscan_hborder)->setPropertyLegacy(hborder);
m_connector->underscan.setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off);
m_connector->underscanVBorder.setPropertyLegacy(m_pending.overscan);
m_connector->underscanHBorder.setPropertyLegacy(hborder);
}
if (const auto scaling = m_connector->getProp(DrmConnector::PropertyIndex::ScalingMode); scaling && scaling->hasEnum(DrmConnector::ScalingMode::None)) {
scaling->setEnumLegacy(DrmConnector::ScalingMode::None);
if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) {
m_connector->scalingMode.setEnumLegacy(DrmConnector::ScalingMode::None);
}
if (m_pending.crtc != m_current.crtc || m_pending.mode != m_current.mode) {
Error err = legacyModeset();
@ -125,13 +125,13 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy()
qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno);
return errnoToError();
}
if (const auto contentType = m_connector->getProp(DrmConnector::PropertyIndex::ContentType)) {
contentType->setEnumLegacy(m_pending.contentType);
if (m_connector->contentType.isValid()) {
m_connector->contentType.setEnumLegacy(m_pending.contentType);
}
setCursorLegacy();
moveCursorLegacy();
}
if (!m_connector->getProp(DrmConnector::PropertyIndex::Dpms)->setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) {
if (!m_connector->dpms.setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) {
qCWarning(KWIN_DRM) << "Setting legacy dpms failed!" << strerror(errno);
return errnoToError();
}

@ -23,59 +23,67 @@ namespace KWin
{
DrmPlane::DrmPlane(DrmGpu *gpu, uint32_t planeId)
: DrmObject(gpu, planeId, {
PropertyDefinition(QByteArrayLiteral("type"), Requirement::Required, {QByteArrayLiteral("Overlay"), QByteArrayLiteral("Primary"), QByteArrayLiteral("Cursor")}),
PropertyDefinition(QByteArrayLiteral("SRC_X"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("SRC_Y"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("SRC_W"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("SRC_H"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("CRTC_X"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("CRTC_Y"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("CRTC_W"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("CRTC_H"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("FB_ID"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
PropertyDefinition(QByteArrayLiteral("rotation"), Requirement::Optional, {QByteArrayLiteral("rotate-0"), QByteArrayLiteral("rotate-90"), QByteArrayLiteral("rotate-180"), QByteArrayLiteral("rotate-270"), QByteArrayLiteral("reflect-x"), QByteArrayLiteral("reflect-y")}),
PropertyDefinition(QByteArrayLiteral("IN_FORMATS"), Requirement::Optional),
},
DRM_MODE_OBJECT_PLANE)
{
}
bool DrmPlane::init()
: DrmObject(gpu, planeId, DRM_MODE_OBJECT_PLANE)
, type(this, QByteArrayLiteral("type"), {
QByteArrayLiteral("Overlay"),
QByteArrayLiteral("Primary"),
QByteArrayLiteral("Cursor"),
})
, srcX(this, QByteArrayLiteral("SRC_X"))
, srcY(this, QByteArrayLiteral("SRC_Y"))
, srcW(this, QByteArrayLiteral("SRC_W"))
, srcH(this, QByteArrayLiteral("SRC_H"))
, crtcX(this, QByteArrayLiteral("CRTC_X"))
, crtcY(this, QByteArrayLiteral("CRTC_Y"))
, crtcW(this, QByteArrayLiteral("CRTC_W"))
, crtcH(this, QByteArrayLiteral("CRTC_H"))
, fbId(this, QByteArrayLiteral("FB_ID"))
, crtcId(this, QByteArrayLiteral("CRTC_ID"))
, rotation(this, QByteArrayLiteral("rotation"), {
QByteArrayLiteral("rotate-0"),
QByteArrayLiteral("rotate-90"),
QByteArrayLiteral("rotate-180"),
QByteArrayLiteral("rotate-270"),
QByteArrayLiteral("reflect-x"),
QByteArrayLiteral("reflect-y"),
})
, inFormats(this, QByteArrayLiteral("IN_FORMATS"))
{
}
bool DrmPlane::updateProperties()
{
DrmUniquePtr<drmModePlane> p(drmModeGetPlane(gpu()->fd(), id()));
if (!p) {
qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id();
return false;
}
DrmPropertyList props = queryProperties();
type.update(props);
srcX.update(props);
srcY.update(props);
srcW.update(props);
srcH.update(props);
crtcX.update(props);
crtcY.update(props);
crtcW.update(props);
crtcH.update(props);
fbId.update(props);
crtcId.update(props);
rotation.update(props);
inFormats.update(props);
if (!type.isValid() || !srcX.isValid() || !srcY.isValid() || !srcW.isValid() || !srcH.isValid()
|| !crtcX.isValid() || !crtcY.isValid() || !crtcW.isValid() || !crtcH.isValid() || !fbId.isValid()) {
return false;
}
m_possibleCrtcs = p->possible_crtcs;
bool success = updateProperties();
if (success) {
if (const auto prop = getProp(PropertyIndex::Rotation)) {
m_supportedTransformations = Transformations();
auto checkSupport = [this, prop](Transformation t) {
if (prop->hasEnum(t)) {
m_supportedTransformations |= t;
}
};
checkSupport(Transformation::Rotate0);
checkSupport(Transformation::Rotate90);
checkSupport(Transformation::Rotate180);
checkSupport(Transformation::Rotate270);
checkSupport(Transformation::ReflectX);
checkSupport(Transformation::ReflectY);
} else {
m_supportedTransformations = Transformation::Rotate0;
}
// read formats from blob if available and if modifiers are supported, and from the plane object if not
if (const auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && formatProp->immutableBlob() && gpu()->addFB2ModifiersSupported()) {
if (inFormats.isValid() && inFormats.immutableBlob() && gpu()->addFB2ModifiersSupported()) {
drmModeFormatModifierIterator iterator{};
while (drmModeFormatModifierBlobIterNext(formatProp->immutableBlob(), &iterator)) {
while (drmModeFormatModifierBlobIterNext(inFormats.immutableBlob(), &iterator)) {
m_supportedFormats[iterator.fmt].push_back(iterator.mod);
}
} else {
@ -87,14 +95,7 @@ bool DrmPlane::init()
qCWarning(KWIN_DRM) << "Driver doesn't advertise any formats for this plane. Falling back to XRGB8888 without explicit modifiers";
m_supportedFormats.insert(DRM_FORMAT_XRGB8888, {});
}
}
return success;
}
DrmPlane::TypeIndex DrmPlane::type() const
{
const auto &prop = getProp(PropertyIndex::Type);
return prop->enumForValue<DrmPlane::TypeIndex>(prop->current());
return true;
}
void DrmPlane::setNext(const std::shared_ptr<DrmFramebuffer> &b)
@ -111,15 +112,15 @@ void DrmPlane::flipBuffer()
void DrmPlane::set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst)
{
// Src* are in 16.16 fixed point format
commit->addProperty(getProp(PropertyIndex::SrcX), srcPos.x() << 16);
commit->addProperty(getProp(PropertyIndex::SrcX), srcPos.x() << 16);
commit->addProperty(getProp(PropertyIndex::SrcY), srcPos.y() << 16);
commit->addProperty(getProp(PropertyIndex::SrcW), srcSize.width() << 16);
commit->addProperty(getProp(PropertyIndex::SrcH), srcSize.height() << 16);
commit->addProperty(getProp(PropertyIndex::CrtcX), dst.x());
commit->addProperty(getProp(PropertyIndex::CrtcY), dst.y());
commit->addProperty(getProp(PropertyIndex::CrtcW), dst.width());
commit->addProperty(getProp(PropertyIndex::CrtcH), dst.height());
commit->addProperty(srcX, srcPos.x() << 16);
commit->addProperty(srcX, srcPos.x() << 16);
commit->addProperty(srcY, srcPos.y() << 16);
commit->addProperty(srcW, srcSize.width() << 16);
commit->addProperty(srcH, srcSize.height() << 16);
commit->addProperty(crtcX, dst.x());
commit->addProperty(crtcY, dst.y());
commit->addProperty(crtcW, dst.width());
commit->addProperty(crtcH, dst.height());
}
bool DrmPlane::isCrtcSupported(int pipeIndex) const
@ -147,15 +148,10 @@ void DrmPlane::setCurrent(const std::shared_ptr<DrmFramebuffer> &b)
m_current = b;
}
DrmPlane::Transformations DrmPlane::supportedTransformations() const
{
return m_supportedTransformations;
}
void DrmPlane::disable(DrmAtomicCommit *commit)
{
commit->addProperty(getProp(PropertyIndex::CrtcId), 0);
commit->addProperty(getProp(PropertyIndex::FbId), 0);
commit->addProperty(crtcId, 0);
commit->addProperty(fbId, 0);
m_next = nullptr;
}

@ -29,46 +29,8 @@ class DrmPlane : public DrmObject
public:
DrmPlane(DrmGpu *gpu, uint32_t planeId);
enum class PropertyIndex : uint32_t {
Type = 0,
SrcX,
SrcY,
SrcW,
SrcH,
CrtcX,
CrtcY,
CrtcW,
CrtcH,
FbId,
CrtcId,
Rotation,
In_Formats,
Count
};
Q_ENUM(PropertyIndex)
enum class TypeIndex : uint32_t {
Overlay = 0,
Primary,
Cursor,
Count
};
Q_ENUM(TypeIndex)
enum class Transformation : uint32_t {
Rotate0 = 1 << 0,
Rotate90 = 1 << 1,
Rotate180 = 1 << 2,
Rotate270 = 1 << 3,
ReflectX = 1 << 4,
ReflectY = 1 << 5
};
Q_ENUM(Transformation)
Q_DECLARE_FLAGS(Transformations, Transformation)
bool init() override;
bool updateProperties() override;
void disable(DrmAtomicCommit *commit) override;
TypeIndex type() const;
bool isCrtcSupported(int pipeIndex) const;
QMap<uint32_t, QVector<uint64_t>> formats() const;
@ -81,11 +43,39 @@ public:
void set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst);
Transformations supportedTransformations() const;
void releaseBuffers();
static int32_t transformationToDegrees(DrmPlane::Transformations transformation);
enum class TypeIndex : uint64_t {
Overlay = 0,
Primary = 1,
Cursor = 2
};
enum class Transformation : uint32_t {
Rotate0 = 1 << 0,
Rotate90 = 1 << 1,
Rotate180 = 1 << 2,
Rotate270 = 1 << 3,
ReflectX = 1 << 4,
ReflectY = 1 << 5
};
Q_ENUM(Transformation)
Q_DECLARE_FLAGS(Transformations, Transformation)
DrmEnumProperty<TypeIndex> type;
DrmProperty srcX;
DrmProperty srcY;
DrmProperty srcW;
DrmProperty srcH;
DrmProperty crtcX;
DrmProperty crtcY;
DrmProperty crtcW;
DrmProperty crtcH;
DrmProperty fbId;
DrmProperty crtcId;
DrmEnumProperty<Transformations> rotation;
DrmProperty inFormats;
static int32_t transformationToDegrees(Transformations transformation);
private:
std::shared_ptr<DrmFramebuffer> m_current;
@ -93,7 +83,6 @@ private:
QMap<uint32_t, QVector<uint64_t>> m_supportedFormats;
uint32_t m_possibleCrtcs;
Transformations m_supportedTransformations = Transformation::Rotate0;
};
}

@ -17,25 +17,11 @@
namespace KWin
{
DrmProperty::DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames)
: m_propId(prop->prop_id)
, m_propName(prop->name)
, m_current(val)
, m_immutable(prop->flags & DRM_MODE_PROP_IMMUTABLE)
, m_isBlob(prop->flags & DRM_MODE_PROP_BLOB)
, m_isBitmask(prop->flags & DRM_MODE_PROP_BITMASK)
, m_obj(obj)
DrmProperty::DrmProperty(DrmObject *obj, const QByteArray &name, const QVector<QByteArray> &enumNames)
: m_obj(obj)
, m_propName(name)
, m_enumNames(enumNames)
{
if (!enumNames.isEmpty()) {
m_enumNames = enumNames;
initEnumMap(prop);
}
if (prop->flags & DRM_MODE_PROP_RANGE) {
Q_ASSERT(prop->count_values > 1);
m_minValue = prop->values[0];
m_maxValue = prop->values[1];
}
updateBlob();
}
bool DrmProperty::setPropertyLegacy(uint64_t value)
@ -50,8 +36,24 @@ bool DrmProperty::setPropertyLegacy(uint64_t value)
}
}
void DrmProperty::initEnumMap(drmModePropertyRes *prop)
void DrmProperty::update(DrmPropertyList &propertyList)
{
if (const auto opt = propertyList.takeProperty(m_propName)) {
const auto &[prop, value] = *opt;
m_propId = prop->prop_id;
m_current = value;
m_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE;
m_isBlob = prop->flags & DRM_MODE_PROP_BLOB;
m_isBitmask = prop->flags & DRM_MODE_PROP_BITMASK;
if (prop->flags & DRM_MODE_PROP_RANGE) {
Q_ASSERT(prop->count_values > 1);
m_minValue = prop->values[0];
m_maxValue = prop->values[1];
}
m_enumToPropertyMap.clear();
m_propertyToEnumMap.clear();
// bitmasks need translation too, not just enums
if (prop->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
for (int i = 0; i < prop->count_enums; i++) {
struct drm_mode_property_enum *en = &prop->enums[i];
int j = m_enumNames.indexOf(QByteArray(en->name));
@ -67,15 +69,26 @@ void DrmProperty::initEnumMap(drmModePropertyRes *prop)
qCWarning(KWIN_DRM, "%s has unrecognized enum '%s'", qPrintable(m_propName), en->name);
}
}
}
if (m_immutable && m_isBlob) {
if (m_current != 0) {
m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current));
if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) {
m_immutableBlob.reset();
}
} else {
m_immutableBlob.reset();
}
}
} else {
m_propId = 0;
m_immutableBlob.reset();
m_enumToPropertyMap.clear();
m_propertyToEnumMap.clear();
}
}
void DrmProperty::setCurrent(uint64_t value)
{
m_current = value;
updateBlob();
}
uint64_t DrmProperty::current() const
uint64_t DrmProperty::value() const
{
return m_current;
}
@ -105,16 +118,6 @@ bool DrmProperty::isBitmask() const
return m_isBitmask;
}
bool DrmProperty::isLegacy() const
{
return m_legacy;
}
void DrmProperty::setLegacy()
{
m_legacy = true;
}
uint64_t DrmProperty::minValue() const
{
return m_minValue;
@ -125,27 +128,18 @@ uint64_t DrmProperty::maxValue() const
return m_maxValue;
}
void DrmProperty::updateBlob()
{
if (m_immutable && m_isBlob) {
if (m_current != 0) {
m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current));
if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) {
m_immutableBlob.reset();
}
} else {
m_immutableBlob.reset();
}
}
}
drmModePropertyBlobRes *DrmProperty::immutableBlob() const
{
return m_immutableBlob.get();
}
const DrmObject *DrmProperty::drmObject() const
DrmObject *DrmProperty::drmObject() const
{
return m_obj;
}
bool DrmProperty::isValid() const
{
return m_propId != 0;
}
}

@ -22,21 +22,79 @@ namespace KWin
{
class DrmObject;
class DrmPropertyList;
class DrmProperty
{
public:
DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val, const QVector<QByteArray> &enumNames);
DrmProperty(DrmObject *obj, const QByteArray &name, const QVector<QByteArray> &enumNames = {});
const QByteArray &name() const;
DrmObject *drmObject() const;
uint32_t propId() const;
bool isImmutable() const;
bool isBitmask() const;
bool hasAllEnums() const;
uint64_t value() const;
drmModePropertyBlobRes *immutableBlob() const;
uint64_t minValue() const;
uint64_t maxValue() const;
bool isValid() const;
void update(DrmPropertyList &propertyList);
bool setPropertyLegacy(uint64_t value);
protected:
DrmObject *const m_obj;
const QByteArray m_propName;
const QVector<QByteArray> m_enumNames;
uint32_t m_propId = 0;
// the last known value from the kernel
uint64_t m_current = 0;
DrmUniquePtr<drmModePropertyBlobRes> m_immutableBlob;
uint64_t m_minValue = -1;
uint64_t m_maxValue = -1;
QMap<uint64_t, uint64_t> m_enumToPropertyMap;
QMap<uint64_t, uint64_t> m_propertyToEnumMap;
bool m_immutable = false;
bool m_isBlob = false;
bool m_isBitmask = false;
};
template<typename Enum>
class DrmEnumProperty : public DrmProperty
{
public:
DrmEnumProperty(DrmObject *obj, const QByteArray &name, const QVector<QByteArray> &enumNames)
: DrmProperty(obj, name, enumNames)
{
}
Enum enumValue() const
{
return enumForValue(value());
}
template<typename Enum>
bool hasEnum(Enum value) const
{
return m_enumToPropertyMap.contains(static_cast<uint64_t>(value));
const uint64_t integerValue = static_cast<uint64_t>(value);
if (m_isBitmask) {
for (uint64_t mask = 1; integerValue >= mask && mask != 0; mask <<= 1) {
if ((integerValue & mask) && !m_enumToPropertyMap.contains(mask)) {
return false;
}
}
template<typename T>
T enumForValue(uint64_t value) const
return true;
} else {
return m_enumToPropertyMap.contains(integerValue);
}
}
Enum enumForValue(uint64_t value) const
{
if (m_isBitmask) {
uint64_t ret = 0;
@ -45,12 +103,13 @@ public:
ret |= m_propertyToEnumMap[mask];
}
}
return static_cast<T>(ret);
return static_cast<Enum>(ret);
} else {
return static_cast<T>(m_propertyToEnumMap[value]);
return static_cast<Enum>(m_propertyToEnumMap[value]);
}
}
uint64_t valueForEnum(auto enumValue)
uint64_t valueForEnum(Enum enumValue) const
{
const uint64_t integer = static_cast<uint64_t>(enumValue);
if (m_isBitmask) {
@ -66,57 +125,13 @@ public:
}
}
uint32_t propId() const;
const QByteArray &name() const;
bool isImmutable() const;
bool isBitmask() const;
bool isLegacy() const;
/**
* Makes this property be ignored by DrmObject::atomicPopulate
*/
void setLegacy();
void setCurrent(uint64_t value);
uint64_t current() const;
drmModePropertyBlobRes *immutableBlob() const;
uint64_t minValue() const;
uint64_t maxValue() const;
bool setPropertyLegacy(uint64_t value);
template<typename T>
bool setEnumLegacy(T value)
bool setEnumLegacy(Enum value)
{
if (hasEnum(static_cast<uint64_t>(value))) {
return setPropertyLegacy(m_enumToPropertyMap[static_cast<uint32_t>(value)]);
}
if (hasEnum(value)) {
return setPropertyLegacy(valueForEnum(value));
} else {
return false;
}
const DrmObject *drmObject() const;
private:
void initEnumMap(drmModePropertyRes *prop);
void updateBlob();
uint32_t m_propId = 0;
QByteArray m_propName;
// the last known value from the kernel
uint64_t m_current = 0;
DrmUniquePtr<drmModePropertyBlobRes> m_immutableBlob;
uint64_t m_minValue = -1;
uint64_t m_maxValue = -1;
QMap<uint64_t, uint64_t> m_enumToPropertyMap;
QMap<uint64_t, uint64_t> m_propertyToEnumMap;
QVector<QByteArray> m_enumNames;
const bool m_immutable;
const bool m_isBlob;
const bool m_isBitmask;
bool m_legacy = false;
const DrmObject *m_obj;
}
};
}

Loading…
Cancel
Save