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:
parent
3b3c75a8e9
commit
4453ce7eef
5 changed files with 82 additions and 73 deletions
|
@ -304,19 +304,6 @@ bool DrmConnector::updateProperties()
|
||||||
if (scalingMode.isValid() && scalingMode.hasEnum(ScalingMode::Full_Aspect)) {
|
if (scalingMode.isValid() && scalingMode.hasEnum(ScalingMode::Full_Aspect)) {
|
||||||
m_modes.append(generateCommonModes());
|
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();
|
m_mstPath.clear();
|
||||||
|
|
|
@ -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
|
// check for added and removed connectors
|
||||||
QList<DrmConnector *> existing;
|
QList<DrmConnector *> existing;
|
||||||
QList<DrmOutput *> addedOutputs;
|
QList<DrmOutput *> addedOutputs;
|
||||||
|
@ -292,6 +301,8 @@ bool DrmGpu::updateOutputs()
|
||||||
// only "enable" VR headsets here; Workspace makes this decision for normal outputs
|
// only "enable" VR headsets here; Workspace makes this decision for normal outputs
|
||||||
pipeline->setEnable(conn->isNonDesktop());
|
pipeline->setEnable(conn->isNonDesktop());
|
||||||
pipeline->applyPendingChanges();
|
pipeline->applyPendingChanges();
|
||||||
|
} else {
|
||||||
|
output->updateConnectorProperties();
|
||||||
}
|
}
|
||||||
if (stillExists) {
|
if (stillExists) {
|
||||||
it++;
|
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();
|
DrmPipeline::Error err = testPendingConfiguration();
|
||||||
if (err == DrmPipeline::Error::None) {
|
if (err == DrmPipeline::Error::None) {
|
||||||
for (const auto &pipeline : std::as_const(m_pipelines)) {
|
for (const auto &pipeline : std::as_const(m_pipelines)) {
|
||||||
|
|
|
@ -35,7 +35,6 @@
|
||||||
namespace KWin
|
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;
|
static const bool s_disableTripleBuffering = qEnvironmentVariableIntValue("KWIN_DRM_DISABLE_TRIPLE_BUFFERING") == 1;
|
||||||
|
|
||||||
DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
|
DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
|
||||||
|
@ -44,68 +43,30 @@ DrmOutput::DrmOutput(const std::shared_ptr<DrmConnector> &conn)
|
||||||
, m_connector(conn)
|
, m_connector(conn)
|
||||||
{
|
{
|
||||||
m_pipeline->setOutput(this);
|
m_pipeline->setOutput(this);
|
||||||
m_renderLoop->setRefreshRate(m_pipeline->mode()->refreshRate());
|
|
||||||
if (m_gpu->atomicModeSetting() && !s_disableTripleBuffering) {
|
if (m_gpu->atomicModeSetting() && !s_disableTripleBuffering) {
|
||||||
m_renderLoop->setMaxPendingFrameCount(2);
|
m_renderLoop->setMaxPendingFrameCount(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
Capabilities capabilities = Capability::Dpms | Capability::IccProfile;
|
const Edid *edid = m_connector->edid();
|
||||||
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();
|
|
||||||
setInformation(Information{
|
setInformation(Information{
|
||||||
.name = conn->connectorName(),
|
.name = m_connector->connectorName(),
|
||||||
.manufacturer = edid->manufacturerString(),
|
.manufacturer = edid->manufacturerString(),
|
||||||
.model = conn->modelName(),
|
.model = m_connector->modelName(),
|
||||||
.serialNumber = edid->serialNumber(),
|
.serialNumber = edid->serialNumber(),
|
||||||
.eisaId = edid->eisaId(),
|
.eisaId = edid->eisaId(),
|
||||||
.physicalSize = conn->physicalSize(),
|
.physicalSize = m_connector->physicalSize(),
|
||||||
.edid = *edid,
|
.edid = *edid,
|
||||||
.subPixel = conn->subpixel(),
|
.subPixel = m_connector->subpixel(),
|
||||||
.capabilities = capabilities,
|
.capabilities = computeCapabilities(),
|
||||||
.panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : OutputTransform::Normal,
|
.panelOrientation = m_connector->panelOrientation.isValid() ? DrmConnector::toKWinTransform(m_connector->panelOrientation.enumValue()) : OutputTransform::Normal,
|
||||||
.internal = conn->isInternal(),
|
.internal = m_connector->isInternal(),
|
||||||
.nonDesktop = conn->isNonDesktop(),
|
.nonDesktop = m_connector->isNonDesktop(),
|
||||||
.mstPath = conn->mstPath(),
|
.mstPath = m_connector->mstPath(),
|
||||||
.maxPeakBrightness = edid->desiredMaxLuminance(),
|
.maxPeakBrightness = edid->desiredMaxLuminance(),
|
||||||
.maxAverageBrightness = edid->desiredMaxFrameAverageLuminance(),
|
.maxAverageBrightness = edid->desiredMaxFrameAverageLuminance(),
|
||||||
.minBrightness = edid->desiredMinLuminance(),
|
.minBrightness = edid->desiredMinLuminance(),
|
||||||
});
|
});
|
||||||
|
updateConnectorProperties();
|
||||||
initialState.modes = getModes();
|
|
||||||
initialState.currentMode = m_pipeline->mode();
|
|
||||||
if (!initialState.currentMode) {
|
|
||||||
initialState.currentMode = initialState.modes.constFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
setState(initialState);
|
|
||||||
|
|
||||||
m_turnOffTimer.setSingleShot(true);
|
m_turnOffTimer.setSingleShot(true);
|
||||||
m_turnOffTimer.setInterval(dimAnimationTime());
|
m_turnOffTimer.setInterval(dimAnimationTime());
|
||||||
|
@ -244,8 +205,10 @@ DrmPlane::Transformations outputToPlaneTransform(OutputTransform transform)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrmOutput::updateModes()
|
void DrmOutput::updateConnectorProperties()
|
||||||
{
|
{
|
||||||
|
updateInformation();
|
||||||
|
|
||||||
State next = m_state;
|
State next = m_state;
|
||||||
next.modes = getModes();
|
next.modes = getModes();
|
||||||
|
|
||||||
|
@ -266,12 +229,61 @@ void DrmOutput::updateModes()
|
||||||
|
|
||||||
next.currentMode = m_pipeline->mode();
|
next.currentMode = m_pipeline->mode();
|
||||||
if (!next.currentMode) {
|
if (!next.currentMode) {
|
||||||
|
// some mode needs to be set
|
||||||
next.currentMode = next.modes.constFirst();
|
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);
|
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)
|
void DrmOutput::updateDpmsMode(DpmsMode dpmsMode)
|
||||||
{
|
{
|
||||||
State next = m_state;
|
State next = m_state;
|
||||||
|
|
|
@ -48,7 +48,6 @@ public:
|
||||||
bool queueChanges(const std::shared_ptr<OutputChangeSet> &properties);
|
bool queueChanges(const std::shared_ptr<OutputChangeSet> &properties);
|
||||||
void applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &properties);
|
void applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &properties);
|
||||||
void revertQueuedChanges();
|
void revertQueuedChanges();
|
||||||
void updateModes();
|
|
||||||
void updateDpmsMode(DpmsMode dpmsMode);
|
void updateDpmsMode(DpmsMode dpmsMode);
|
||||||
|
|
||||||
bool updateCursorLayer() override;
|
bool updateCursorLayer() override;
|
||||||
|
@ -62,11 +61,15 @@ public:
|
||||||
QVector3D channelFactors() const;
|
QVector3D channelFactors() const;
|
||||||
bool needsColormanagement() const;
|
bool needsColormanagement() const;
|
||||||
|
|
||||||
|
void updateConnectorProperties();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool setDrmDpmsMode(DpmsMode mode);
|
bool setDrmDpmsMode(DpmsMode mode);
|
||||||
void setDpmsMode(DpmsMode mode) override;
|
void setDpmsMode(DpmsMode mode) override;
|
||||||
bool doSetChannelFactors(const QVector3D &rgb);
|
bool doSetChannelFactors(const QVector3D &rgb);
|
||||||
ColorDescription createColorDescription(const std::shared_ptr<OutputChangeSet> &props) const;
|
ColorDescription createColorDescription(const std::shared_ptr<OutputChangeSet> &props) const;
|
||||||
|
Capabilities computeCapabilities() const;
|
||||||
|
void updateInformation();
|
||||||
|
|
||||||
QList<std::shared_ptr<OutputMode>> getModes() const;
|
QList<std::shared_ptr<OutputMode>> getModes() const;
|
||||||
|
|
||||||
|
|
|
@ -552,8 +552,12 @@ static QUuid generateOutputId(const QString &eisaId, const QString &model,
|
||||||
|
|
||||||
void Output::setInformation(const Information &information)
|
void Output::setInformation(const Information &information)
|
||||||
{
|
{
|
||||||
|
const auto oldInfo = m_information;
|
||||||
m_information = information;
|
m_information = information;
|
||||||
m_uuid = generateOutputId(eisaId(), model(), serialNumber(), name());
|
m_uuid = generateOutputId(eisaId(), model(), serialNumber(), name());
|
||||||
|
if (oldInfo.capabilities != information.capabilities) {
|
||||||
|
Q_EMIT capabilitiesChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Output::setState(const State &state)
|
void Output::setState(const State &state)
|
||||||
|
|
Loading…
Reference in a new issue