platforms/drm: disable unused resources on modesets
When we switch CRTCs it can happen that a CRTC would stay enabled yet has no connectors anymore. In this case the kernel may reject our atomic commit, which would cause the modeset to fail. To counteract that, properly disable unused drm objects
This commit is contained in:
parent
102fb3d5f2
commit
7283c98f27
11 changed files with 101 additions and 14 deletions
|
@ -177,6 +177,7 @@ void DrmGpu::initDrmResources()
|
|||
DrmPlane *p = new DrmPlane(this, kplane->plane_id);
|
||||
if (p->init()) {
|
||||
m_planes << p;
|
||||
m_allObjects << p;
|
||||
} else {
|
||||
delete p;
|
||||
}
|
||||
|
@ -199,13 +200,19 @@ void DrmGpu::initDrmResources()
|
|||
}
|
||||
auto planes = m_planes;
|
||||
for (int i = 0; i < resources->count_crtcs; ++i) {
|
||||
uint32_t crtcId = resources->crtcs[i];
|
||||
DrmPlane *primary = nullptr;
|
||||
DrmPlane *cursor = nullptr;
|
||||
for (const auto &plane : qAsConst(planes)) {
|
||||
if (plane->type() == DrmPlane::TypeIndex::Primary
|
||||
&& plane->isCrtcSupported(i)) {
|
||||
primary = plane;
|
||||
if (plane->getProp(DrmPlane::PropertyIndex::CrtcId)->current() == resources->crtcs[i]) {
|
||||
break;
|
||||
if (plane->isCrtcSupported(i)) {
|
||||
if (plane->type() == DrmPlane::TypeIndex::Primary) {
|
||||
if (!primary || primary->getProp(DrmPlane::PropertyIndex::CrtcId)->pending() == crtcId) {
|
||||
primary = plane;
|
||||
}
|
||||
} else if (plane->type() == DrmPlane::TypeIndex::Cursor) {
|
||||
if (!cursor || cursor->getProp(DrmPlane::PropertyIndex::CrtcId)->pending() == crtcId) {
|
||||
cursor = plane;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,12 +221,13 @@ void DrmGpu::initDrmResources()
|
|||
continue;
|
||||
}
|
||||
planes.removeOne(primary);
|
||||
auto c = new DrmCrtc(this, resources->crtcs[i], i, primary);
|
||||
auto c = new DrmCrtc(this, crtcId, i, primary, cursor);
|
||||
if (!c->init()) {
|
||||
delete c;
|
||||
continue;
|
||||
}
|
||||
m_crtcs << c;
|
||||
m_allObjects << c;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,6 +271,7 @@ bool DrmGpu::updateOutputs()
|
|||
continue;
|
||||
}
|
||||
m_connectors << conn;
|
||||
m_allObjects << conn;
|
||||
} else {
|
||||
removedConnectors.removeOne(conn);
|
||||
conn->updateProperties();
|
||||
|
@ -299,6 +308,7 @@ bool DrmGpu::updateOutputs()
|
|||
removeLeaseOutput(leaseOutput);
|
||||
}
|
||||
m_connectors.removeOne(connector);
|
||||
m_allObjects.removeOne(connector);
|
||||
delete connector;
|
||||
}
|
||||
|
||||
|
@ -348,13 +358,14 @@ bool DrmGpu::checkCrtcAssignment(QVector<DrmConnector*> connectors, QVector<DrmC
|
|||
leasePipelines << output->pipeline();
|
||||
}
|
||||
}
|
||||
bool test = DrmPipeline::commitPipelines(m_pipelines, DrmPipeline::CommitMode::Test);
|
||||
const auto unused = unusedObjects();
|
||||
bool test = DrmPipeline::commitPipelines(m_pipelines, DrmPipeline::CommitMode::Test, unused);
|
||||
if (!leasePipelines.isEmpty() && test) {
|
||||
// non-desktop outputs should be disabled for normal usage
|
||||
for (const auto &pipeline : qAsConst(leasePipelines)) {
|
||||
pipeline->pending.active = false;
|
||||
}
|
||||
bool ret = DrmPipeline::commitPipelines(m_pipelines, DrmPipeline::CommitMode::Test);
|
||||
bool ret = DrmPipeline::commitPipelines(m_pipelines, DrmPipeline::CommitMode::Test, unused);
|
||||
if (ret) {
|
||||
for (const auto &pipeline : qAsConst(leasePipelines)) {
|
||||
pipeline->applyPendingChanges();
|
||||
|
@ -728,6 +739,8 @@ bool DrmGpu::needsModeset() const
|
|||
{
|
||||
return std::any_of(m_pipelines.constBegin(), m_pipelines.constEnd(), [](const auto &pipeline) {
|
||||
return pipeline->needsModeset();
|
||||
}) || std::any_of(m_allObjects.constBegin(), m_allObjects.constEnd(), [](const auto &object) {
|
||||
return object->needsModeset();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -743,11 +756,28 @@ bool DrmGpu::maybeModeset()
|
|||
return pipeline->modesetPresentPending() || !pipeline->pending.active;
|
||||
});
|
||||
if (presentPendingForAll) {
|
||||
return DrmPipeline::commitPipelines(pipelines, DrmPipeline::CommitMode::CommitModeset);
|
||||
return DrmPipeline::commitPipelines(pipelines, DrmPipeline::CommitMode::CommitModeset, unusedObjects());
|
||||
} else {
|
||||
// commit only once all pipelines are ready for presentation
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<DrmObject*> DrmGpu::unusedObjects() const
|
||||
{
|
||||
if (!m_atomicModeSetting) {
|
||||
return {};
|
||||
}
|
||||
QVector<DrmObject*> ret = m_allObjects;
|
||||
for (const auto &pipeline : m_pipelines) {
|
||||
ret.removeOne(pipeline->connector());
|
||||
if (pipeline->pending.crtc) {
|
||||
ret.removeOne(pipeline->pending.crtc);
|
||||
ret.removeOne(pipeline->pending.crtc->primaryPlane());
|
||||
ret.removeOne(pipeline->pending.crtc->cursorPlane());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,6 +101,7 @@ private:
|
|||
void initDrmResources();
|
||||
|
||||
bool checkCrtcAssignment(QVector<DrmConnector*> connectors, QVector<DrmCrtc*> crtcs);
|
||||
QVector<DrmObject*> unusedObjects() const;
|
||||
|
||||
void handleLeaseRequest(KWaylandServer::DrmLeaseV1Interface *leaseRequest);
|
||||
void handleLeaseRevoked(KWaylandServer::DrmLeaseV1Interface *lease);
|
||||
|
@ -123,6 +124,7 @@ private:
|
|||
QVector<DrmPlane*> m_planes;
|
||||
QVector<DrmCrtc*> m_crtcs;
|
||||
QVector<DrmConnector*> m_connectors;
|
||||
QVector<DrmObject*> m_allObjects;
|
||||
QVector<DrmPipeline*> m_pipelines;
|
||||
|
||||
QVector<DrmOutput*> m_drmOutputs;
|
||||
|
|
|
@ -36,6 +36,11 @@ public:
|
|||
*/
|
||||
virtual bool init() = 0;
|
||||
|
||||
/**
|
||||
* Set the properties in such a way that this resource won't be used anymore
|
||||
*/
|
||||
virtual void disable() = 0;
|
||||
|
||||
uint32_t id() const;
|
||||
DrmGpu *gpu() const;
|
||||
uint32_t type() const;
|
||||
|
|
|
@ -369,6 +369,11 @@ DrmPipeline *DrmConnector::pipeline() const
|
|||
return m_pipeline.data();
|
||||
}
|
||||
|
||||
void DrmConnector::disable()
|
||||
{
|
||||
setPending(PropertyIndex::CrtcId, 0);
|
||||
}
|
||||
|
||||
QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj)
|
||||
{
|
||||
QDebugStateSaver saver(s);
|
||||
|
|
|
@ -53,6 +53,7 @@ public:
|
|||
bool init() override;
|
||||
bool needsModeset() const override;
|
||||
bool updateProperties() override;
|
||||
void disable() override;
|
||||
|
||||
QVector<uint32_t> encoders() const;
|
||||
bool isConnected() const;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane)
|
||||
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),
|
||||
|
@ -29,6 +29,7 @@ DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryP
|
|||
, m_crtc(drmModeGetCrtc(gpu->fd(), crtcId))
|
||||
, m_pipeIndex(pipeIndex)
|
||||
, m_primaryPlane(primaryPlane)
|
||||
, m_cursorPlane(cursorPlane)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -147,4 +148,15 @@ DrmPlane *DrmCrtc::primaryPlane() const
|
|||
return m_primaryPlane;
|
||||
}
|
||||
|
||||
DrmPlane *DrmCrtc::cursorPlane() const
|
||||
{
|
||||
return m_cursorPlane;
|
||||
}
|
||||
|
||||
void DrmCrtc::disable()
|
||||
{
|
||||
setPending(PropertyIndex::Active, 0);
|
||||
setPendingBlob(PropertyIndex::ModeId, nullptr, sizeof(drmModeModeInfo));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ class DrmPlane;
|
|||
class DrmCrtc : public DrmObject
|
||||
{
|
||||
public:
|
||||
DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane);
|
||||
DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane, DrmPlane *cursorPlane);
|
||||
|
||||
enum class PropertyIndex : uint32_t {
|
||||
ModeId = 0,
|
||||
|
@ -40,10 +40,12 @@ public:
|
|||
|
||||
bool init() override;
|
||||
bool needsModeset() const override;
|
||||
void disable() override;
|
||||
|
||||
int pipeIndex() const;
|
||||
int gammaRampSize() const;
|
||||
DrmPlane *primaryPlane() const;
|
||||
DrmPlane *cursorPlane() const;
|
||||
drmModeModeInfo queryCurrentMode();
|
||||
|
||||
QSharedPointer<DrmBuffer> current() const;
|
||||
|
@ -64,6 +66,8 @@ private:
|
|||
QSharedPointer<DrmBuffer> m_nextBuffer;
|
||||
int m_pipeIndex;
|
||||
DrmPlane *m_primaryPlane;
|
||||
// currently unused but needs to be filtered out for modesets
|
||||
DrmPlane *m_cursorPlane;
|
||||
|
||||
struct {
|
||||
QPoint pos;
|
||||
|
|
|
@ -208,4 +208,10 @@ DrmPlane::Transformations DrmPlane::supportedTransformations() const
|
|||
return m_supportedTransformations;
|
||||
}
|
||||
|
||||
void DrmPlane::disable()
|
||||
{
|
||||
setPending(PropertyIndex::CrtcId, 0);
|
||||
setPending(PropertyIndex::FbId, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ public:
|
|||
|
||||
bool init() override;
|
||||
bool needsModeset() const override;
|
||||
void disable() override;
|
||||
TypeIndex type();
|
||||
|
||||
bool isCrtcSupported(int pipeIndex) const;
|
||||
|
|
|
@ -111,7 +111,7 @@ bool DrmPipeline::present(const QSharedPointer<DrmBuffer> &buffer)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, CommitMode mode)
|
||||
bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, CommitMode mode, const QVector<DrmObject*> &unusedObjects)
|
||||
{
|
||||
Q_ASSERT(!pipelines.isEmpty());
|
||||
if (pipelines[0]->gpu()->atomicModeSetting()) {
|
||||
|
@ -121,7 +121,7 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
return false;
|
||||
}
|
||||
uint32_t flags = 0;
|
||||
const auto &failed = [pipelines, req, mode](){
|
||||
const auto &failed = [pipelines, req, mode, unusedObjects](){
|
||||
drmModeAtomicFree(req);
|
||||
for (const auto &pipeline : pipelines) {
|
||||
pipeline->printDebugInfo();
|
||||
|
@ -139,6 +139,9 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
pipeline->output()->presentFailed();
|
||||
}
|
||||
}
|
||||
for (const auto &obj : unusedObjects) {
|
||||
obj->rollbackPending();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
for (const auto &pipeline : pipelines) {
|
||||
|
@ -151,6 +154,16 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
return failed();
|
||||
}
|
||||
}
|
||||
for (const auto &unused : unusedObjects) {
|
||||
unused->disable();
|
||||
if (unused->needsModeset()) {
|
||||
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
}
|
||||
if (!unused->atomicPopulate(req)) {
|
||||
qCWarning(KWIN_DRM) << "Populating atomic values failed for unused resource" << unused;
|
||||
return failed();
|
||||
}
|
||||
}
|
||||
bool modeset = flags & DRM_MODE_ATOMIC_ALLOW_MODESET;
|
||||
Q_ASSERT(!modeset || mode != CommitMode::Commit);
|
||||
if (modeset) {
|
||||
|
@ -176,6 +189,7 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
if (pipeline->pending.crtc) {
|
||||
pipeline->pending.crtc->commitPending();
|
||||
pipeline->pending.crtc->primaryPlane()->commitPending();
|
||||
pipeline->pending.crtc->cursorPlane()->commitPending();
|
||||
}
|
||||
if (mode != CommitMode::Test) {
|
||||
pipeline->m_modesetPresentPending = false;
|
||||
|
@ -185,6 +199,7 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
pipeline->pending.crtc->primaryPlane()->setNext(pipeline->m_primaryBuffer);
|
||||
pipeline->pending.crtc->commit();
|
||||
pipeline->pending.crtc->primaryPlane()->commit();
|
||||
pipeline->pending.crtc->cursorPlane()->commit();
|
||||
}
|
||||
pipeline->m_current = pipeline->pending;
|
||||
if (modeset && pipeline->activePending()) {
|
||||
|
@ -192,6 +207,12 @@ bool DrmPipeline::commitPipelines(const QVector<DrmPipeline*> &pipelines, Commit
|
|||
}
|
||||
}
|
||||
}
|
||||
for (const auto &obj : unusedObjects) {
|
||||
obj->commitPending();
|
||||
if (mode != CommitMode::Test) {
|
||||
obj->commit();
|
||||
}
|
||||
}
|
||||
drmModeAtomicFree(req);
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -101,7 +101,7 @@ public:
|
|||
CommitModeset
|
||||
};
|
||||
Q_ENUM(CommitMode);
|
||||
static bool commitPipelines(const QVector<DrmPipeline*> &pipelines, CommitMode mode);
|
||||
static bool commitPipelines(const QVector<DrmPipeline*> &pipelines, CommitMode mode, const QVector<DrmObject*> &unusedObjects = {});
|
||||
|
||||
private:
|
||||
bool populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags);
|
||||
|
|
Loading…
Reference in a new issue