Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit fe63e21f authored by Roman Gilg's avatar Roman Gilg

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
parent 8cf5041e
......@@ -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
......
/********************************************************************
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;
}
}
/********************************************************************
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
......@@ -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.
......
......@@ -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()) {
......
......@@ -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;
}
......
This diff is collapsed.
......@@ -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();
QSize pixelSize() const;
qreal scale() const;
bool commitChanges() override;
/*
* The geometry of this output in global compositor co-ordinates (i.e scaled)
*/
QRect geometry() const;
QSize pixelSize() const override;
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;
......
......@@ -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);
}
......
......@@ -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
......@@ -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);
}
......
......@@ -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;
}
......
......@@ -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)) {
......
......@@ -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 {
......
Markdown is supported
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