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:
parent
1b5009ae2b
commit
02bb276ebf
5 changed files with 123 additions and 66 deletions
|
@ -22,6 +22,64 @@
|
||||||
namespace KWin
|
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)
|
DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
|
||||||
: DrmObject(gpu, connectorId, {
|
: DrmObject(gpu, connectorId, {
|
||||||
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
|
PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required),
|
||||||
|
@ -55,25 +113,9 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmConnector::~DrmConnector() = default;
|
DrmConnector::~DrmConnector()
|
||||||
|
|
||||||
namespace {
|
|
||||||
quint64 refreshRateForMode(_drmModeModeInfo *m)
|
|
||||||
{
|
{
|
||||||
// Calculate higher precision (mHz) refresh rate
|
qDeleteAll(m_modes);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DrmConnector::init()
|
bool DrmConnector::init()
|
||||||
|
@ -137,7 +179,7 @@ QSize DrmConnector::physicalSize() const
|
||||||
return m_physicalSize;
|
return m_physicalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DrmConnector::Mode &DrmConnector::currentMode() const
|
DrmConnectorMode *DrmConnector::currentMode() const
|
||||||
{
|
{
|
||||||
return m_modes[m_modeIndex];
|
return m_modes[m_modeIndex];
|
||||||
}
|
}
|
||||||
|
@ -147,7 +189,7 @@ int DrmConnector::currentModeIndex() const
|
||||||
return m_modeIndex;
|
return m_modeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector<DrmConnector::Mode> &DrmConnector::modes()
|
QVector<DrmConnectorMode *> DrmConnector::modes()
|
||||||
{
|
{
|
||||||
return m_modes;
|
return m_modes;
|
||||||
}
|
}
|
||||||
|
@ -157,26 +199,26 @@ void DrmConnector::setModeIndex(int index)
|
||||||
m_modeIndex = 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
|
return one->clock == two->clock
|
||||||
&& one.hdisplay == two.hdisplay
|
&& one->hdisplay == two->hdisplay
|
||||||
&& one.hsync_start == two.hsync_start
|
&& one->hsync_start == two->hsync_start
|
||||||
&& one.hsync_end == two.hsync_end
|
&& one->hsync_end == two->hsync_end
|
||||||
&& one.htotal == two.htotal
|
&& one->htotal == two->htotal
|
||||||
&& one.hskew == two.hskew
|
&& one->hskew == two->hskew
|
||||||
&& one.vdisplay == two.vdisplay
|
&& one->vdisplay == two->vdisplay
|
||||||
&& one.vsync_start == two.vsync_start
|
&& one->vsync_start == two->vsync_start
|
||||||
&& one.vsync_end == two.vsync_end
|
&& one->vsync_end == two->vsync_end
|
||||||
&& one.vtotal == two.vtotal
|
&& one->vtotal == two->vtotal
|
||||||
&& one.vscan == two.vscan
|
&& one->vscan == two->vscan
|
||||||
&& one.vrefresh == two.vrefresh;
|
&& one->vrefresh == two->vrefresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmConnector::findCurrentMode(drmModeModeInfo currentMode)
|
void DrmConnector::findCurrentMode(drmModeModeInfo currentMode)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_modes.count(); i++) {
|
for (int i = 0; i < m_modes.count(); i++) {
|
||||||
if (checkIfEqual(m_modes[i].mode, currentMode)) {
|
if (checkIfEqual(m_modes[i]->nativeMode(), ¤tMode)) {
|
||||||
m_modeIndex = i;
|
m_modeIndex = i;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -259,16 +301,12 @@ bool DrmConnector::needsModeset() const
|
||||||
|
|
||||||
void DrmConnector::updateModes()
|
void DrmConnector::updateModes()
|
||||||
{
|
{
|
||||||
|
qDeleteAll(m_modes);
|
||||||
m_modes.clear();
|
m_modes.clear();
|
||||||
|
|
||||||
// reload modes
|
// reload modes
|
||||||
for (int i = 0; i < m_conn->count_modes; i++) {
|
for (int i = 0; i < m_conn->count_modes; i++) {
|
||||||
auto mode = m_conn->modes[i];
|
m_modes.append(new DrmConnectorMode(this, m_conn->modes[i]));
|
||||||
Mode m;
|
|
||||||
m.mode = mode;
|
|
||||||
m.size = QSize(mode.hdisplay, mode.vdisplay);
|
|
||||||
m.refreshRate = refreshRateForMode(&mode);
|
|
||||||
m_modes << m;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,30 @@ namespace KWin
|
||||||
{
|
{
|
||||||
|
|
||||||
class DrmPipeline;
|
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
|
class DrmConnector : public DrmObject
|
||||||
{
|
{
|
||||||
|
@ -66,14 +90,9 @@ public:
|
||||||
QString modelName() const;
|
QString modelName() const;
|
||||||
QSize physicalSize() const;
|
QSize physicalSize() const;
|
||||||
|
|
||||||
struct Mode {
|
DrmConnectorMode *currentMode() const;
|
||||||
drmModeModeInfo mode;
|
|
||||||
QSize size;
|
|
||||||
uint32_t refreshRate;
|
|
||||||
};
|
|
||||||
const Mode ¤tMode() const;
|
|
||||||
int currentModeIndex() const;
|
int currentModeIndex() const;
|
||||||
const QVector<Mode> &modes();
|
QVector<DrmConnectorMode *> modes();
|
||||||
void setModeIndex(int index);
|
void setModeIndex(int index);
|
||||||
void findCurrentMode(drmModeModeInfo currentMode);
|
void findCurrentMode(drmModeModeInfo currentMode);
|
||||||
void updateModes();
|
void updateModes();
|
||||||
|
@ -92,7 +111,7 @@ private:
|
||||||
QVector<uint32_t> m_encoders;
|
QVector<uint32_t> m_encoders;
|
||||||
Edid m_edid;
|
Edid m_edid;
|
||||||
QSize m_physicalSize = QSize(-1, -1);
|
QSize m_physicalSize = QSize(-1, -1);
|
||||||
QVector<Mode> m_modes;
|
QVector<DrmConnectorMode *> m_modes;
|
||||||
int m_modeIndex = 0;
|
int m_modeIndex = 0;
|
||||||
|
|
||||||
friend QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj);
|
friend QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj);
|
||||||
|
|
|
@ -156,7 +156,7 @@ DrmPlane *DrmCrtc::cursorPlane() const
|
||||||
void DrmCrtc::disable()
|
void DrmCrtc::disable()
|
||||||
{
|
{
|
||||||
setPending(PropertyIndex::Active, 0);
|
setPending(PropertyIndex::Active, 0);
|
||||||
setPendingBlob(PropertyIndex::ModeId, nullptr, sizeof(drmModeModeInfo));
|
setPending(PropertyIndex::ModeId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline)
|
||||||
{
|
{
|
||||||
m_pipeline->setOutput(this);
|
m_pipeline->setOutput(this);
|
||||||
auto conn = m_pipeline->connector();
|
auto conn = m_pipeline->connector();
|
||||||
m_renderLoop->setRefreshRate(conn->currentMode().refreshRate);
|
m_renderLoop->setRefreshRate(conn->currentMode()->refreshRate());
|
||||||
setSubPixelInternal(conn->subpixel());
|
setSubPixelInternal(conn->subpixel());
|
||||||
setInternal(conn->isInternal());
|
setInternal(conn->isInternal());
|
||||||
setCapabilityInternal(DrmOutput::Capability::Dpms);
|
setCapabilityInternal(DrmOutput::Capability::Dpms);
|
||||||
|
@ -192,7 +192,7 @@ QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
|
||||||
bool modeFound = false;
|
bool modeFound = false;
|
||||||
QVector<Mode> modes;
|
QVector<Mode> modes;
|
||||||
auto conn = m_pipeline->connector();
|
auto conn = m_pipeline->connector();
|
||||||
auto modelist = conn->modes();
|
QVector<DrmConnectorMode *> modelist = conn->modes();
|
||||||
|
|
||||||
modes.reserve(modelist.count());
|
modes.reserve(modelist.count());
|
||||||
for (int i = 0; i < modelist.count(); ++i) {
|
for (int i = 0; i < modelist.count(); ++i) {
|
||||||
|
@ -201,13 +201,13 @@ QVector<AbstractWaylandOutput::Mode> DrmOutput::getModes() const
|
||||||
mode.flags |= ModeFlag::Current;
|
mode.flags |= ModeFlag::Current;
|
||||||
modeFound = true;
|
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.flags |= ModeFlag::Preferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode.id = i;
|
mode.id = i;
|
||||||
mode.size = modelist[i].size;
|
mode.size = modelist[i]->size();
|
||||||
mode.refreshRate = modelist[i].refreshRate;
|
mode.refreshRate = modelist[i]->refreshRate();
|
||||||
modes << mode;
|
modes << mode;
|
||||||
}
|
}
|
||||||
if (!modeFound) {
|
if (!modeFound) {
|
||||||
|
@ -353,8 +353,8 @@ void DrmOutput::updateModes()
|
||||||
if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test)) {
|
if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test)) {
|
||||||
m_pipeline->applyPendingChanges();
|
m_pipeline->applyPendingChanges();
|
||||||
auto mode = m_pipeline->connector()->currentMode();
|
auto mode = m_pipeline->connector()->currentMode();
|
||||||
setCurrentModeInternal(mode.size, mode.refreshRate);
|
setCurrentModeInternal(mode->size(), mode->refreshRate());
|
||||||
m_renderLoop->setRefreshRate(mode.refreshRate);
|
m_renderLoop->setRefreshRate(mode->refreshRate());
|
||||||
} else {
|
} else {
|
||||||
qCWarning(KWIN_DRM) << "Setting changed mode failed!";
|
qCWarning(KWIN_DRM) << "Setting changed mode failed!";
|
||||||
m_pipeline->revertPendingChanges();
|
m_pipeline->revertPendingChanges();
|
||||||
|
@ -440,7 +440,7 @@ bool DrmOutput::queueChanges(const WaylandOutputConfig &config)
|
||||||
auto modelist = m_connector->modes();
|
auto modelist = m_connector->modes();
|
||||||
int index = -1;
|
int index = -1;
|
||||||
for (int i = 0; i < modelist.size(); i++) {
|
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;
|
index = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -471,8 +471,8 @@ void DrmOutput::applyQueuedChanges(const WaylandOutputConfig &config)
|
||||||
|
|
||||||
m_connector->setModeIndex(m_pipeline->pending.modeIndex);
|
m_connector->setModeIndex(m_pipeline->pending.modeIndex);
|
||||||
auto mode = m_connector->currentMode();
|
auto mode = m_connector->currentMode();
|
||||||
setCurrentModeInternal(mode.size, mode.refreshRate);
|
setCurrentModeInternal(mode->size(), mode->refreshRate());
|
||||||
m_renderLoop->setRefreshRate(mode.refreshRate);
|
m_renderLoop->setRefreshRate(mode->refreshRate());
|
||||||
setOverscanInternal(m_pipeline->pending.overscan);
|
setOverscanInternal(m_pipeline->pending.overscan);
|
||||||
setRgbRangeInternal(m_pipeline->pending.rgbRange);
|
setRgbRangeInternal(m_pipeline->pending.rgbRange);
|
||||||
setVrrPolicy(props->vrrPolicy);
|
setVrrPolicy(props->vrrPolicy);
|
||||||
|
|
|
@ -259,7 +259,7 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags)
|
||||||
flags |= DRM_MODE_PAGE_FLIP_EVENT;
|
flags |= DRM_MODE_PAGE_FLIP_EVENT;
|
||||||
}
|
}
|
||||||
if (pending.crtc) {
|
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()->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->primaryPlane()->setBuffer(activePending() ? m_primaryBuffer.get() : nullptr);
|
||||||
pending.crtc->setPending(DrmCrtc::PropertyIndex::VrrEnabled, pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive);
|
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->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()->setPending(DrmPlane::PropertyIndex::CrtcId, activePending() ? pending.crtc->id() : 0);
|
||||||
pending.crtc->primaryPlane()->setTransformation(DrmPlane::Transformation::Rotate0);
|
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();
|
m_formats = pending.crtc->primaryPlane()->formats();
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ bool DrmPipeline::legacyModeset()
|
||||||
{
|
{
|
||||||
auto mode = m_connector->modes()[pending.modeIndex];
|
auto mode = m_connector->modes()[pending.modeIndex];
|
||||||
uint32_t connId = m_connector->id();
|
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);
|
qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno);
|
||||||
pending = m_next;
|
pending = m_next;
|
||||||
m_primaryBuffer = m_oldTestBuffer;
|
m_primaryBuffer = m_oldTestBuffer;
|
||||||
|
@ -438,14 +438,14 @@ QSize DrmPipeline::sourceSize() const
|
||||||
{
|
{
|
||||||
auto mode = m_connector->modes()[pending.modeIndex];
|
auto mode = m_connector->modes()[pending.modeIndex];
|
||||||
if (pending.transformation & (DrmPlane::Transformation::Rotate90 | DrmPlane::Transformation::Rotate270)) {
|
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
|
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
|
QPoint DrmPipeline::cursorPos() const
|
||||||
|
|
Loading…
Reference in a new issue