From 062dfefafe06629117abf37b68ef59964fbb9654 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Wed, 20 Feb 2019 13:19:51 +0000 Subject: [PATCH] [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 --- .../hwcomposer/hwcomposer_backend.cpp | 169 ++++++++++++------ .../platforms/hwcomposer/hwcomposer_backend.h | 43 +++-- .../hwcomposer/screens_hwcomposer.cpp | 21 +-- .../platforms/hwcomposer/screens_hwcomposer.h | 8 +- 4 files changed, 141 insertions(+), 100 deletions(-) diff --git a/plugins/platforms/hwcomposer/hwcomposer_backend.cpp b/plugins/platforms/hwcomposer/hwcomposer_backend.cpp index 6cc024fa95..651d1e5756 100644 --- a/plugins/platforms/hwcomposer/hwcomposer_backend.cpp +++ b/plugins/platforms/hwcomposer/hwcomposer_backend.cpp @@ -26,8 +26,7 @@ along with this program. If not, see . #include "main.h" #include "wayland_server.h" // KWayland -#include -#include +#include // Qt #include #include @@ -39,6 +38,8 @@ along with this program. If not, see . // 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({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); +} + } diff --git a/plugins/platforms/hwcomposer/hwcomposer_backend.h b/plugins/platforms/hwcomposer/hwcomposer_backend.h index 29ae5a5f8e..32d3dd7fc9 100644 --- a/plugins/platforms/hwcomposer/hwcomposer_backend.h +++ b/plugins/platforms/hwcomposer/hwcomposer_backend.h @@ -20,6 +20,7 @@ along with this program. If not, see . #ifndef KWIN_HWCOMPOSER_BACKEND_H #define KWIN_HWCOMPOSER_BACKEND_H #include "platform.h" +#include "abstract_output.h" #include "input.h" #include @@ -33,8 +34,6 @@ along with this program. If not, see . // needed as hwcomposer_window.h includes EGL which on non-arm includes Xlib #include -#include - 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 supportedCompositors() const override { return QVector{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 m_filter; - QSizeF m_physicalSize; + QScopedPointer m_output; }; class HwcomposerWindow : public HWComposerNativeWindow diff --git a/plugins/platforms/hwcomposer/screens_hwcomposer.cpp b/plugins/platforms/hwcomposer/screens_hwcomposer.cpp index be14e7d31c..f8e6147fcf 100644 --- a/plugins/platforms/hwcomposer/screens_hwcomposer.cpp +++ b/plugins/platforms/hwcomposer/screens_hwcomposer.cpp @@ -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); } } diff --git a/plugins/platforms/hwcomposer/screens_hwcomposer.h b/plugins/platforms/hwcomposer/screens_hwcomposer.h index 384236d9ad..a40dc83c7b 100644 --- a/plugins/platforms/hwcomposer/screens_hwcomposer.h +++ b/plugins/platforms/hwcomposer/screens_hwcomposer.h @@ -19,20 +19,18 @@ along with this program. If not, see . *********************************************************************/ #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;