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
|
||||
{
|
||||
|
||||
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(), ¤tMode)) {
|
||||
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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¤tMode() 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue