platforms/drm: Move ownership of mode blob to connector mode

The main motivation behind this change is to move management of drm
blobs out of property wrappers in specialized wrappers to simplify state
management with blobs.

Connector mode blobs are created on demand.
This commit is contained in:
Vlad Zahorodnii 2021-09-28 11:30:57 +03:00 committed by Xaver Hugl
parent 1b5009ae2b
commit 02bb276ebf
5 changed files with 123 additions and 66 deletions

View file

@ -22,6 +22,64 @@
namespace KWin
{
static quint64 refreshRateForMode(_drmModeModeInfo *m)
{
// Calculate higher precision (mHz) refresh rate
// logic based on Weston, see compositor-drm.c
quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal;
if (m->flags & DRM_MODE_FLAG_INTERLACE) {
refreshRate *= 2;
}
if (m->flags & DRM_MODE_FLAG_DBLSCAN) {
refreshRate /= 2;
}
if (m->vscan > 1) {
refreshRate /= m->vscan;
}
return refreshRate;
}
DrmConnectorMode::DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode)
: m_connector(connector)
, m_nativeMode(nativeMode)
, m_size(nativeMode.hdisplay, nativeMode.vdisplay)
, m_refreshRate(refreshRateForMode(&nativeMode))
{
}
DrmConnectorMode::~DrmConnectorMode()
{
if (m_blobId) {
drmModeDestroyPropertyBlob(m_connector->gpu()->fd(), m_blobId);
m_blobId = 0;
}
}
drmModeModeInfo *DrmConnectorMode::nativeMode()
{
return &m_nativeMode;
}
QSize DrmConnectorMode::size() const
{
return m_size;
}
uint32_t DrmConnectorMode::refreshRate() const
{
return m_refreshRate;
}
uint32_t DrmConnectorMode::blobId()
{
if (!m_blobId) {
if (drmModeCreatePropertyBlob(m_connector->gpu()->fd(), &m_nativeMode, sizeof(m_nativeMode), &m_blobId) != 0) {
qCWarning(KWIN_DRM) << "Failed to create connector mode blob:" << strerror(errno);
}
}
return m_blobId;
}
DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
: DrmObject(gpu, connectorId, {
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
@ -55,25 +113,9 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
}
}
DrmConnector::~DrmConnector() = default;
namespace {
quint64 refreshRateForMode(_drmModeModeInfo *m)
DrmConnector::~DrmConnector()
{
// Calculate higher precision (mHz) refresh rate
// logic based on Weston, see compositor-drm.c
quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal;
if (m->flags & DRM_MODE_FLAG_INTERLACE) {
refreshRate *= 2;
}
if (m->flags & DRM_MODE_FLAG_DBLSCAN) {
refreshRate /= 2;
}
if (m->vscan > 1) {
refreshRate /= m->vscan;
}
return refreshRate;
}
qDeleteAll(m_modes);
}
bool DrmConnector::init()
@ -137,7 +179,7 @@ QSize DrmConnector::physicalSize() const
return m_physicalSize;
}
const DrmConnector::Mode &DrmConnector::currentMode() const
DrmConnectorMode *DrmConnector::currentMode() const
{
return m_modes[m_modeIndex];
}
@ -147,7 +189,7 @@ int DrmConnector::currentModeIndex() const
return m_modeIndex;
}
const QVector<DrmConnector::Mode> &DrmConnector::modes()
QVector<DrmConnectorMode *> DrmConnector::modes()
{
return m_modes;
}
@ -157,26 +199,26 @@ void DrmConnector::setModeIndex(int index)
m_modeIndex = index;
}
static bool checkIfEqual(drmModeModeInfo one, drmModeModeInfo two)
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;
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].mode, currentMode)) {
if (checkIfEqual(m_modes[i]->nativeMode(), &currentMode)) {
m_modeIndex = i;
return;
}
@ -259,16 +301,12 @@ 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++) {
auto mode = m_conn->modes[i];
Mode m;
m.mode = mode;
m.size = QSize(mode.hdisplay, mode.vdisplay);
m.refreshRate = refreshRateForMode(&mode);
m_modes << m;
m_modes.append(new DrmConnectorMode(this, m_conn->modes[i]));
}
}

View file

@ -23,6 +23,30 @@ namespace KWin
{
class DrmPipeline;
class DrmConnector;
/**
* The DrmConnectorMode class represents a native mode and the associated blob.
*/
class DrmConnectorMode
{
public:
DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode);
~DrmConnectorMode();
uint32_t blobId();
drmModeModeInfo *nativeMode();
QSize size() const;
uint32_t refreshRate() const;
private:
DrmConnector *m_connector;
drmModeModeInfo m_nativeMode;
QSize m_size;
uint32_t m_refreshRate;
uint32_t m_blobId = 0;
};
class DrmConnector : public DrmObject
{
@ -66,14 +90,9 @@ public:
QString modelName() const;
QSize physicalSize() const;
struct Mode {
drmModeModeInfo mode;
QSize size;
uint32_t refreshRate;
};
const Mode &currentMode() const;
DrmConnectorMode *currentMode() const;
int currentModeIndex() const;
const QVector<Mode> &modes();
QVector<DrmConnectorMode *> modes();
void setModeIndex(int index);
void findCurrentMode(drmModeModeInfo currentMode);
void updateModes();
@ -92,7 +111,7 @@ private:
QVector<uint32_t> m_encoders;
Edid m_edid;
QSize m_physicalSize = QSize(-1, -1);
QVector<Mode> m_modes;
QVector<DrmConnectorMode *> m_modes;
int m_modeIndex = 0;
friend QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj);

View file

@ -156,7 +156,7 @@ DrmPlane *DrmCrtc::cursorPlane() const
void DrmCrtc::disable()
{
setPending(PropertyIndex::Active, 0);
setPendingBlob(PropertyIndex::ModeId, nullptr, sizeof(drmModeModeInfo));
setPending(PropertyIndex::ModeId, 0);
}
}

View file

@ -42,7 +42,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
{
m_pipeline->setOutput(this);
auto conn = m_pipeline->connector();
m_renderLoop->setRefreshRate(conn->currentMode().refreshRate);
m_renderLoop->setRefreshRate(conn->currentMode()->refreshRate());
setSubPixelInternal(conn->subpixel());
setInternal(conn->isInternal());
setCapabilityInternal(DrmOutput::Capability::Dpms);
@ -192,7 +192,7 @@ QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
bool modeFound = false;
QVector<Mode> modes;
auto conn = m_pipeline->connector();
auto modelist = conn->modes();
QVector<DrmConnectorMode *> modelist = conn->modes();
modes.reserve(modelist.count());
for (int i = 0; i < modelist.count(); ++i) {
@ -201,13 +201,13 @@ QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
mode.flags |= ModeFlag::Current;
modeFound = true;
}
if (modelist[i].mode.type & DRM_MODE_TYPE_PREFERRED) {
if (modelist[i]->nativeMode()->type & DRM_MODE_TYPE_PREFERRED) {
mode.flags |= ModeFlag::Preferred;
}
mode.id = i;
mode.size = modelist[i].size;
mode.refreshRate = modelist[i].refreshRate;
mode.size = modelist[i]->size();
mode.refreshRate = modelist[i]->refreshRate();
modes << mode;
}
if (!modeFound) {
@ -353,8 +353,8 @@ void DrmOutput::updateModes()
if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test)) {
m_pipeline->applyPendingChanges();
auto mode = m_pipeline->connector()->currentMode();
setCurrentModeInternal(mode.size, mode.refreshRate);
m_renderLoop->setRefreshRate(mode.refreshRate);
setCurrentModeInternal(mode->size(), mode->refreshRate());
m_renderLoop->setRefreshRate(mode->refreshRate());
} else {
qCWarning(KWIN_DRM) << "Setting changed mode failed!";
m_pipeline->revertPendingChanges();
@ -440,7 +440,7 @@ bool DrmOutput::queueChanges(const WaylandOutputConfig &config)
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) {
if (modelist[i]->size() == props->modeSize && modelist[i]->refreshRate() == props->refreshRate) {
index = i;
break;
}
@ -471,8 +471,8 @@ void DrmOutput::applyQueuedChanges(const WaylandOutputConfig &config)
m_connector->setModeIndex(m_pipeline->pending.modeIndex);
auto mode = m_connector->currentMode();
setCurrentModeInternal(mode.size, mode.refreshRate);
m_renderLoop->setRefreshRate(mode.refreshRate);
setCurrentModeInternal(mode->size(), mode->refreshRate());
m_renderLoop->setRefreshRate(mode->refreshRate());
setOverscanInternal(m_pipeline->pending.overscan);
setRgbRangeInternal(m_pipeline->pending.rgbRange);
setVrrPolicy(props->vrrPolicy);

View file

@ -259,7 +259,7 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags)
flags |= DRM_MODE_PAGE_FLIP_EVENT;
}
if (pending.crtc) {
auto modeSize = m_connector->modes()[pending.modeIndex].size;
auto modeSize = m_connector->modes()[pending.modeIndex]->size();
pending.crtc->primaryPlane()->set(QPoint(0, 0), m_primaryBuffer ? m_primaryBuffer->size() : modeSize, QPoint(0, 0), modeSize);
pending.crtc->primaryPlane()->setBuffer(activePending() ? m_primaryBuffer.get() : nullptr);
pending.crtc->setPending(DrmCrtc::PropertyIndex::VrrEnabled, pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive);
@ -362,11 +362,11 @@ void DrmPipeline::prepareModeset()
}
pending.crtc->setPending(DrmCrtc::PropertyIndex::Active, activePending());
pending.crtc->setPendingBlob(DrmCrtc::PropertyIndex::ModeId, activePending() ? &mode.mode : nullptr, sizeof(drmModeModeInfo));
pending.crtc->setPending(DrmCrtc::PropertyIndex::ModeId, activePending() ? mode->blobId() : 0);
pending.crtc->primaryPlane()->setPending(DrmPlane::PropertyIndex::CrtcId, activePending() ? pending.crtc->id() : 0);
pending.crtc->primaryPlane()->setTransformation(DrmPlane::Transformation::Rotate0);
pending.crtc->primaryPlane()->set(QPoint(0, 0), sourceSize(), QPoint(0, 0), mode.size);
pending.crtc->primaryPlane()->set(QPoint(0, 0), sourceSize(), QPoint(0, 0), mode->size());
m_formats = pending.crtc->primaryPlane()->formats();
}
@ -418,7 +418,7 @@ bool DrmPipeline::legacyModeset()
{
auto mode = m_connector->modes()[pending.modeIndex];
uint32_t connId = m_connector->id();
if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, &mode.mode) != 0) {
if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, mode->nativeMode()) != 0) {
qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno);
pending = m_next;
m_primaryBuffer = m_oldTestBuffer;
@ -438,14 +438,14 @@ QSize DrmPipeline::sourceSize() const
{
auto mode = m_connector->modes()[pending.modeIndex];
if (pending.transformation & (DrmPlane::Transformation::Rotate90 | DrmPlane::Transformation::Rotate270)) {
return mode.size.transposed();
return mode->size().transposed();
}
return mode.size;
return mode->size();
}
bool DrmPipeline::isCursorVisible() const
{
return pending.crtc && pending.crtc->isCursorVisible(QRect(QPoint(0, 0), m_connector->currentMode().size));
return pending.crtc && pending.crtc->isCursorVisible(QRect(QPoint(0, 0), m_connector->currentMode()->size()));
}
QPoint DrmPipeline::cursorPos() const