backends/drm: update output properties after they're created too

Otherwise we might miss some changes that come without a hotplug event,
like adaptive sync becoming available after the output has been initialized

BUG: 486149
This commit is contained in:
Xaver Hugl 2024-05-07 23:59:04 +02:00
parent 3b3c75a8e9
commit 4453ce7eef
5 changed files with 82 additions and 73 deletions

View file

@ -304,19 +304,6 @@ bool DrmConnector::updateProperties()
if (scalingMode.isValid() && scalingMode.hasEnum(ScalingMode::Full_Aspect)) {
m_modes.append(generateCommonModes());
}
if (m_pipeline->mode()) {
if (const auto mode = findMode(*m_pipeline->mode()->nativeMode())) {
m_pipeline->setMode(mode);
} else {
m_pipeline->setMode(m_modes.constFirst());
}
} else {
m_pipeline->setMode(m_modes.constFirst());
}
m_pipeline->applyPendingChanges();
if (m_pipeline->output()) {
m_pipeline->output()->updateModes();
}
}
m_mstPath.clear();

View file

@ -250,6 +250,15 @@ bool DrmGpu::updateOutputs()
}
}
// update crtc properties
for (const auto &crtc : std::as_const(m_crtcs)) {
crtc->updateProperties();
}
// update plane properties
for (const auto &plane : std::as_const(m_planes)) {
plane->updateProperties();
}
// check for added and removed connectors
QList<DrmConnector *> existing;
QList<DrmOutput *> addedOutputs;
@ -292,6 +301,8 @@ bool DrmGpu::updateOutputs()
// only "enable" VR headsets here; Workspace makes this decision for normal outputs
pipeline->setEnable(conn->isNonDesktop());
pipeline->applyPendingChanges();
} else {
output->updateConnectorProperties();
}
if (stillExists) {
it++;
@ -301,14 +312,6 @@ bool DrmGpu::updateOutputs()
}
}
// update crtc properties
for (const auto &crtc : std::as_const(m_crtcs)) {
crtc->updateProperties();
}
// update plane properties
for (const auto &plane : std::as_const(m_planes)) {
plane->updateProperties();
}
DrmPipeline::Error err = testPendingConfiguration();
if (err == DrmPipeline::Error::None) {
for (const auto &pipeline : std::as_const(m_pipelines)) {

View file

@ -35,7 +35,6 @@
namespace KWin
{
static const bool s_allowColorspaceIntel = qEnvironmentVariableIntValue("KWIN_DRM_ALLOW_INTEL_COLORSPACE") == 1;
static const bool s_disableTripleBuffering = qEnvironmentVariableIntValue("KWIN_DRM_DISABLE_TRIPLE_BUFFERING") == 1;
DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
@ -44,68 +43,30 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
, m_connector(conn)
{
m_pipeline->setOutput(this);
m_renderLoop->setRefreshRate(m_pipeline->mode()->refreshRate());
if (m_gpu->atomicModeSetting() && !s_disableTripleBuffering) {
m_renderLoop->setMaxPendingFrameCount(2);
}
Capabilities capabilities = Capability::Dpms | Capability::IccProfile;
State initialState;
if (conn->overscan.isValid() || conn->underscan.isValid()) {
capabilities |= Capability::Overscan;
initialState.overscan = conn->overscan.isValid() ? conn->overscan.value() : conn->underscanVBorder.value();
}
if (conn->vrrCapable.isValid() && conn->vrrCapable.value()) {
capabilities |= Capability::Vrr;
}
if (gpu()->asyncPageflipSupported()) {
capabilities |= Capability::Tearing;
}
if (conn->broadcastRGB.isValid()) {
capabilities |= Capability::RgbRange;
initialState.rgbRange = DrmConnector::broadcastRgbToRgbRange(conn->broadcastRGB.enumValue());
}
if (m_connector->hdrMetadata.isValid() && m_connector->edid()->supportsPQ()) {
capabilities |= Capability::HighDynamicRange;
}
if (m_connector->colorspace.isValid() && m_connector->colorspace.hasEnum(DrmConnector::Colorspace::BT2020_RGB) && m_connector->edid()->supportsBT2020()) {
if (!m_gpu->isI915() || s_allowColorspaceIntel) {
capabilities |= Capability::WideColorGamut;
}
}
if (conn->isInternal()) {
// TODO only set this if an orientation sensor is available?
capabilities |= Capability::AutoRotation;
}
const Edid *edid = conn->edid();
const Edid *edid = m_connector->edid();
setInformation(Information{
.name = conn->connectorName(),
.name = m_connector->connectorName(),
.manufacturer = edid->manufacturerString(),
.model = conn->modelName(),
.model = m_connector->modelName(),
.serialNumber = edid->serialNumber(),
.eisaId = edid->eisaId(),
.physicalSize = conn->physicalSize(),
.physicalSize = m_connector->physicalSize(),
.edid = *edid,
.subPixel = conn->subpixel(),
.capabilities = capabilities,
.panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : OutputTransform::Normal,
.internal = conn->isInternal(),
.nonDesktop = conn->isNonDesktop(),
.mstPath = conn->mstPath(),
.subPixel = m_connector->subpixel(),
.capabilities = computeCapabilities(),
.panelOrientation = m_connector->panelOrientation.isValid() ? DrmConnector::toKWinTransform(m_connector->panelOrientation.enumValue()) : OutputTransform::Normal,
.internal = m_connector->isInternal(),
.nonDesktop = m_connector->isNonDesktop(),
.mstPath = m_connector->mstPath(),
.maxPeakBrightness = edid->desiredMaxLuminance(),
.maxAverageBrightness = edid->desiredMaxFrameAverageLuminance(),
.minBrightness = edid->desiredMinLuminance(),
});
initialState.modes = getModes();
initialState.currentMode = m_pipeline->mode();
if (!initialState.currentMode) {
initialState.currentMode = initialState.modes.constFirst();
}
setState(initialState);
updateConnectorProperties();
m_turnOffTimer.setSingleShot(true);
m_turnOffTimer.setInterval(dimAnimationTime());
@ -244,8 +205,10 @@ DrmPlane::Transformations outputToPlaneTransform(OutputTransform transform)
}
}
void DrmOutput::updateModes()
void DrmOutput::updateConnectorProperties()
{
updateInformation();
State next = m_state;
next.modes = getModes();
@ -266,12 +229,61 @@ void DrmOutput::updateModes()
next.currentMode = m_pipeline->mode();
if (!next.currentMode) {
// some mode needs to be set
next.currentMode = next.modes.constFirst();
m_renderLoop->setRefreshRate(next.currentMode->refreshRate());
m_pipeline->setMode(std::static_pointer_cast<DrmConnectorMode>(next.currentMode));
m_pipeline->applyPendingChanges();
}
setState(next);
}
static const bool s_allowColorspaceIntel = qEnvironmentVariableIntValue("KWIN_DRM_ALLOW_INTEL_COLORSPACE") == 1;
Output::Capabilities DrmOutput::computeCapabilities() const
{
Capabilities capabilities = Capability::Dpms | Capability::IccProfile;
if (m_connector->overscan.isValid() || m_connector->underscan.isValid()) {
capabilities |= Capability::Overscan;
}
if (m_connector->vrrCapable.isValid() && m_connector->vrrCapable.value()) {
capabilities |= Capability::Vrr;
}
if (gpu()->asyncPageflipSupported()) {
capabilities |= Capability::Tearing;
}
if (m_connector->broadcastRGB.isValid()) {
capabilities |= Capability::RgbRange;
}
if (m_connector->hdrMetadata.isValid() && m_connector->edid()->supportsPQ()) {
capabilities |= Capability::HighDynamicRange;
}
if (m_connector->colorspace.isValid() && m_connector->colorspace.hasEnum(DrmConnector::Colorspace::BT2020_RGB) && m_connector->edid()->supportsBT2020()) {
if (!m_gpu->isI915() || s_allowColorspaceIntel) {
capabilities |= Capability::WideColorGamut;
}
}
if (m_connector->isInternal()) {
// TODO only set this if an orientation sensor is available?
capabilities |= Capability::AutoRotation;
}
return capabilities;
}
void DrmOutput::updateInformation()
{
// not all changes are currently handled by the rest of KWin
// so limit the changes to what's verified to work
const Edid *edid = m_connector->edid();
Information nextInfo = m_information;
nextInfo.capabilities = computeCapabilities();
nextInfo.maxPeakBrightness = edid->desiredMaxLuminance();
nextInfo.maxAverageBrightness = edid->desiredMaxFrameAverageLuminance();
nextInfo.minBrightness = edid->desiredMinLuminance();
setInformation(nextInfo);
}
void DrmOutput::updateDpmsMode(DpmsMode dpmsMode)
{
State next = m_state;

View file

@ -48,7 +48,6 @@ public:
bool queueChanges(const std::shared_ptr<OutputChangeSet> &properties);
void applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &properties);
void revertQueuedChanges();
void updateModes();
void updateDpmsMode(DpmsMode dpmsMode);
bool updateCursorLayer() override;
@ -62,11 +61,15 @@ public:
QVector3D channelFactors() const;
bool needsColormanagement() const;
void updateConnectorProperties();
private:
bool setDrmDpmsMode(DpmsMode mode);
void setDpmsMode(DpmsMode mode) override;
bool doSetChannelFactors(const QVector3D &rgb);
ColorDescription createColorDescription(const std::shared_ptr<OutputChangeSet> &props) const;
Capabilities computeCapabilities() const;
void updateInformation();
QList<std::shared_ptr<OutputMode>> getModes() const;

View file

@ -552,8 +552,12 @@ static QUuid generateOutputId(const QString &eisaId, const QString &model,
void Output::setInformation(const Information &information)
{
const auto oldInfo = m_information;
m_information = information;
m_uuid = generateOutputId(eisaId(), model(), serialNumber(), name());
if (oldInfo.capabilities != information.capabilities) {
Q_EMIT capabilitiesChanged();
}
}
void Output::setState(const State &state)