Introduce generic Output class

Summary:
In order to separate high-level properties of individual outputs from
hardware-specific ones and access these, introduce a new generic class Output.

Also make the DrmOutput class directly a child class of this generic class.

The long-term goal is to get rid of the Screens global object on Wayland and
instead directly work with Output objects on compositing level.

This should enable us long-term to do direct scanout to hardware planes, what
I predict needs this generic output representation at one point.

Test Plan: Manually.

Reviewers: #kwin

Subscribers: kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D11781
icc-effect-5.14.5
Roman Gilg 2018-03-29 01:27:21 +02:00
parent 8cf5041e69
commit fe63e21f80
14 changed files with 447 additions and 237 deletions

View File

@ -453,6 +453,7 @@ set(kwin_KDEINIT_SRCS
decorations/decorationrenderer.cpp
decorations/decorations_logging.cpp
platform.cpp
abstract_output.cpp
shell_client.cpp
wayland_server.cpp
wayland_cursor_theme.cpp

130
abstract_output.cpp Normal file
View File

@ -0,0 +1,130 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright 2018 Roman Gilg <subdiff@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "abstract_output.h"
#include "wayland_server.h"
// KWayland
#include <KWayland/Server/output_interface.h>
#include <KWayland/Server/outputchangeset.h>
#include <KWayland/Server/outputdevice_interface.h>
#include <KWayland/Server/xdgoutput_interface.h>
// KF5
#include <KLocalizedString>
#include <cmath>
namespace KWin
{
AbstractOutput::AbstractOutput(QObject *parent)
: QObject(parent)
{
}
AbstractOutput::~AbstractOutput()
{
delete m_waylandOutputDevice.data();
delete m_xdgOutput.data();
delete m_waylandOutput.data();
}
QString AbstractOutput::name() const
{
if (!m_waylandOutput) {
return i18n("unknown");
}
return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model());
}
QRect AbstractOutput::geometry() const
{
return QRect(m_globalPos, pixelSize() / scale());
}
QSize AbstractOutput::physicalSize() const
{
if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) {
return m_physicalSize.transposed();
}
return m_physicalSize;
}
void AbstractOutput::setGlobalPos(const QPoint &pos)
{
m_globalPos = pos;
if (m_waylandOutput) {
m_waylandOutput->setGlobalPosition(pos);
}
if (m_waylandOutputDevice) {
m_waylandOutputDevice->setGlobalPosition(pos);
}
if (m_xdgOutput) {
m_xdgOutput->setLogicalPosition(pos);
m_xdgOutput->done();
}
}
void AbstractOutput::setScale(qreal scale)
{
m_scale = scale;
if (m_waylandOutput) {
// this is the scale that clients will ideally use for their buffers
// this has to be an int which is fine
// I don't know whether we want to round or ceil
// or maybe even set this to 3 when we're scaling to 1.5
// don't treat this like it's chosen deliberately
m_waylandOutput->setScale(std::ceil(scale));
}
if (m_waylandOutputDevice) {
m_waylandOutputDevice->setScaleF(scale);
}
if (m_xdgOutput) {
m_xdgOutput->setLogicalSize(pixelSize() / m_scale);
m_xdgOutput->done();
}
}
void AbstractOutput::setChanges(KWayland::Server::OutputChangeSet *changes)
{
m_changeset = changes;
qCDebug(KWIN_CORE) << "set changes in AbstractOutput";
commitChanges();
}
void AbstractOutput::setWaylandOutput(KWayland::Server::OutputInterface *set)
{
m_waylandOutput = set;
}
void AbstractOutput::createXdgOutput()
{
if (!m_waylandOutput || m_xdgOutput) {
return;
}
m_xdgOutput = waylandServer()->xdgOutputManager()->createXdgOutput(m_waylandOutput, m_waylandOutput);
}
void AbstractOutput::setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set)
{
m_waylandOutputDevice = set;
}
}

146
abstract_output.h Normal file
View File

@ -0,0 +1,146 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright 2018 Roman Gilg <subdiff@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_OUTPUT_H
#define KWIN_OUTPUT_H
#include <utils.h>
#include <kwin_export.h>
#include <QObject>
#include <QPoint>
#include <QPointer>
#include <QRect>
#include <QSize>
#include <QVector>
namespace KWayland
{
namespace Server
{
class OutputInterface;
class OutputDeviceInterface;
class OutputChangeSet;
class OutputManagementInterface;
class XdgOutputInterface;
}
}
namespace KWin
{
/**
* Generic output representation in a Wayland session
**/
class KWIN_EXPORT AbstractOutput : public QObject
{
Q_OBJECT
public:
explicit AbstractOutput(QObject *parent = nullptr);
virtual ~AbstractOutput();
QString name() const;
bool isEnabled() const {
return !m_waylandOutput.isNull();
}
virtual QSize pixelSize() const = 0;
qreal scale() const {
return m_scale;
}
/*
* The geometry of this output in global compositor co-ordinates (i.e scaled)
*/
QRect geometry() const;
QSize physicalSize() const;
Qt::ScreenOrientation orientation() const {
return m_orientation;
}
bool isInternal() const {
return m_internal;
}
void setGlobalPos(const QPoint &pos);
void setScale(qreal scale);
/**
* This sets the changes and tests them against the specific output
*/
void setChanges(KWayland::Server::OutputChangeSet *changeset);
virtual bool commitChanges() { return false; }
QPointer<KWayland::Server::OutputInterface> waylandOutput() const {
return m_waylandOutput;
}
protected:
QPointer<KWayland::Server::OutputChangeSet> changes() const {
return m_changeset;
}
void setWaylandOutput(KWayland::Server::OutputInterface *set);
QPointer<KWayland::Server::XdgOutputInterface> xdgOutput() const {
return m_xdgOutput;
}
void createXdgOutput();
QPointer<KWayland::Server::OutputDeviceInterface> waylandOutputDevice() const {
return m_waylandOutputDevice;
}
void setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set);
QPoint globalPos() const {
return m_globalPos;
}
QSize rawPhysicalSize() const {
return m_physicalSize;
}
void setRawPhysicalSize(const QSize &set) {
m_physicalSize = set;
}
void setOrientation(Qt::ScreenOrientation set) {
m_orientation = set;
}
bool internal() const {
return m_internal;
}
void setInternal(bool set) {
m_internal = set;
}
private:
QPointer<KWayland::Server::OutputChangeSet> m_changeset;
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
QPointer<KWayland::Server::XdgOutputInterface> m_xdgOutput;
QPointer<KWayland::Server::OutputDeviceInterface> m_waylandOutputDevice;
QPoint m_globalPos;
qreal m_scale = 1;
QSize m_physicalSize;
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
bool m_internal = false;
};
}
#endif // KWIN_OUTPUT_H

View File

@ -45,6 +45,7 @@ class Manager;
struct GammaRamp;
}
class AbstractOutput;
class Edge;
class Compositor;
class OverlayWindow;
@ -64,6 +65,17 @@ class Renderer;
class DecoratedClientImpl;
}
class KWIN_EXPORT Outputs : public QVector<AbstractOutput*>
{
public:
Outputs(){};
template <typename T>
Outputs(const QVector<T> &other) {
resize(other.size());
std::copy(other.constBegin(), other.constEnd(), begin());
}
};
class KWIN_EXPORT Platform : public QObject
{
Q_OBJECT
@ -411,6 +423,15 @@ public:
return false;
}
// outputs with connections (org_kde_kwin_outputdevice)
virtual Outputs outputs() const {
return Outputs();
}
// actively compositing outputs (wl_output)
virtual Outputs enabledOutputs() const {
return Outputs();
}
/*
* A string of information to include in kwin debug output
* It should not be translated.

View File

@ -49,6 +49,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QSocketNotifier>
#include <QPainter>
// system
#include <algorithm>
#include <unistd.h>
// drm
#include <xf86drm.h>
@ -90,7 +91,11 @@ DrmBackend::~DrmBackend()
while (m_pageFlipsPending != 0) {
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
// we need to first remove all outputs
qDeleteAll(m_outputs);
m_outputs.clear();
m_enabledOutputs.clear();
qDeleteAll(m_planes);
qDeleteAll(m_crtcs);
qDeleteAll(m_connectors);
@ -116,6 +121,16 @@ void DrmBackend::init()
}
}
Outputs DrmBackend::outputs() const
{
return m_outputs;
}
Outputs DrmBackend::enabledOutputs() const
{
return m_enabledOutputs;
}
void DrmBackend::outputWentOff()
{
if (!m_dpmsFilter.isNull()) {

View File

@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QImage>
#include <QPointer>
#include <QSize>
#include <QVector>
#include <xf86drmMode.h>
#include <memory>
@ -93,12 +94,15 @@ public:
int fd() const {
return m_fd;
}
QVector<DrmOutput*> outputs() const {
Outputs outputs() const override;
Outputs enabledOutputs() const override;
QVector<DrmOutput*> drmOutputs() const {
return m_outputs;
}
QVector<DrmOutput*> enabledOutputs() const {
QVector<DrmOutput*> drmEnabledOutputs() const {
return m_enabledOutputs;
}
QVector<DrmPlane*> planes() const {
return m_planes;
}

View File

@ -36,7 +36,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Server/display.h>
#include <KWayland/Server/output_interface.h>
#include <KWayland/Server/outputchangeset.h>
#include <KWayland/Server/outputdevice_interface.h>
#include <KWayland/Server/outputmanagement_interface.h>
#include <KWayland/Server/outputconfiguration_interface.h>
#include <KWayland/Server/xdgoutput_interface.h>
@ -53,13 +52,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <xf86drmMode.h>
#include <libdrm/drm_mode.h>
#include <cmath>
namespace KWin
{
DrmOutput::DrmOutput(DrmBackend *backend)
: QObject()
: AbstractOutput(backend)
, m_backend(backend)
{
}
@ -91,8 +88,6 @@ void DrmOutput::teardown()
m_crtc->setOutput(nullptr);
m_conn->setOutput(nullptr);
delete m_waylandOutput.data();
delete m_waylandOutputDevice.data();
delete m_cursor[0];
delete m_cursor[1];
if (!m_pageFlipPending) {
@ -146,11 +141,11 @@ void DrmOutput::updateCursor()
m_hasNewCursor = true;
QImage *c = m_cursor[m_cursorIndex]->image();
c->fill(Qt::transparent);
c->setDevicePixelRatio(m_scale);
c->setDevicePixelRatio(scale());
QPainter p;
p.begin(c);
if (m_orientation == Qt::InvertedLandscapeOrientation) {
if (orientation() == Qt::InvertedLandscapeOrientation) {
QMatrix4x4 matrix;
matrix.translate(cursorImage.width() / 2.0, cursorImage.height() / 2.0);
matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f);
@ -165,7 +160,7 @@ void DrmOutput::moveCursor(const QPoint &globalPos)
{
QMatrix4x4 matrix;
QMatrix4x4 hotspotMatrix;
if (m_orientation == Qt::InvertedLandscapeOrientation) {
if (orientation() == Qt::InvertedLandscapeOrientation) {
matrix.translate(pixelSize().width() /2.0, pixelSize().height() / 2.0);
matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f);
matrix.translate(-pixelSize().width() /2.0, -pixelSize().height() / 2.0);
@ -174,39 +169,23 @@ void DrmOutput::moveCursor(const QPoint &globalPos)
hotspotMatrix.rotate(180.0f, 0.0f, 0.0f, 1.0f);
hotspotMatrix.translate(-cursorSize.width()/2.0, -cursorSize.height()/2.0);
}
hotspotMatrix.scale(m_scale);
matrix.scale(m_scale);
matrix.translate(-m_globalPos.x(), -m_globalPos.y());
hotspotMatrix.scale(scale());
matrix.scale(scale());
const auto outputGlobalPos = AbstractOutput::globalPos();
matrix.translate(-outputGlobalPos.x(), -outputGlobalPos.y());
const QPoint p = matrix.map(globalPos) - hotspotMatrix.map(m_backend->softwareCursorHotspot());
drmModeMoveCursor(m_backend->fd(), m_crtc->id(), p.x(), p.y());
}
QSize DrmOutput::pixelSize() const
{
if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) {
auto orient = orientation();
if (orient == Qt::PortraitOrientation || orient == Qt::InvertedPortraitOrientation) {
return QSize(m_mode.vdisplay, m_mode.hdisplay);
}
return QSize(m_mode.hdisplay, m_mode.vdisplay);
}
QSize DrmOutput::physicalSize() const
{
if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) {
return QSize(m_physicalSize.height(), m_physicalSize.width());
}
return m_physicalSize;
}
QRect DrmOutput::geometry() const
{
return QRect(m_globalPos, pixelSize() / m_scale);
}
qreal DrmOutput::scale() const
{
return m_scale;
}
void DrmOutput::setEnabled(bool enabled)
{
if (enabled == isEnabled()) {
@ -217,17 +196,12 @@ void DrmOutput::setEnabled(bool enabled)
initOutput();
} else {
setDpms(DpmsMode::Off);
delete m_waylandOutput.data();
delete waylandOutput().data();
}
m_waylandOutputDevice->setEnabled(enabled ?
waylandOutputDevice()->setEnabled(enabled ?
KWayland::Server::OutputDeviceInterface::Enablement::Enabled : KWayland::Server::OutputDeviceInterface::Enablement::Disabled);
}
bool DrmOutput::isEnabled() const
{
return !m_waylandOutput.isNull();
}
static KWayland::Server::OutputInterface::DpmsMode toWaylandDpmsMode(DrmOutput::DpmsMode mode)
{
using namespace KWayland::Server;
@ -314,9 +288,9 @@ bool DrmOutput::init(drmModeConnector *connector)
return false;
}
m_internal = connector->connector_type == DRM_MODE_CONNECTOR_LVDS || connector->connector_type == DRM_MODE_CONNECTOR_eDP;
setInternal(connector->connector_type == DRM_MODE_CONNECTOR_LVDS || connector->connector_type == DRM_MODE_CONNECTOR_eDP);
if (m_internal) {
if (internal()) {
connect(kwinApp(), &Application::screensCreated, this,
[this] {
connect(screens()->orientationSensor(), &OrientationSensor::orientationChanged, this, &DrmOutput::automaticRotation);
@ -336,7 +310,7 @@ bool DrmOutput::init(drmModeConnector *connector)
qCWarning(KWIN_DRM) << "Overwriting monitor physical size for" << m_edid.eisaId << "/" << m_edid.monitorName << "/" << m_edid.serialNumber << " from " << physicalSize << "to " << overwriteSize;
physicalSize = overwriteSize;
}
m_physicalSize = physicalSize;
setRawPhysicalSize(physicalSize);
initOutputDevice(connector);
@ -356,41 +330,48 @@ void DrmOutput::initUuid()
void DrmOutput::initOutput()
{
Q_ASSERT(m_waylandOutputDevice);
if (!m_waylandOutput.isNull()) {
delete m_waylandOutput.data();
m_waylandOutput.clear();
auto wlOutputDevice = waylandOutputDevice();
Q_ASSERT(wlOutputDevice);
auto wlOutput = waylandOutput();
if (!wlOutput.isNull()) {
delete wlOutput.data();
wlOutput.clear();
}
m_waylandOutput = waylandServer()->display()->createOutput();
m_xdgOutput = waylandServer()->xdgOutputManager()->createXdgOutput(m_waylandOutput, m_waylandOutput);
wlOutput = waylandServer()->display()->createOutput();
setWaylandOutput(wlOutput.data());
createXdgOutput();
connect(this, &DrmOutput::modeChanged, this,
[this] {
if (m_waylandOutput.isNull()) {
auto wlOutput = waylandOutput();
if (wlOutput.isNull()) {
return;
}
m_waylandOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay), refreshRateForMode(&m_mode));
if (m_xdgOutput) {
m_xdgOutput->setLogicalSize(pixelSize() / m_scale);
m_xdgOutput->done();
wlOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay),
refreshRateForMode(&m_mode));
auto xdg = xdgOutput();
if (xdg) {
xdg->setLogicalSize(pixelSize() / scale());
xdg->done();
}
}
);
m_waylandOutput->setManufacturer(m_waylandOutputDevice->manufacturer());
m_waylandOutput->setModel(m_waylandOutputDevice->model());
m_waylandOutput->setPhysicalSize(m_physicalSize);
wlOutput->setManufacturer(wlOutputDevice->manufacturer());
wlOutput->setModel(wlOutputDevice->model());
wlOutput->setPhysicalSize(rawPhysicalSize());
// set dpms
if (!m_dpms.isNull()) {
m_waylandOutput->setDpmsSupported(true);
m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode));
connect(m_waylandOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this,
wlOutput->setDpmsSupported(true);
wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode));
connect(wlOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this,
[this] (KWayland::Server::OutputInterface::DpmsMode mode) {
setDpms(fromWaylandDpmsMode(mode));
}, Qt::QueuedConnection
);
}
for(const auto &mode: m_waylandOutputDevice->modes()) {
for(const auto &mode: wlOutputDevice->modes()) {
KWayland::Server::OutputInterface::ModeFlags flags;
if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Current) {
flags |= KWayland::Server::OutputInterface::ModeFlag::Current;
@ -398,25 +379,26 @@ void DrmOutput::initOutput()
if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred) {
flags |= KWayland::Server::OutputInterface::ModeFlag::Preferred;
}
m_waylandOutput->addMode(mode.size, flags, mode.refreshRate);
wlOutput->addMode(mode.size, flags, mode.refreshRate);
}
m_waylandOutput->create();
wlOutput->create();
}
void DrmOutput::initOutputDevice(drmModeConnector *connector)
{
if (!m_waylandOutputDevice.isNull()) {
delete m_waylandOutputDevice.data();
m_waylandOutputDevice.clear();
auto wlOutputDevice = waylandOutputDevice();
if (!wlOutputDevice.isNull()) {
delete wlOutputDevice.data();
wlOutputDevice.clear();
}
m_waylandOutputDevice = waylandServer()->display()->createOutputDevice();
m_waylandOutputDevice->setUuid(m_uuid);
wlOutputDevice = waylandServer()->display()->createOutputDevice();
wlOutputDevice->setUuid(m_uuid);
if (!m_edid.eisaId.isEmpty()) {
m_waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId));
wlOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId));
} else {
m_waylandOutputDevice->setManufacturer(i18n("unknown"));
wlOutputDevice->setManufacturer(i18n("unknown"));
}
QString connectorName = s_connectorNames.value(connector->connector_type, QByteArrayLiteral("Unknown"));
@ -435,9 +417,9 @@ void DrmOutput::initOutputDevice(drmModeConnector *connector)
modelName = i18n("unknown");
}
m_waylandOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName);
wlOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName);
m_waylandOutputDevice->setPhysicalSize(m_physicalSize);
wlOutputDevice->setPhysicalSize(rawPhysicalSize());
// read in mode information
for (int i = 0; i < connector->count_modes; ++i) {
@ -460,9 +442,10 @@ void DrmOutput::initOutputDevice(drmModeConnector *connector)
mode.flags = deviceflags;
mode.refreshRate = refreshRate;
qCDebug(KWIN_DRM) << "Adding mode: " << i << mode.size;
m_waylandOutputDevice->addMode(mode);
wlOutputDevice->addMode(mode);
}
m_waylandOutputDevice->create();
wlOutputDevice->create();
setWaylandOutputDevice(wlOutputDevice.data());
}
bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const
@ -757,8 +740,9 @@ void DrmOutput::dpmsOnHandler()
{
qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to On.";
if (m_waylandOutput) {
m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending));
auto wlOutput = waylandOutput();
if (wlOutput) {
wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending));
}
emit dpmsChanged();
@ -775,168 +759,124 @@ void DrmOutput::dpmsOffHandler()
{
qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to Off.";
if (m_waylandOutput) {
m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending));
auto wlOutput = waylandOutput();
if (wlOutput) {
wlOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending));
}
emit dpmsChanged();
m_backend->outputWentOff();
}
QString DrmOutput::name() const
{
if (!m_waylandOutput) {
return i18n("unknown");
}
return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model());
}
int DrmOutput::currentRefreshRate() const
{
if (!m_waylandOutput) {
auto wlOutput = waylandOutput();
if (!wlOutput) {
return 60000;
}
return m_waylandOutput->refreshRate();
}
void DrmOutput::setGlobalPos(const QPoint &pos)
{
m_globalPos = pos;
if (m_waylandOutput) {
m_waylandOutput->setGlobalPosition(pos);
}
if (m_waylandOutputDevice) {
m_waylandOutputDevice->setGlobalPosition(pos);
}
if (m_xdgOutput) {
m_xdgOutput->setLogicalPosition(pos);
m_xdgOutput->done();
}
}
void DrmOutput::setScale(qreal scale)
{
m_scale = scale;
if (m_waylandOutput) {
// this is the scale that clients will ideally use for their buffers
// this has to be an int which is fine
// I don't know whether we want to round or ceil
// or maybe even set this to 3 when we're scaling to 1.5
// don't treat this like it's chosen deliberately
m_waylandOutput->setScale(std::ceil(scale));
}
if (m_waylandOutputDevice) {
m_waylandOutputDevice->setScaleF(scale);
}
if (m_xdgOutput) {
m_xdgOutput->setLogicalSize(pixelSize() / m_scale);
m_xdgOutput->done();
}
}
void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes)
{
m_changeset = changes;
qCDebug(KWIN_DRM) << "set changes in DrmOutput";
commitChanges();
return wlOutput->refreshRate();
}
bool DrmOutput::commitChanges()
{
Q_ASSERT(!m_waylandOutputDevice.isNull());
auto wlOutputDevice = waylandOutputDevice();
Q_ASSERT(!wlOutputDevice.isNull());
if (m_changeset.isNull()) {
auto changeset = changes();
if (changeset.isNull()) {
qCDebug(KWIN_DRM) << "no changes";
// No changes to an output is an entirely valid thing
return true;
}
//enabledChanged is handled by drmbackend
if (m_changeset->modeChanged()) {
qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode();
m_waylandOutputDevice->setCurrentMode(m_changeset->mode());
updateMode(m_changeset->mode());
if (changeset->modeChanged()) {
qCDebug(KWIN_DRM) << "Setting new mode:" << changeset->mode();
wlOutputDevice->setCurrentMode(changeset->mode());
updateMode(changeset->mode());
}
if (m_changeset->transformChanged()) {
qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(m_changeset->transform());
transform(m_changeset->transform());
if (changeset->transformChanged()) {
qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(changeset->transform());
transform(changeset->transform());
}
if (m_changeset->positionChanged()) {
qCDebug(KWIN_DRM) << "Server setting position: " << m_changeset->position();
setGlobalPos(m_changeset->position());
if (changeset->positionChanged()) {
qCDebug(KWIN_DRM) << "Server setting position: " << changeset->position();
setGlobalPos(changeset->position());
// may just work already!
}
if (m_changeset->scaleChanged()) {
qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale();
setScale(m_changeset->scaleF());
if (changeset->scaleChanged()) {
qCDebug(KWIN_DRM) << "Setting scale:" << changeset->scale();
setScale(changeset->scaleF());
}
return true;
}
void DrmOutput::transform(KWayland::Server::OutputDeviceInterface::Transform transform)
{
m_waylandOutputDevice->setTransform(transform);
waylandOutputDevice()->setTransform(transform);
using KWayland::Server::OutputDeviceInterface;
using KWayland::Server::OutputInterface;
auto wlOutput = waylandOutput();
switch (transform) {
case OutputDeviceInterface::Transform::Normal:
if (m_primaryPlane) {
m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate0);
}
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Normal);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Normal);
}
m_orientation = Qt::PrimaryOrientation;
setOrientation(Qt::PrimaryOrientation);
break;
case OutputDeviceInterface::Transform::Rotated90:
if (m_primaryPlane) {
m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate90);
}
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Rotated90);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Rotated90);
}
m_orientation = Qt::PortraitOrientation;
setOrientation(Qt::PortraitOrientation);
break;
case OutputDeviceInterface::Transform::Rotated180:
if (m_primaryPlane) {
m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate180);
}
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Rotated180);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Rotated180);
}
m_orientation = Qt::InvertedLandscapeOrientation;
setOrientation(Qt::InvertedLandscapeOrientation);
break;
case OutputDeviceInterface::Transform::Rotated270:
if (m_primaryPlane) {
m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate270);
}
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Rotated270);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Rotated270);
}
m_orientation = Qt::InvertedPortraitOrientation;
setOrientation(Qt::InvertedPortraitOrientation);
break;
case OutputDeviceInterface::Transform::Flipped:
// TODO: what is this exactly?
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Flipped);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Flipped);
}
break;
case OutputDeviceInterface::Transform::Flipped90:
// TODO: what is this exactly?
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Flipped90);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Flipped90);
}
break;
case OutputDeviceInterface::Transform::Flipped180:
// TODO: what is this exactly?
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Flipped180);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Flipped180);
}
break;
case OutputDeviceInterface::Transform::Flipped270:
// TODO: what is this exactly?
if (m_waylandOutput) {
m_waylandOutput->setTransform(OutputInterface::Transform::Flipped270);
if (wlOutput) {
wlOutput->setTransform(OutputInterface::Transform::Flipped270);
}
break;
}
@ -1070,7 +1010,7 @@ bool DrmOutput::presentAtomically(DrmBuffer *buffer)
// go back to previous state
if (m_lastWorkingState.valid) {
m_mode = m_lastWorkingState.mode;
m_orientation = m_lastWorkingState.orientation;
setOrientation(m_lastWorkingState.orientation);
setGlobalPos(m_lastWorkingState.globalPos);
if (m_primaryPlane) {
m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations);
@ -1094,8 +1034,8 @@ bool DrmOutput::presentAtomically(DrmBuffer *buffer)
if (wasModeset) {
// store current mode set as new good state
m_lastWorkingState.mode = m_mode;
m_lastWorkingState.orientation = m_orientation;
m_lastWorkingState.globalPos = m_globalPos;
m_lastWorkingState.orientation = orientation();
m_lastWorkingState.globalPos = globalPos();
if (m_primaryPlane) {
m_lastWorkingState.planeTransformations = m_primaryPlane->transformation();
}

View File

@ -20,31 +20,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_DRM_OUTPUT_H
#define KWIN_DRM_OUTPUT_H
#include "abstract_output.h"
#include "drm_pointer.h"
#include "drm_object.h"
#include "drm_object_plane.h"
#include <QObject>
#include <QPoint>
#include <QPointer>
#include <QSize>
#include <QVector>
#include <xf86drmMode.h>
#include <KWayland/Server/outputdevice_interface.h>
namespace KWayland
{
namespace Server
{
class OutputInterface;
class OutputDeviceInterface;
class OutputChangeSet;
class OutputManagementInterface;
class XdgOutputInterface;
}
}
namespace KWin
{
@ -55,7 +43,7 @@ class DrmPlane;
class DrmConnector;
class DrmCrtc;
class DrmOutput : public QObject
class KWIN_EXPORT DrmOutput : public AbstractOutput
{
Q_OBJECT
public:
@ -86,23 +74,11 @@ public:
* The default is on
*/
void setEnabled(bool enabled);
bool isEnabled() const;
/**
* This sets the changes and tests them against the DRM output
*/
void setChanges(KWayland::Server::OutputChangeSet *changeset);
bool commitChanges();
bool commitChanges() override;
QSize pixelSize() const;
qreal scale() const;
QSize pixelSize() const override;
/*
* The geometry of this output in global compositor co-ordinates (i.e scaled)
*/
QRect geometry() const;
QString name() const;
int currentRefreshRate() const;
// These values are defined by the kernel
enum class DpmsMode {
@ -121,24 +97,10 @@ public:
return m_uuid;
}
QSize physicalSize() const;
bool initCursor(const QSize &cursorSize);
bool supportsTransformations() const;
bool isInternal() const {
return m_internal;
}
Qt::ScreenOrientation orientation() const {
return m_orientation;
}
const QPointer<KWayland::Server::OutputInterface> getWaylandInterface() const {
return m_waylandOutput;
}
Q_SIGNALS:
void dpmsChanged();
void modeChanged();
@ -165,8 +127,6 @@ private:
bool isCurrentMode(const drmModeModeInfo *mode) const;
void initUuid();
void setGlobalPos(const QPoint &pos);
void setScale(qreal scale);
void initOutput();
bool initPrimaryPlane();
bool initCursorPlane();
@ -183,15 +143,9 @@ private:
DrmBackend *m_backend;
DrmConnector *m_conn = nullptr;
DrmCrtc *m_crtc = nullptr;
QPoint m_globalPos;
qreal m_scale = 1;
bool m_lastGbm = false;
drmModeModeInfo m_mode;
Edid m_edid;
QPointer<KWayland::Server::OutputInterface> m_waylandOutput;
QPointer<KWayland::Server::XdgOutputInterface> m_xdgOutput;
QPointer<KWayland::Server::OutputDeviceInterface> m_waylandOutputDevice;
QPointer<KWayland::Server::OutputChangeSet> m_changeset;
KWin::ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms;
DpmsMode m_dpmsMode = DpmsMode::On;
DpmsMode m_dpmsModePending = DpmsMode::On;
@ -204,8 +158,6 @@ private:
bool m_pageFlipPending = false;
bool m_dpmsAtomicOffPending = false;
bool m_modesetRequested = true;
QSize m_physicalSize;
Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation;
struct {
Qt::ScreenOrientation orientation;

View File

@ -141,7 +141,7 @@ bool EglGbmBackend::initRenderingContext()
return false;
}
const auto outputs = m_backend->outputs();
const auto outputs = m_backend->drmOutputs();
for (DrmOutput *drmOutput: outputs) {
createOutput(drmOutput);
}

View File

@ -82,7 +82,7 @@ void RemoteAccessManager::passBuffer(DrmOutput *output, DrmBuffer *buffer)
buf->setStride(gbm_bo_get_stride(bo));
buf->setFormat(gbm_bo_get_format(bo));
m_interface->sendBufferReady(output->getWaylandInterface().data(), buf);
m_interface->sendBufferReady(output->waylandOutput().data(), buf);
}
} // KWin namespace

View File

@ -30,7 +30,7 @@ DrmQPainterBackend::DrmQPainterBackend(DrmBackend *backend)
, QPainterBackend()
, m_backend(backend)
{
const auto outputs = m_backend->outputs();
const auto outputs = m_backend->drmOutputs();
for (auto output: outputs) {
initOutput(output);
}

View File

@ -70,16 +70,17 @@ QSize DrmScreens::size(int screen) const
void DrmScreens::updateCount()
{
setCount(m_backend->enabledOutputs().size());
setCount(m_backend->drmEnabledOutputs().size());
}
int DrmScreens::number(const QPoint &pos) const
{
int bestScreen = 0;
int minDistance = INT_MAX;
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
for (int i = 0; i < outputs.size(); ++i) {
const QRect &geo = outputs.at(i)->geometry();
auto o = outputs.at(i);
const QRect &geo = o->geometry();
if (geo.contains(pos)) {
return i;
}
@ -97,7 +98,7 @@ int DrmScreens::number(const QPoint &pos) const
QString DrmScreens::name(int screen) const
{
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
if (screen >= outputs.size()) {
return Screens::name(screen);
}
@ -106,7 +107,7 @@ QString DrmScreens::name(int screen) const
float DrmScreens::refreshRate(int screen) const
{
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
if (screen >= outputs.size()) {
return Screens::refreshRate(screen);
}
@ -115,7 +116,7 @@ float DrmScreens::refreshRate(int screen) const
QSizeF DrmScreens::physicalSize(int screen) const
{
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
if (screen >= outputs.size()) {
return Screens::physicalSize(screen);
}
@ -124,7 +125,7 @@ QSizeF DrmScreens::physicalSize(int screen) const
bool DrmScreens::isInternal(int screen) const
{
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
if (screen >= outputs.size()) {
return false;
}
@ -133,7 +134,7 @@ bool DrmScreens::isInternal(int screen) const
bool DrmScreens::supportsTransformations(int screen) const
{
const auto outputs = m_backend->enabledOutputs();
const auto outputs = m_backend->drmEnabledOutputs();
if (screen >= outputs.size()) {
return false;
}
@ -142,7 +143,7 @@ bool DrmScreens::supportsTransformations(int screen) const
Qt::ScreenOrientation DrmScreens::orientation(int screen) const
{
const auto outputs = m_backend->outputs();
const auto outputs = m_backend->drmOutputs();
if (screen >= outputs.size()) {
return Qt::PrimaryOrientation;
}

View File

@ -52,7 +52,7 @@ void VirtualScreens::init()
QRect VirtualScreens::geometry(int screen) const
{
const auto outputs = m_backend->outputs();
const auto outputs = m_backend->virtualOutputs();
if (screen >= outputs.size()) {
return QRect();
}
@ -73,7 +73,7 @@ int VirtualScreens::number(const QPoint &pos) const
{
int bestScreen = 0;
int minDistance = INT_MAX;
const auto outputs = m_backend->outputs();
const auto outputs = m_backend->virtualOutputs();
for (int i = 0; i < outputs.size(); ++i) {
const QRect &geo = outputs.at(i)->geometry();
if (geo.contains(pos)) {

View File

@ -48,7 +48,7 @@ public:
int outputCount() const {
return m_outputs.size();
}
const QVector<VirtualOutput*> outputs() const {
const QVector<VirtualOutput*> virtualOutputs() const {
return m_outputs;
}
qreal outputScale() const {