Commit a1ed313a authored by Xaver Hugl's avatar Xaver Hugl
Browse files

backends/drm: move placeholder output management to Workspace

Backends aren't the right layer to take care of placeholder outputs, and
don't really have enough information to do it either. This also fixes a
crash, because the placeholder output currently gets created too late
parent 070f63c4
Pipeline #224088 passed with stage
in 21 minutes and 4 seconds
......@@ -93,6 +93,7 @@ target_sources(kwin PRIVATE
outputconfiguration.cpp
outputlayer.cpp
overlaywindow.cpp
placeholderinputeventfilter.cpp
placement.cpp
platform.cpp
plugin.cpp
......
......@@ -21,7 +21,6 @@ target_sources(kwin PRIVATE
drm_output.cpp
drm_pipeline.cpp
drm_pipeline_legacy.cpp
drm_placeholderinputeventfilter.cpp
drm_property.cpp
drm_qpainter_backend.cpp
drm_qpainter_layer.cpp
......
......@@ -355,31 +355,6 @@ void DrmBackend::updateOutputs()
Q_EMIT screensQueried();
}
void DrmBackend::enableOutput(DrmAbstractOutput *output, bool enable)
{
if (enable) {
checkOutputsAreOn();
if (m_placeHolderOutput && !output->isNonDesktop()) {
qCDebug(KWIN_DRM) << "removing placeholder output";
primaryGpu()->removeVirtualOutput(m_placeHolderOutput);
m_placeHolderOutput = nullptr;
m_placeholderFilter.reset();
}
} else {
const int normalOutputsCount = std::count_if(m_outputs.constBegin(), m_outputs.constEnd(), [](const auto output) {
return output->isEnabled() && !output->isNonDesktop();
});
if (normalOutputsCount == 0 && !output->isNonDesktop() && !kwinApp()->isTerminating()) {
qCDebug(KWIN_DRM) << "adding placeholder output";
m_placeHolderOutput = primaryGpu()->createVirtualOutput({}, output->pixelSize(), 1, DrmVirtualOutput::Type::Placeholder);
// placeholder doesn't actually need to render anything
m_placeHolderOutput->renderLoop()->inhibit();
m_placeholderFilter = std::make_unique<PlaceholderInputEventFilter>();
input()->prependInputEventFilter(m_placeholderFilter.get());
}
}
}
std::unique_ptr<InputBackend> DrmBackend::createInputBackend()
{
return std::make_unique<LibinputBackend>(m_session);
......@@ -428,9 +403,9 @@ QString DrmBackend::supportInformation() const
return supportInfo;
}
Output *DrmBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
Output *DrmBackend::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
{
auto output = primaryGpu()->createVirtualOutput(name, size * scale, scale, DrmVirtualOutput::Type::Virtual);
auto output = primaryGpu()->createVirtualOutput(name, size * scale, scale, type);
Q_EMIT screensQueried();
return output;
}
......
......@@ -11,7 +11,6 @@
#include "platform.h"
#include "dpmsinputeventfilter.h"
#include "drm_placeholderinputeventfilter.h"
#include <QPointer>
#include <QSize>
......@@ -55,15 +54,13 @@ public:
Outputs outputs() const override;
void enableOutput(DrmAbstractOutput *output, bool enable);
void createDpmsFilter();
void checkOutputsAreOn();
QVector<CompositingType> supportedCompositors() const override;
QString supportInformation() const override;
Output *createVirtualOutput(const QString &name, const QSize &size, double scale) override;
Output *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type) override;
void removeVirtualOutput(Output *output) override;
DrmGpu *primaryGpu() const;
......@@ -109,7 +106,6 @@ private:
const QStringList m_explicitGpus;
std::vector<std::unique_ptr<DrmGpu>> m_gpus;
std::unique_ptr<DpmsInputEventFilter> m_dpmsFilter;
std::unique_ptr<PlaceholderInputEventFilter> m_placeholderFilter;
DrmRenderBackend *m_renderBackend = nullptr;
gbm_bo *createBo(const QSize &size, quint32 format, const QVector<uint64_t> &modifiers);
......
......@@ -587,7 +587,7 @@ const QVector<DrmPipeline *> DrmGpu::pipelines() const
return m_pipelines;
}
DrmVirtualOutput *DrmGpu::createVirtualOutput(const QString &name, const QSize &size, double scale, DrmVirtualOutput::Type type)
DrmVirtualOutput *DrmGpu::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
{
auto output = new DrmVirtualOutput(name, this, size, type);
output->setScale(scale);
......
......@@ -74,7 +74,7 @@ public:
bool updateOutputs();
DrmVirtualOutput *createVirtualOutput(const QString &name, const QSize &size, double scale, DrmVirtualOutput::Type type);
DrmVirtualOutput *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type);
void removeVirtualOutput(DrmVirtualOutput *output);
DrmPipeline::Error testPendingConfiguration();
......
......@@ -235,11 +235,6 @@ QList<std::shared_ptr<OutputMode>> DrmOutput::getModes() const
return ret;
}
void DrmOutput::updateEnablement(bool enable)
{
m_gpu->platform()->enableOutput(this, enable);
}
void DrmOutput::setDpmsMode(DpmsMode mode)
{
if (mode == DpmsMode::Off) {
......
......@@ -68,7 +68,6 @@ public:
void setColorTransformation(const std::shared_ptr<ColorTransformation> &transformation) override;
private:
void updateEnablement(bool enable) override;
bool setDrmDpmsMode(DpmsMode mode);
void setDpmsMode(DpmsMode mode) override;
......
......@@ -20,7 +20,7 @@
namespace KWin
{
DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, Type type)
DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, VirtualOutputType type)
: DrmAbstractOutput(gpu)
, m_vsyncMonitor(SoftwareVsyncMonitor::create())
{
......@@ -33,7 +33,7 @@ DrmVirtualOutput::DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize
setInformation(Information{
.name = QStringLiteral("Virtual-") + name,
.physicalSize = size,
.placeholder = type == Type::Placeholder,
.placeholder = type == VirtualOutputType::Placeholder,
});
recreateSurface();
......@@ -63,11 +63,6 @@ void DrmVirtualOutput::setDpmsMode(DpmsMode mode)
setDpmsModeInternal(mode);
}
void DrmVirtualOutput::updateEnablement(bool enable)
{
m_gpu->platform()->enableOutput(this, enable);
}
DrmOutputLayer *DrmVirtualOutput::outputLayer() const
{
return m_layer.get();
......
......@@ -10,6 +10,7 @@
#pragma once
#include "drm_abstract_output.h"
#include "platform.h"
#include <QObject>
#include <QRect>
......@@ -26,12 +27,7 @@ class DrmVirtualOutput : public DrmAbstractOutput
Q_OBJECT
public:
enum class Type {
Virtual,
Placeholder,
};
DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, Type type);
DrmVirtualOutput(const QString &name, DrmGpu *gpu, const QSize &size, VirtualOutputType type);
~DrmVirtualOutput() override;
bool present() override;
......@@ -41,7 +37,6 @@ public:
private:
void vblank(std::chrono::nanoseconds timestamp);
void setDpmsMode(DpmsMode mode) override;
void updateEnablement(bool enable) override;
std::shared_ptr<DrmOutputLayer> m_layer;
bool m_pageFlipPending = true;
......
......@@ -775,11 +775,11 @@ void WaylandBackend::createOutputs()
for (int i = 0; i < initialOutputCount(); i++) {
const QString name = QStringLiteral("WL-%1").arg(i);
createOutput(name, QSize(pixelWidth, pixelHeight));
createOutput(name, QSize(pixelWidth, pixelHeight), false);
}
}
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size)
WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &size, bool placeholder)
{
auto surface = m_compositor->createSurface(this);
if (!surface || !surface->isValid()) {
......@@ -799,7 +799,7 @@ WaylandOutput *WaylandBackend::createOutput(const QString &name, const QSize &si
WaylandOutput *waylandOutput = nullptr;
if (m_xdgShell && m_xdgShell->isValid()) {
waylandOutput = new XdgShellOutput(name, surface, m_xdgShell, this, m_nextId++);
waylandOutput = new XdgShellOutput(name, surface, m_xdgShell, this, m_nextId++, placeholder);
}
if (!waylandOutput) {
......@@ -967,9 +967,9 @@ void WaylandBackend::clearDpmsFilter()
m_dpmsFilter.reset();
}
Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale)
Output *WaylandBackend::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
{
return createOutput(name, size * scale);
return createOutput(name, size * scale, type == VirtualOutputType::Placeholder);
}
void WaylandBackend::removeVirtualOutput(Output *output)
......
......@@ -298,7 +298,7 @@ public:
void createDpmsFilter();
void clearDpmsFilter();
Output *createVirtualOutput(const QString &name, const QSize &size, double scale) override;
Output *createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type) override;
void removeVirtualOutput(Output *output) override;
std::optional<DmaBufParams> testCreateDmaBuf(const QSize &size, quint32 format, const QVector<uint64_t> &modifiers) override;
......@@ -327,7 +327,7 @@ private:
void createOutputs();
void destroyOutputs();
WaylandOutput *createOutput(const QString &name, const QSize &size);
WaylandOutput *createOutput(const QString &name, const QSize &size, bool placeholder);
wl_display *m_display;
KWayland::Client::EventQueue *m_eventQueue;
......
......@@ -24,7 +24,7 @@ namespace Wayland
using namespace KWayland::Client;
static const int s_refreshRate = 60000; // TODO: can we get refresh rate data from Wayland host?
WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBackend *backend)
WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBackend *backend, bool placeholder)
: Output(backend)
, m_renderLoop(std::make_unique<RenderLoop>())
, m_surface(surface)
......@@ -34,6 +34,7 @@ WaylandOutput::WaylandOutput(const QString &name, Surface *surface, WaylandBacke
.name = name,
.model = name,
.capabilities = Capability::Dpms,
.placeholder = placeholder,
});
connect(surface, &Surface::frameRendered, this, &WaylandOutput::frameRendered);
......@@ -90,8 +91,8 @@ void WaylandOutput::setDpmsMode(DpmsMode mode)
}
}
XdgShellOutput::XdgShellOutput(const QString &name, Surface *surface, XdgShell *xdgShell, WaylandBackend *backend, int number)
: WaylandOutput(name, surface, backend)
XdgShellOutput::XdgShellOutput(const QString &name, Surface *surface, XdgShell *xdgShell, WaylandBackend *backend, int number, bool placeholder)
: WaylandOutput(name, surface, backend, placeholder)
, m_number(number)
{
m_xdgShellSurface = xdgShell->createSurface(surface, this);
......
......@@ -39,7 +39,7 @@ class WaylandOutput : public Output
{
Q_OBJECT
public:
WaylandOutput(const QString &name, KWayland::Client::Surface *surface, WaylandBackend *backend);
WaylandOutput(const QString &name, KWayland::Client::Surface *surface, WaylandBackend *backend, bool placeholder);
~WaylandOutput() override;
RenderLoop *renderLoop() const override;
......@@ -89,7 +89,7 @@ public:
XdgShellOutput(const QString &name,
KWayland::Client::Surface *surface,
KWayland::Client::XdgShell *xdgShell,
WaylandBackend *backend, int number);
WaylandBackend *backend, int number, bool placeholder);
~XdgShellOutput() override;
void lockPointer(KWayland::Client::Pointer *pointer, bool lock) override;
......
......@@ -7,7 +7,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "drm_placeholderinputeventfilter.h"
#include "placeholderinputeventfilter.h"
namespace KWin
{
......
......@@ -142,11 +142,12 @@ void Platform::setReady(bool ready)
Q_EMIT readyChanged(m_ready);
}
Output *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale)
Output *Platform::createVirtualOutput(const QString &name, const QSize &size, double scale, VirtualOutputType type)
{
Q_UNUSED(name);
Q_UNUSED(size);
Q_UNUSED(scale);
Q_UNUSED(type);
return nullptr;
}
......
......@@ -40,6 +40,11 @@ class ScreenEdges;
class OutputConfiguration;
struct DmaBufParams;
enum class VirtualOutputType {
Normal,
Placeholder,
};
class KWIN_EXPORT Outputs : public QVector<Output *>
{
public:
......@@ -317,7 +322,7 @@ public:
m_selectedCompositor = type;
}
virtual Output *createVirtualOutput(const QString &name, const QSize &size, qreal scaling);
virtual Output *createVirtualOutput(const QString &name, const QSize &size, qreal scaling, VirtualOutputType type);
virtual void removeVirtualOutput(Output *output);
/**
......
......@@ -110,7 +110,7 @@ void ScreencastManager::streamVirtualOutput(KWaylandServer::ScreencastStreamV1In
double scale,
KWaylandServer::ScreencastV1Interface::CursorMode mode)
{
auto output = kwinApp()->platform()->createVirtualOutput(name, size, scale);
auto output = kwinApp()->platform()->createVirtualOutput(name, size, scale, VirtualOutputType::Normal);
streamOutput(stream, output, mode);
connect(stream, &KWaylandServer::ScreencastStreamV1Interface::finished, output, [output] {
kwinApp()->platform()->removeVirtualOutput(output);
......
......@@ -47,6 +47,7 @@
#endif
#include "decorations/decorationbridge.h"
#include "main.h"
#include "placeholderinputeventfilter.h"
#include "unmanaged.h"
#include "useractions.h"
#include "utils/xcbutils.h"
......@@ -1424,6 +1425,12 @@ void Workspace::addOutput(Output *output)
}
Q_EMIT outputAdded(output);
if (m_placeholderOutput) {
kwinApp()->platform()->removeVirtualOutput(m_placeholderOutput);
m_placeholderOutput = nullptr;
m_placeholderFilter.reset();
}
}
void Workspace::removeOutput(Output *output)
......@@ -1431,6 +1438,14 @@ void Workspace::removeOutput(Output *output)
if (!m_outputs.removeOne(output)) {
return;
}
if (m_outputs.empty()) {
// not all parts of KWin handle having no output yet. To prevent crashes, create a placeholder output
m_placeholderOutput = kwinApp()->platform()->createVirtualOutput("placeholder", output->pixelSize(), output->scale(), VirtualOutputType::Placeholder);
m_placeholderOutput->renderLoop()->inhibit();
// also prevent accidental inputs while the user has no screen connected
m_placeholderFilter = std::make_unique<PlaceholderInputEventFilter>();
input()->prependInputEventFilter(m_placeholderFilter.get());
}
if (m_activeOutput == output) {
m_activeOutput = outputAt(output->geometry().center());
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment