[platforms/hwcomposer] Port to AbstractOutput

Summary:
This gives us XdgOutput support a requirement now that wayland server
reports that we support it and Qt5.12 then expects it to be sent.

It also provides an easy starting point for supporting wayland scaling
and a slight step towards multi-output.

Test Plan:
Ran on phone. Got output. Turning screen on and off works.
The double tap doesn't work great, but that was true before
(via bshah's hack to build on the current state)

Reviewers: #kwin, romangg

Reviewed By: #kwin, romangg

Subscribers: romangg, nicolasfella, zzag, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D18808
This commit is contained in:
David Edmundson 2019-02-20 13:19:51 +00:00
parent 3cdea2f77c
commit 062dfefafe
4 changed files with 141 additions and 100 deletions

View file

@ -26,8 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "main.h"
#include "wayland_server.h"
// KWayland
#include <KWayland/Server/display.h>
#include <KWayland/Server/seat_interface.h>
#include <KWayland/Server/output_interface.h>
// Qt
#include <QKeyEvent>
#include <QDBusConnection>
@ -39,6 +38,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// based on test_hwcomposer.c from libhybris project (Apache 2 licensed)
using namespace KWayland::Server;
namespace KWin
{
@ -157,50 +158,6 @@ HwcomposerBackend::~HwcomposerBackend()
if (!m_outputBlank) {
toggleBlankOutput();
}
if (m_device) {
hwc_close_1(m_device);
}
}
KWayland::Server::OutputInterface* HwcomposerBackend::createOutput(hwc_composer_device_1_t *device)
{
uint32_t configs[5];
size_t numConfigs = 5;
if (device->getDisplayConfigs(device, 0, configs, &numConfigs) != 0) {
qCWarning(KWIN_HWCOMPOSER) << "Failed to get hwcomposer display configurations";
return nullptr;
}
int32_t attr_values[5];
uint32_t attributes[] = {
HWC_DISPLAY_WIDTH,
HWC_DISPLAY_HEIGHT,
HWC_DISPLAY_DPI_X,
HWC_DISPLAY_DPI_Y,
HWC_DISPLAY_VSYNC_PERIOD ,
HWC_DISPLAY_NO_ATTRIBUTE
};
device->getDisplayAttributes(device, 0, configs[0], attributes, attr_values);
QSize pixel(attr_values[0], attr_values[1]);
if (pixel.isEmpty()) {
return nullptr;
}
using namespace KWayland::Server;
OutputInterface *o = waylandServer()->display()->createOutput(waylandServer()->display());
o->addMode(pixel, OutputInterface::ModeFlag::Current | OutputInterface::ModeFlag::Preferred, (attr_values[4] == 0) ? 60000 : 10E11/attr_values[4]);
if (attr_values[2] != 0 && attr_values[3] != 0) {
static const qreal factor = 25.4;
m_physicalSize = QSizeF(qreal(pixel.width() * 1000) / qreal(attr_values[2]) * factor,
qreal(pixel.height() * 1000) / qreal(attr_values[3]) * factor);
o->setPhysicalSize(m_physicalSize.toSize());
} else {
// couldn't read physical size, assume 96 dpi
o->setPhysicalSize(pixel / 3.8);
}
o->create();
return o;
}
void HwcomposerBackend::init()
@ -249,31 +206,35 @@ void HwcomposerBackend::init()
};
m_device->registerProcs(m_device, procs);
//move to HwcomposerOutput + signal
initLights();
toggleBlankOutput();
m_filter.reset(new BacklightInputEventFilter(this));
input()->prependInputEventFilter(m_filter.data());
// get display configuration
auto output = createOutput(hwcDevice);
if (!output) {
m_output.reset(new HwcomposerOutput(hwcDevice));
if (!m_output->isValid()) {
emit initFailed();
return;
}
m_displaySize = output->pixelSize();
m_refreshRate = output->refreshRate();
if (m_refreshRate != 0) {
m_vsyncInterval = 1000000/m_refreshRate;
if (m_output->refreshRate() != 0) {
m_vsyncInterval = 1000000/m_output->refreshRate();
}
if (m_lights) {
using namespace KWayland::Server;
output->setDpmsSupported(true);
auto updateDpms = [this, output] {
output->setDpmsMode(m_outputBlank ? OutputInterface::DpmsMode::Off : OutputInterface::DpmsMode::On);
auto updateDpms = [this] {
if (!m_output || !m_output->waylandOutput()) {
m_output->waylandOutput()->setDpmsMode(m_outputBlank ? OutputInterface::DpmsMode::Off : OutputInterface::DpmsMode::On);
}
};
updateDpms();
connect(this, &HwcomposerBackend::outputBlankChanged, this, updateDpms);
connect(output, &OutputInterface::dpmsModeRequested, this,
connect(m_output.data(), &HwcomposerOutput::dpmsModeRequested, this,
[this] (KWayland::Server::OutputInterface::DpmsMode mode) {
if (mode == OutputInterface::DpmsMode::On) {
if (m_outputBlank) {
@ -287,13 +248,19 @@ void HwcomposerBackend::init()
}
);
}
qCDebug(KWIN_HWCOMPOSER) << "Display size:" << m_displaySize;
qCDebug(KWIN_HWCOMPOSER) << "Refresh rate:" << m_refreshRate;
emit screensQueried();
setReady(true);
}
QSize HwcomposerBackend::screenSize() const
{
if (m_output) {
return m_output->pixelSize();
}
return QSize();
}
void HwcomposerBackend::initLights()
{
hw_module_t *lightsModule = nullptr;
@ -372,6 +339,20 @@ Screens *HwcomposerBackend::createScreens(QObject *parent)
return new HwcomposerScreens(this, parent);
}
Outputs HwcomposerBackend::outputs() const
{
if (!m_output.isNull()) {
return QVector<HwcomposerOutput*>({m_output.data()});
}
return {};
}
Outputs HwcomposerBackend::enabledOutputs() const
{
return outputs();
}
OpenGLBackend *HwcomposerBackend::createOpenGLBackend()
{
return new EglHwcomposerBackend(this);
@ -482,4 +463,74 @@ void HwcomposerWindow::present(HWComposerNativeWindowBuffer *buffer)
m_list[0]->flags = 0;
}
HwcomposerOutput::HwcomposerOutput(hwc_composer_device_1_t *device)
: AbstractOutput()
, m_device(device)
{
uint32_t configs[5];
size_t numConfigs = 5;
if (device->getDisplayConfigs(device, 0, configs, &numConfigs) != 0) {
qCWarning(KWIN_HWCOMPOSER) << "Failed to get hwcomposer display configurations";
return;
}
int32_t attr_values[5];
uint32_t attributes[] = {
HWC_DISPLAY_WIDTH,
HWC_DISPLAY_HEIGHT,
HWC_DISPLAY_DPI_X,
HWC_DISPLAY_DPI_Y,
HWC_DISPLAY_VSYNC_PERIOD ,
HWC_DISPLAY_NO_ATTRIBUTE
};
device->getDisplayAttributes(device, 0, configs[0], attributes, attr_values);
QSize pixel(attr_values[0], attr_values[1]);
if (pixel.isEmpty()) {
return;
}
m_pixelSize = pixel;
if (attr_values[2] != 0 && attr_values[3] != 0) {
static const qreal factor = 25.4;
auto physicalSize = QSizeF(qreal(pixel.width() * 1000) / qreal(attr_values[2]) * factor,
qreal(pixel.height() * 1000) / qreal(attr_values[3]) * factor);
setRawPhysicalSize(physicalSize.toSize());
} else {
// couldn't read physical size, assume 96 dpi
setRawPhysicalSize(pixel / 3.8);
}
OutputDeviceInterface::Mode mode;
mode.id = 0;
mode.size = pixel;
mode.flags = OutputDeviceInterface::ModeFlag::Current | OutputDeviceInterface::ModeFlag::Preferred;
mode.refreshRate = (attr_values[4] == 0) ? 60000 : 10E11/attr_values[4];
initWaylandOutputDevice(QString(), QString(), QByteArray(), {mode});
setInternal(true);
setEnabled(true);
setDpmsSupported(true);
setWaylandMode(m_pixelSize, mode.refreshRate);
}
HwcomposerOutput::~HwcomposerOutput()
{
hwc_close_1(m_device);
}
QSize HwcomposerOutput::pixelSize() const
{
return m_pixelSize;
}
bool HwcomposerOutput::isValid() const
{
return m_pixelSize.isValid();
}
void HwcomposerOutput::updateDpms(KWayland::Server::OutputInterface::DpmsMode mode)
{
emit dpmsModeRequested(mode);
}
}

View file

@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_HWCOMPOSER_BACKEND_H
#define KWIN_HWCOMPOSER_BACKEND_H
#include "platform.h"
#include "abstract_output.h"
#include "input.h"
#include <QElapsedTimer>
@ -33,8 +34,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// needed as hwcomposer_window.h includes EGL which on non-arm includes Xlib
#include <fixx11h.h>
#include <KWayland/Server/output_interface.h>
typedef struct hwc_display_contents_1 hwc_display_contents_1_t;
typedef struct hwc_layer_1 hwc_layer_1_t;
typedef struct hwc_composer_device_1 hwc_composer_device_1_t;
@ -48,6 +47,23 @@ namespace KWin
class HwcomposerWindow;
class BacklightInputEventFilter;
class HwcomposerOutput : public AbstractOutput
{
Q_OBJECT
public:
HwcomposerOutput(hwc_composer_device_1_t *device);
~HwcomposerOutput() override;
bool isValid() const;
QSize pixelSize() const override;
void updateDpms(KWayland::Server::OutputInterface::DpmsMode mode) override;
Q_SIGNALS:
void dpmsModeRequested(KWayland::Server::OutputInterface::DpmsMode mode);
private:
QSize m_pixelSize;
hwc_composer_device_1_t *m_device;
};
class HwcomposerBackend : public Platform
{
Q_OBJECT
@ -61,22 +77,19 @@ public:
Screens *createScreens(QObject *parent = nullptr) override;
OpenGLBackend *createOpenGLBackend() override;
QSize screenSize() const override {
return m_displaySize;
Outputs outputs() const override;
Outputs enabledOutputs() const override;
QSize size() const {
return screenSize();
}
QSize screenSize() const override;
HwcomposerWindow *createSurface();
QSize size() const {
return m_displaySize;
}
hwc_composer_device_1_t *device() const {
return m_device;
}
int refreshRate() const {
return m_refreshRate;
}
void enableVSync(bool enable);
void waitVSync();
void wakeVSync();
@ -88,9 +101,6 @@ public:
QVector<CompositingType> supportedCompositors() const override {
return QVector<CompositingType>{OpenGLCompositing};
}
QSizeF physicalSize() const {
return m_physicalSize;
}
Q_SIGNALS:
void outputBlankChanged();
@ -104,12 +114,9 @@ private Q_SLOTS:
private:
void initLights();
void toggleScreenBrightness();
KWayland::Server::OutputInterface* createOutput(hwc_composer_device_1_t *device);
QSize m_displaySize;
hwc_composer_device_1_t *m_device = nullptr;
light_device_t *m_lights = nullptr;
bool m_outputBlank = true;
int m_refreshRate = 60000;
int m_vsyncInterval = 16;
uint32_t m_hwcVersion;
int m_oldScreenBrightness = 0x7f;
@ -117,7 +124,7 @@ private:
QMutex m_vsyncMutex;
QWaitCondition m_vsyncWaitCondition;
QScopedPointer<BacklightInputEventFilter> m_filter;
QSizeF m_physicalSize;
QScopedPointer<HwcomposerOutput> m_output;
};
class HwcomposerWindow : public HWComposerNativeWindow

View file

@ -24,26 +24,11 @@ namespace KWin
{
HwcomposerScreens::HwcomposerScreens(HwcomposerBackend *backend, QObject *parent)
: BasicScreens(backend, parent)
: OutputScreens(backend, parent)
, m_backend(backend)
{
}
HwcomposerScreens::~HwcomposerScreens() = default;
float HwcomposerScreens::refreshRate(int screen) const
{
Q_UNUSED(screen)
return m_backend->refreshRate() / 1000.0f;
}
QSizeF HwcomposerScreens::physicalSize(int screen) const
{
const QSizeF size = m_backend->physicalSize();
if (size.isValid()) {
return size;
}
return Screens::physicalSize(screen);
connect(m_backend, &HwcomposerBackend::screensQueried, this, &OutputScreens::updateCount);
connect(m_backend, &HwcomposerBackend::screensQueried, this, &OutputScreens::changed);
}
}

View file

@ -19,20 +19,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_SCREENS_HWCOMPOSER_H
#define KWIN_SCREENS_HWCOMPOSER_H
#include "screens.h"
#include "outputscreens.h"
namespace KWin
{
class HwcomposerBackend;
class HwcomposerScreens : public BasicScreens
class HwcomposerScreens : public OutputScreens
{
Q_OBJECT
public:
HwcomposerScreens(HwcomposerBackend *backend, QObject *parent = nullptr);
virtual ~HwcomposerScreens();
float refreshRate(int screen) const override;
QSizeF physicalSize(int screen) const override;
virtual ~HwcomposerScreens() = default;
private:
HwcomposerBackend *m_backend;