backends/drm: port away from mode indices
They're error prone and don't really work for changing modes. Having a current mode in DrmConnector also doesn't work well together with the transactional style of how DrmPipeline operates
This commit is contained in:
parent
03efdabf26
commit
e8eb55ad2e
6 changed files with 74 additions and 109 deletions
|
@ -23,6 +23,22 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
static bool checkIfEqual(const drmModeModeInfo *one, const drmModeModeInfo *two)
|
||||
{
|
||||
return one->clock == two->clock
|
||||
&& one->hdisplay == two->hdisplay
|
||||
&& one->hsync_start == two->hsync_start
|
||||
&& one->hsync_end == two->hsync_end
|
||||
&& one->htotal == two->htotal
|
||||
&& one->hskew == two->hskew
|
||||
&& one->vdisplay == two->vdisplay
|
||||
&& one->vsync_start == two->vsync_start
|
||||
&& one->vsync_end == two->vsync_end
|
||||
&& one->vtotal == two->vtotal
|
||||
&& one->vscan == two->vscan
|
||||
&& one->vrefresh == two->vrefresh;
|
||||
}
|
||||
|
||||
static quint64 refreshRateForMode(_drmModeModeInfo *m)
|
||||
{
|
||||
// Calculate higher precision (mHz) refresh rate
|
||||
|
@ -81,6 +97,11 @@ uint32_t DrmConnectorMode::blobId()
|
|||
return m_blobId;
|
||||
}
|
||||
|
||||
bool DrmConnectorMode::operator==(const DrmConnectorMode &otherMode)
|
||||
{
|
||||
return checkIfEqual(&m_nativeMode, &otherMode.m_nativeMode);
|
||||
}
|
||||
|
||||
DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
|
||||
: DrmObject(gpu, connectorId, {
|
||||
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
|
||||
|
@ -124,11 +145,6 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
|
|||
}
|
||||
}
|
||||
|
||||
DrmConnector::~DrmConnector()
|
||||
{
|
||||
qDeleteAll(m_modes);
|
||||
}
|
||||
|
||||
bool DrmConnector::init()
|
||||
{
|
||||
return m_conn && initProps();
|
||||
|
@ -197,51 +213,17 @@ QSize DrmConnector::physicalSize() const
|
|||
return m_physicalSize;
|
||||
}
|
||||
|
||||
DrmConnectorMode *DrmConnector::currentMode() const
|
||||
{
|
||||
return m_modes[m_modeIndex];
|
||||
}
|
||||
|
||||
int DrmConnector::currentModeIndex() const
|
||||
{
|
||||
return m_modeIndex;
|
||||
}
|
||||
|
||||
QVector<DrmConnectorMode *> DrmConnector::modes() const
|
||||
QVector<QSharedPointer<DrmConnectorMode>> DrmConnector::modes() const
|
||||
{
|
||||
return m_modes;
|
||||
}
|
||||
|
||||
void DrmConnector::setModeIndex(int index)
|
||||
QSharedPointer<DrmConnectorMode> DrmConnector::findMode(const drmModeModeInfo &modeInfo) const
|
||||
{
|
||||
m_modeIndex = index;
|
||||
}
|
||||
|
||||
static bool checkIfEqual(const drmModeModeInfo *one, const drmModeModeInfo *two)
|
||||
{
|
||||
return one->clock == two->clock
|
||||
&& one->hdisplay == two->hdisplay
|
||||
&& one->hsync_start == two->hsync_start
|
||||
&& one->hsync_end == two->hsync_end
|
||||
&& one->htotal == two->htotal
|
||||
&& one->hskew == two->hskew
|
||||
&& one->vdisplay == two->vdisplay
|
||||
&& one->vsync_start == two->vsync_start
|
||||
&& one->vsync_end == two->vsync_end
|
||||
&& one->vtotal == two->vtotal
|
||||
&& one->vscan == two->vscan
|
||||
&& one->vrefresh == two->vrefresh;
|
||||
}
|
||||
|
||||
void DrmConnector::findCurrentMode(drmModeModeInfo currentMode)
|
||||
{
|
||||
for (int i = 0; i < m_modes.count(); i++) {
|
||||
if (checkIfEqual(m_modes[i]->nativeMode(), ¤tMode)) {
|
||||
m_modeIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_modeIndex = 0;
|
||||
const auto it = std::find_if(m_modes.constBegin(), m_modes.constEnd(), [&modeInfo](const auto &mode) {
|
||||
return checkIfEqual(mode->nativeMode(), &modeInfo);
|
||||
});
|
||||
return it == m_modes.constEnd() ? nullptr : *it;
|
||||
}
|
||||
|
||||
AbstractWaylandOutput::SubPixel DrmConnector::subpixel() const
|
||||
|
@ -322,12 +304,11 @@ bool DrmConnector::needsModeset() const
|
|||
|
||||
void DrmConnector::updateModes()
|
||||
{
|
||||
qDeleteAll(m_modes);
|
||||
m_modes.clear();
|
||||
|
||||
// reload modes
|
||||
for (int i = 0; i < m_conn->count_modes; i++) {
|
||||
m_modes.append(new DrmConnectorMode(this, m_conn->modes[i]));
|
||||
m_modes.append(QSharedPointer<DrmConnectorMode>::create(this, m_conn->modes[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,6 +389,9 @@ bool DrmConnector::updateProperties()
|
|||
|
||||
// init modes
|
||||
updateModes();
|
||||
if (!m_modes.isEmpty() && !m_pipeline->pending.mode) {
|
||||
m_pipeline->pending.mode = m_modes.constFirst();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
QSize size() const;
|
||||
uint32_t refreshRate() const;
|
||||
|
||||
bool operator==(const DrmConnectorMode &otherMode);
|
||||
|
||||
private:
|
||||
DrmConnector *m_connector;
|
||||
drmModeModeInfo m_nativeMode;
|
||||
|
@ -53,7 +55,6 @@ class DrmConnector : public DrmObject
|
|||
{
|
||||
public:
|
||||
DrmConnector(DrmGpu *gpu, uint32_t connectorId);
|
||||
~DrmConnector() override;
|
||||
|
||||
enum class PropertyIndex : uint32_t {
|
||||
CrtcId = 0,
|
||||
|
@ -97,11 +98,8 @@ public:
|
|||
QString modelName() const;
|
||||
QSize physicalSize() const;
|
||||
|
||||
DrmConnectorMode *currentMode() const;
|
||||
int currentModeIndex() const;
|
||||
QVector<DrmConnectorMode *> modes() const;
|
||||
void setModeIndex(int index);
|
||||
void findCurrentMode(drmModeModeInfo currentMode);
|
||||
QVector<QSharedPointer<DrmConnectorMode>> modes() const;
|
||||
QSharedPointer<DrmConnectorMode> findMode(const drmModeModeInfo &modeInfo) const;
|
||||
void updateModes();
|
||||
|
||||
AbstractWaylandOutput::SubPixel subpixel() const;
|
||||
|
@ -118,8 +116,7 @@ private:
|
|||
DrmScopedPointer<drmModeConnector> m_conn;
|
||||
Edid m_edid;
|
||||
QSize m_physicalSize = QSize(-1, -1);
|
||||
QVector<DrmConnectorMode *> m_modes;
|
||||
int m_modeIndex = 0;
|
||||
QVector<QSharedPointer<DrmConnectorMode>> m_modes;
|
||||
uint32_t m_possibleCrtcs = 0;
|
||||
|
||||
friend QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj);
|
||||
|
|
|
@ -46,8 +46,8 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
|
|||
, m_connector(pipeline->connector())
|
||||
{
|
||||
m_pipeline->setOutput(this);
|
||||
auto conn = m_pipeline->connector();
|
||||
m_renderLoop->setRefreshRate(conn->currentMode()->refreshRate());
|
||||
const auto conn = m_pipeline->connector();
|
||||
m_renderLoop->setRefreshRate(m_pipeline->pending.mode->refreshRate());
|
||||
setSubPixelInternal(conn->subpixel());
|
||||
setInternal(conn->isInternal());
|
||||
setCapabilityInternal(DrmOutput::Capability::Dpms);
|
||||
|
@ -177,13 +177,13 @@ QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
|
|||
{
|
||||
bool modeFound = false;
|
||||
QVector<Mode> modes;
|
||||
auto conn = m_pipeline->connector();
|
||||
QVector<DrmConnectorMode *> modelist = conn->modes();
|
||||
const auto modelist = m_pipeline->connector()->modes();
|
||||
|
||||
modes.reserve(modelist.count());
|
||||
for (int i = 0; i < modelist.count(); ++i) {
|
||||
Mode mode;
|
||||
if (i == conn->currentModeIndex()) {
|
||||
// compare the actual mode objects, not the pointers!
|
||||
if (*modelist[i] == *m_pipeline->pending.mode) {
|
||||
mode.flags |= ModeFlag::Current;
|
||||
modeFound = true;
|
||||
}
|
||||
|
@ -298,34 +298,24 @@ DrmPlane::Transformations outputToPlaneTransform(DrmOutput::Transform transform)
|
|||
|
||||
void DrmOutput::updateModes()
|
||||
{
|
||||
auto conn = m_pipeline->connector();
|
||||
conn->updateModes();
|
||||
|
||||
const auto modes = getModes();
|
||||
setModes(modes);
|
||||
|
||||
auto it = std::find_if(modes.constBegin(), modes.constEnd(),
|
||||
[](const AbstractWaylandOutput::Mode &mode){
|
||||
return mode.flags.testFlag(ModeFlag::Current);
|
||||
}
|
||||
);
|
||||
Q_ASSERT(it != modes.constEnd());
|
||||
AbstractWaylandOutput::Mode mode = *it;
|
||||
|
||||
// mode changed
|
||||
if (mode.size != modeSize() || mode.refreshRate != refreshRate()) {
|
||||
m_pipeline->pending.modeIndex = mode.id;
|
||||
if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test)) {
|
||||
m_pipeline->connector()->updateModes();
|
||||
setModes(getModes());
|
||||
if (m_pipeline->pending.crtc) {
|
||||
const auto currentMode = m_pipeline->connector()->findMode(m_pipeline->pending.crtc->queryCurrentMode());
|
||||
if (currentMode != m_pipeline->pending.mode) {
|
||||
// DrmConnector::findCurrentMode might fail
|
||||
m_pipeline->pending.mode = currentMode ? currentMode : m_pipeline->connector()->modes().constFirst();
|
||||
if (DrmPipeline::commitPipelines(m_gpu->pipelines(), DrmPipeline::CommitMode::Test)) {
|
||||
m_pipeline->applyPendingChanges();
|
||||
auto mode = m_pipeline->connector()->currentMode();
|
||||
setCurrentModeInternal(mode->size(), mode->refreshRate());
|
||||
m_renderLoop->setRefreshRate(mode->refreshRate());
|
||||
setCurrentModeInternal(m_pipeline->pending.mode->size(), m_pipeline->pending.mode->refreshRate());
|
||||
m_renderLoop->setRefreshRate(m_pipeline->pending.mode->refreshRate());
|
||||
} else {
|
||||
qCWarning(KWIN_DRM) << "Setting changed mode failed!";
|
||||
m_pipeline->revertPendingChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DrmOutput::needsSoftwareTransformation() const
|
||||
{
|
||||
|
@ -409,21 +399,17 @@ bool DrmOutput::queueChanges(const WaylandOutputConfig &config)
|
|||
static bool valid;
|
||||
static int envOnlySoftwareRotations = qEnvironmentVariableIntValue("KWIN_DRM_SW_ROTATIONS_ONLY", &valid) == 1 || !valid;
|
||||
|
||||
auto props = config.constChangeSet(this);
|
||||
const auto props = config.constChangeSet(this);
|
||||
m_pipeline->pending.active = props->enabled;
|
||||
auto modelist = m_connector->modes();
|
||||
int index = -1;
|
||||
for (int i = 0; i < modelist.size(); i++) {
|
||||
if (modelist[i]->size() == props->modeSize && modelist[i]->refreshRate() == props->refreshRate) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) {
|
||||
const auto modelist = m_connector->modes();
|
||||
const auto it = std::find_if(modelist.begin(), modelist.end(), [&props](const auto &mode) {
|
||||
return mode->size() == props->modeSize && mode->refreshRate() == props->refreshRate;
|
||||
});
|
||||
if (it == modelist.end()) {
|
||||
qCWarning(KWIN_DRM).nospace() << "Could not find mode " << props->modeSize << "@" << props->refreshRate << " for output " << this;
|
||||
return false;
|
||||
}
|
||||
m_pipeline->pending.modeIndex = index;
|
||||
m_pipeline->pending.mode = *it;
|
||||
m_pipeline->pending.overscan = props->overscan;
|
||||
m_pipeline->pending.rgbRange = props->rgbRange;
|
||||
m_pipeline->pending.sourceTransformation = outputToPlaneTransform(props->transform);
|
||||
|
@ -448,8 +434,7 @@ void DrmOutput::applyQueuedChanges(const WaylandOutputConfig &config)
|
|||
setScale(props->scale);
|
||||
setTransformInternal(props->transform);
|
||||
|
||||
m_connector->setModeIndex(m_pipeline->pending.modeIndex);
|
||||
auto mode = m_connector->currentMode();
|
||||
const auto &mode = m_pipeline->pending.mode;
|
||||
setCurrentModeInternal(mode->size(), mode->refreshRate());
|
||||
m_renderLoop->setRefreshRate(mode->refreshRate());
|
||||
setOverscanInternal(m_pipeline->pending.overscan);
|
||||
|
|
|
@ -191,7 +191,7 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags)
|
|||
if (pending.crtc) {
|
||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::VrrEnabled, pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive);
|
||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::Gamma_LUT, pending.gamma ? pending.gamma->blobId() : 0);
|
||||
auto modeSize = m_connector->modes().at(pending.modeIndex)->size();
|
||||
const auto modeSize = pending.mode->size();
|
||||
pending.crtc->primaryPlane()->set(QPoint(0, 0), m_primaryBuffer ? m_primaryBuffer->size() : bufferSize(), QPoint(0, 0), modeSize);
|
||||
pending.crtc->primaryPlane()->setBuffer(activePending() ? m_primaryBuffer.get() : nullptr);
|
||||
|
||||
|
@ -224,7 +224,6 @@ void DrmPipeline::prepareAtomicModeset()
|
|||
m_connector->setPending(DrmConnector::PropertyIndex::CrtcId, 0);
|
||||
return;
|
||||
}
|
||||
auto mode = m_connector->modes().at(pending.modeIndex);
|
||||
|
||||
m_connector->setPending(DrmConnector::PropertyIndex::CrtcId, activePending() ? pending.crtc->id() : 0);
|
||||
if (const auto &prop = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) {
|
||||
|
@ -235,7 +234,7 @@ void DrmPipeline::prepareAtomicModeset()
|
|||
}
|
||||
|
||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::Active, activePending());
|
||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::ModeId, activePending() ? mode->blobId() : 0);
|
||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::ModeId, activePending() ? pending.mode->blobId() : 0);
|
||||
|
||||
pending.crtc->primaryPlane()->setPending(DrmPlane::PropertyIndex::CrtcId, activePending() ? pending.crtc->id() : 0);
|
||||
pending.crtc->primaryPlane()->setTransformation(pending.bufferTransformation);
|
||||
|
@ -400,7 +399,7 @@ void DrmPipeline::applyPendingChanges()
|
|||
|
||||
QSize DrmPipeline::bufferSize() const
|
||||
{
|
||||
const auto modeSize = m_connector->modes().at(pending.modeIndex)->size();
|
||||
const auto modeSize = pending.mode->size();
|
||||
if (pending.bufferTransformation & (DrmPlane::Transformation::Rotate90 | DrmPlane::Transformation::Rotate270)) {
|
||||
return modeSize.transposed();
|
||||
}
|
||||
|
@ -409,7 +408,7 @@ QSize DrmPipeline::bufferSize() const
|
|||
|
||||
QSize DrmPipeline::sourceSize() const
|
||||
{
|
||||
const auto modeSize = m_connector->modes().at(pending.modeIndex)->size();
|
||||
const auto modeSize = pending.mode->size();
|
||||
if (pending.sourceTransformation & (DrmPlane::Transformation::Rotate90 | DrmPlane::Transformation::Rotate270)) {
|
||||
return modeSize.transposed();
|
||||
}
|
||||
|
@ -418,7 +417,7 @@ QSize DrmPipeline::sourceSize() const
|
|||
|
||||
bool DrmPipeline::isCursorVisible() const
|
||||
{
|
||||
const QRect mode = QRect(QPoint(), m_connector->modes().at(pending.modeIndex)->size());
|
||||
const QRect mode = QRect(QPoint(), pending.mode->size());
|
||||
return pending.cursorBo && QRect(pending.cursorPos, pending.cursorBo->size()).intersects(mode);
|
||||
}
|
||||
|
||||
|
@ -500,7 +499,7 @@ bool DrmPipeline::needsModeset() const
|
|||
{
|
||||
return pending.crtc != m_current.crtc
|
||||
|| pending.active != m_current.active
|
||||
|| pending.modeIndex != m_current.modeIndex
|
||||
|| pending.mode != m_current.mode
|
||||
|| pending.rgbRange != m_current.rgbRange
|
||||
|| pending.bufferTransformation != m_current.bufferTransformation
|
||||
|| m_connector->linkStatus() == DrmConnector::LinkStatus::Bad
|
||||
|
@ -509,7 +508,7 @@ bool DrmPipeline::needsModeset() const
|
|||
|
||||
bool DrmPipeline::activePending() const
|
||||
{
|
||||
return pending.crtc && pending.active;
|
||||
return pending.crtc && pending.mode && pending.active;
|
||||
}
|
||||
|
||||
void DrmPipeline::revertPendingChanges()
|
||||
|
|
|
@ -30,6 +30,7 @@ class DrmCrtc;
|
|||
class DrmBuffer;
|
||||
class DrmDumbBuffer;
|
||||
class GammaRamp;
|
||||
class DrmConnectorMode;
|
||||
|
||||
class DrmGammaRamp
|
||||
{
|
||||
|
@ -97,7 +98,7 @@ public:
|
|||
DrmCrtc *crtc = nullptr;
|
||||
bool active = true; // whether or not the pipeline should be currently used
|
||||
bool enabled = true;// whether or not the pipeline needs a crtc
|
||||
int modeIndex = 0;
|
||||
QSharedPointer<DrmConnectorMode> mode;
|
||||
uint32_t overscan = 0;
|
||||
AbstractWaylandOutput::RgbRange rgbRange = AbstractWaylandOutput::RgbRange::Automatic;
|
||||
RenderLoopPrivate::SyncMode syncMode = RenderLoopPrivate::SyncMode::Fixed;
|
||||
|
|
|
@ -33,9 +33,8 @@ bool DrmPipeline::presentLegacy()
|
|||
|
||||
bool DrmPipeline::legacyModeset()
|
||||
{
|
||||
auto mode = m_connector->modes().at(pending.modeIndex);
|
||||
uint32_t connId = m_connector->id();
|
||||
if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, mode->nativeMode()) != 0) {
|
||||
if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, pending.mode->nativeMode()) != 0) {
|
||||
qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno);
|
||||
pending = m_next;
|
||||
m_primaryBuffer = m_oldTestBuffer;
|
||||
|
|
Loading…
Reference in a new issue