From e12400a67574f2f7415427f091572e0c22b9d5b3 Mon Sep 17 00:00:00 2001 From: Martin Graesslin Date: Wed, 6 May 2015 17:47:07 +0200 Subject: [PATCH] Add a hwcomposer backend based on libhybris This backend interacts with libhybris to create a hwcomposer which is used for creating the egl context and surface. The initial version of this backend is based on test_hwcomposer.cpp provided by libhybris. Please note that using the hwcomposer backend requires a newer libepoxy, the latest stable release is not able to bring up OpenGLES, so one needs a master build of libepoxy. Notes on licensing: libhybris is Apache 2.0 licensed, which is not compatile with GPLv2. But it is compatible with GPLv3. Thus the source files in the hwcomposer backend are licensed GPLv3+ and not GPLv2+ as the rest of KWin. If one uses KWin without the hwcomposer backend (which is obviously the default) the licence doesn't change. But if the hwcomposer backend is used the overall license of KWin changes to GPLv3+. --- CMakeLists.txt | 4 + backends/CMakeLists.txt | 3 + backends/hwcomposer/CMakeLists.txt | 22 ++ .../hwcomposer/egl_hwcomposer_backend.cpp | 184 +++++++++++++++ backends/hwcomposer/egl_hwcomposer_backend.h | 66 ++++++ backends/hwcomposer/hwcomposer.json | 3 + backends/hwcomposer/hwcomposer_backend.cpp | 193 +++++++++++++++ backends/hwcomposer/hwcomposer_backend.h | 82 +++++++ backends/hwcomposer/logging.cpp | 21 ++ backends/hwcomposer/logging.h | 26 +++ backends/hwcomposer/screens_hwcomposer.cpp | 68 ++++++ backends/hwcomposer/screens_hwcomposer.h | 46 ++++ cmake/modules/Findlibhybris.cmake | 219 ++++++++++++++++++ config-kwin.h.cmake | 1 + main_wayland.cpp | 9 + 15 files changed, 947 insertions(+) create mode 100644 backends/hwcomposer/CMakeLists.txt create mode 100644 backends/hwcomposer/egl_hwcomposer_backend.cpp create mode 100644 backends/hwcomposer/egl_hwcomposer_backend.h create mode 100644 backends/hwcomposer/hwcomposer.json create mode 100644 backends/hwcomposer/hwcomposer_backend.cpp create mode 100644 backends/hwcomposer/hwcomposer_backend.h create mode 100644 backends/hwcomposer/logging.cpp create mode 100644 backends/hwcomposer/logging.h create mode 100644 backends/hwcomposer/screens_hwcomposer.cpp create mode 100644 backends/hwcomposer/screens_hwcomposer.h create mode 100644 cmake/modules/Findlibhybris.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 32c48ccd57..e9752dd016 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,10 @@ if(HAVE_DRM AND gbm_FOUND) set(HAVE_GBM TRUE) endif() +find_package(libhybris) +set_package_properties(libhybris PROPERTIES TYPE OPTIONAL PURPOSE "Required for libhybris backend") +set(HAVE_LIBHYBRIS libhybris_FOUND) + find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 4aeafa97d7..809ac64edb 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -2,5 +2,8 @@ if(HAVE_DRM) add_subdirectory(drm) endif() add_subdirectory(fbdev) +if(HAVE_LIBHYBRIS) + add_subdirectory(hwcomposer) +endif() add_subdirectory(wayland) add_subdirectory(x11) diff --git a/backends/hwcomposer/CMakeLists.txt b/backends/hwcomposer/CMakeLists.txt new file mode 100644 index 0000000000..6181b8eb9c --- /dev/null +++ b/backends/hwcomposer/CMakeLists.txt @@ -0,0 +1,22 @@ +set(HWCOMPOSER_SOURCES + egl_hwcomposer_backend.cpp + hwcomposer_backend.cpp + logging.cpp + screens_hwcomposer.cpp +) + +add_library(KWinWaylandHwcomposerBackend MODULE ${HWCOMPOSER_SOURCES}) +target_link_libraries(KWinWaylandHwcomposerBackend + kwin + libhybris::libhardware + libhybris::hwcomposer + libhybris::hybriseglplatform + libhybris::sync +) + +install( + TARGETS + KWinWaylandHwcomposerBackend + DESTINATION + ${PLUGIN_INSTALL_DIR}/org.kde.kwin.waylandbackends/ +) diff --git a/backends/hwcomposer/egl_hwcomposer_backend.cpp b/backends/hwcomposer/egl_hwcomposer_backend.cpp new file mode 100644 index 0000000000..2d52864bd8 --- /dev/null +++ b/backends/hwcomposer/egl_hwcomposer_backend.cpp @@ -0,0 +1,184 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#include "egl_hwcomposer_backend.h" +#include "hwcomposer_backend.h" +#include "logging.h" + +namespace KWin +{ + +EglHwcomposerBackend::EglHwcomposerBackend(HwcomposerBackend *backend) + : AbstractEglBackend() + , m_backend(backend) +{ + if (!initializeEgl()) { + setFailed("Failed to initialize egl"); + return; + } + init(); + // EGL is always direct rendering + setIsDirectRendering(true); +} + +EglHwcomposerBackend::~EglHwcomposerBackend() +{ + cleanup(); + delete m_nativeSurface; +} + +bool EglHwcomposerBackend::initializeEgl() +{ + // cannot use initClientExtensions as that crashes in libhybris + qputenv("EGL_PLATFORM", QByteArrayLiteral("hwcomposer")); + EGLDisplay display = EGL_NO_DISPLAY; + + display = eglGetDisplay(nullptr); + if (display == EGL_NO_DISPLAY) { + return false; + } + setEglDisplay(display); + return initEglAPI(); +} + +void EglHwcomposerBackend::init() +{ + if (!initRenderingContext()) { + setFailed("Could not initialize rendering context"); + return; + } + + initKWinGL(); + initBufferAge(); + initWayland(); +} + +bool EglHwcomposerBackend::initBufferConfigs() +{ + const EGLint config_attribs[] = { + EGL_BUFFER_SIZE, 32, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE, + }; + + EGLint count; + EGLConfig configs[1024]; + if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1, &count) == EGL_FALSE) { + qCCritical(KWIN_HWCOMPOSER) << "choose config failed"; + return false; + } + if (count != 1) { + qCCritical(KWIN_HWCOMPOSER) << "choose config did not return a config" << count; + return false; + } + setConfig(configs[0]); + + return true; +} + +bool EglHwcomposerBackend::initRenderingContext() +{ + if (!initBufferConfigs()) { + return false; + } + + EGLContext context = EGL_NO_CONTEXT; + const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs); + + if (context == EGL_NO_CONTEXT) { + qCCritical(KWIN_HWCOMPOSER) << "Create Context failed"; + return false; + } + setContext(context); + + m_nativeSurface = m_backend->createSurface(); + EGLSurface surface = eglCreateWindowSurface(eglDisplay(), config(), (EGLNativeWindowType)static_cast(m_nativeSurface), nullptr); + if (surface == EGL_NO_SURFACE) { + qCCritical(KWIN_HWCOMPOSER) << "Create surface failed"; + return false; + } + setSurface(surface); + + return makeContextCurrent(); +} + +bool EglHwcomposerBackend::makeContextCurrent() +{ + if (eglMakeCurrent(eglDisplay(), surface(), surface(), context()) == EGL_FALSE) { + qCCritical(KWIN_HWCOMPOSER) << "Make Context Current failed"; + return false; + } + + EGLint error = eglGetError(); + if (error != EGL_SUCCESS) { + qCWarning(KWIN_HWCOMPOSER) << "Error occurred while creating context " << error; + return false; + } + return true; +} + +void EglHwcomposerBackend::present() +{ + eglSwapBuffers(eglDisplay(), surface()); + m_nativeSurface->present(); +} + +void EglHwcomposerBackend::screenGeometryChanged(const QSize &size) +{ + Q_UNUSED(size) +} + +QRegion EglHwcomposerBackend::prepareRenderingFrame() +{ + // TODO: buffer age? + startRenderTimer(); + // triggers always a full repaint + return QRegion(QRect(QPoint(0, 0), m_backend->size())); +} + +void EglHwcomposerBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) +{ + Q_UNUSED(renderedRegion) + Q_UNUSED(damagedRegion) + present(); +} + +SceneOpenGL::TexturePrivate *EglHwcomposerBackend::createBackendTexture(SceneOpenGL::Texture *texture) +{ + return new EglHwcomposerTexture(texture, this); +} + +bool EglHwcomposerBackend::usesOverlayWindow() const +{ + return false; +} + +EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGL::Texture *texture, EglHwcomposerBackend *backend) + : AbstractEglTexture(texture, backend) +{ +} + +EglHwcomposerTexture::~EglHwcomposerTexture() = default; + +} diff --git a/backends/hwcomposer/egl_hwcomposer_backend.h b/backends/hwcomposer/egl_hwcomposer_backend.h new file mode 100644 index 0000000000..df30d64949 --- /dev/null +++ b/backends/hwcomposer/egl_hwcomposer_backend.h @@ -0,0 +1,66 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#ifndef KWIN_EGL_HWCOMPOSER_BACKEND_H +#define KWIN_EGL_HWCOMPOSER_BACKEND_H +#include "abstract_egl_backend.h" + +namespace KWin +{ + +class HwcomposerBackend; +class HwcomposerWindow; + +class EglHwcomposerBackend : public AbstractEglBackend +{ +public: + EglHwcomposerBackend(HwcomposerBackend *backend); + virtual ~EglHwcomposerBackend(); + bool usesOverlayWindow() const override; + SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) override; + void screenGeometryChanged(const QSize &size) override; + QRegion prepareRenderingFrame() override; + void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; + +protected: + void present() override; + +private: + void init(); + bool initializeEgl(); + bool initRenderingContext(); + bool initBufferConfigs(); + bool makeContextCurrent(); + HwcomposerBackend *m_backend; + HwcomposerWindow *m_nativeSurface = nullptr; +}; + +class EglHwcomposerTexture : public AbstractEglTexture +{ +public: + virtual ~EglHwcomposerTexture(); + +private: + friend class EglHwcomposerBackend; + EglHwcomposerTexture(SceneOpenGL::Texture *texture, EglHwcomposerBackend *backend); +}; + +} + +#endif diff --git a/backends/hwcomposer/hwcomposer.json b/backends/hwcomposer/hwcomposer.json new file mode 100644 index 0000000000..404bba5384 --- /dev/null +++ b/backends/hwcomposer/hwcomposer.json @@ -0,0 +1,3 @@ +{ + "input": false +} diff --git a/backends/hwcomposer/hwcomposer_backend.cpp b/backends/hwcomposer/hwcomposer_backend.cpp new file mode 100644 index 0000000000..f20960af73 --- /dev/null +++ b/backends/hwcomposer/hwcomposer_backend.cpp @@ -0,0 +1,193 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#include "egl_hwcomposer_backend.h" +#include "hwcomposer_backend.h" +#include "logging.h" +#include "screens_hwcomposer.h" +#include +#include + +// based on test_hwcomposer.c from libhybris project (Apache 2 licensed) + +namespace KWin +{ + +HwcomposerBackend::HwcomposerBackend(QObject *parent) + : AbstractBackend(parent) +{ +} + +HwcomposerBackend::~HwcomposerBackend() +{ + if (m_device) { + hwc_close_1(m_device); + } +} + +static QSize getDisplaySize(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 QSize(); + } + + int32_t attr_values[2]; + uint32_t attributes[] = { + HWC_DISPLAY_WIDTH, + HWC_DISPLAY_HEIGHT, + HWC_DISPLAY_NO_ATTRIBUTE + }; + device->getDisplayAttributes(device, 0, configs[0], attributes, attr_values); + return QSize(attr_values[0], attr_values[1]); +} + +void HwcomposerBackend::init() +{ + hw_module_t *hwcModule = nullptr; + if (hw_get_module(HWC_HARDWARE_MODULE_ID, (const hw_module_t **)&hwcModule) != 0) { + qCWarning(KWIN_HWCOMPOSER) << "Failed to get hwcomposer module"; + emit initFailed(); + return; + } + + hwc_composer_device_1_t *hwcDevice = nullptr; + if (hwc_open_1(hwcModule, &hwcDevice) != 0) { + qCWarning(KWIN_HWCOMPOSER) << "Failed to open hwcomposer device"; + emit initFailed(); + return; + } + + // unblank, setPowerMode? + hwcDevice->blank(hwcDevice, 0, 0); + + // get display configuration + m_displaySize = getDisplaySize(hwcDevice); + if (!m_displaySize.isValid()) { + emit initFailed(); + return; + } + qCDebug(KWIN_HWCOMPOSER) << "Display size:" << m_displaySize; + m_device = hwcDevice; + + emit screensQueried(); + setReady(true); +} + +HwcomposerWindow *HwcomposerBackend::createSurface() +{ + return new HwcomposerWindow(this); +} + +Screens *HwcomposerBackend::createScreens(QObject *parent) +{ + return new HwcomposerScreens(this, parent); +} + +OpenGLBackend *HwcomposerBackend::createOpenGLBackend() +{ + return new EglHwcomposerBackend(this); +} + +static void initLayer(hwc_layer_1_t *layer, const hwc_rect_t &rect) +{ + memset(layer, 0, sizeof(hwc_layer_1_t)); + layer->compositionType = HWC_FRAMEBUFFER; + layer->hints = 0; + layer->flags = 0; + layer->handle = 0; + layer->transform = 0; + layer->blending = HWC_BLENDING_NONE; + layer->sourceCrop = rect; + layer->displayFrame = rect; + layer->visibleRegionScreen.numRects = 1; + layer->visibleRegionScreen.rects = &layer->displayFrame; + layer->acquireFenceFd = -1; + layer->releaseFenceFd = -1; +} + +HwcomposerWindow::HwcomposerWindow(HwcomposerBackend *backend) + : HWComposerNativeWindow(backend->size().width(), backend->size().height(), HAL_PIXEL_FORMAT_RGBA_8888) + , m_backend(backend) +{ + size_t size = sizeof(hwc_display_contents_1_t) + 2 * sizeof(hwc_layer_1_t); + hwc_display_contents_1_t *list = (hwc_display_contents_1_t*)malloc(size); + m_list = (hwc_display_contents_1_t**)malloc(HWC_NUM_DISPLAY_TYPES * sizeof(hwc_display_contents_1_t *)); + for (int i = 0; i < HWC_NUM_DISPLAY_TYPES; ++i) { + m_list[i] = list; + } + const hwc_rect_t rect = { + 0, + 0, + m_backend->size().width(), + m_backend->size().height() + }; + initLayer(&list->hwLayers[0], rect); + initLayer(&list->hwLayers[1], rect); + + list->retireFenceFd = -1; + list->flags = HWC_GEOMETRY_CHANGED; + list->numHwLayers = 2; +} + +HwcomposerWindow::~HwcomposerWindow() +{ + // TODO: cleanup +} + +static void syncWait(int fd) +{ + if (fd == -1) { + return; + } + sync_wait(fd, -1); + close(fd); +} + +void HwcomposerWindow::present() +{ + HWComposerNativeWindowBuffer *front; + lockFrontBuffer(&front); + + m_list[0]->hwLayers[1].handle = front->handle; + m_list[0]->hwLayers[0].handle = NULL; + m_list[0]->hwLayers[0].flags = HWC_SKIP_LAYER; + + int oldretire = m_list[0]->retireFenceFd; + int oldrelease = m_list[0]->hwLayers[1].releaseFenceFd; + int oldrelease2 = m_list[0]->hwLayers[0].releaseFenceFd; + + hwc_composer_device_1_t *device = m_backend->device(); + if (device->prepare(device, HWC_NUM_DISPLAY_TYPES, m_list) != 0) { + qCWarning(KWIN_HWCOMPOSER) << "Error preparing hwcomposer for frame"; + } + if (device->set(device, HWC_NUM_DISPLAY_TYPES, m_list) != 0) { + qCWarning(KWIN_HWCOMPOSER) << "Error setting device for frame"; + } + + unlockFrontBuffer(front); + + syncWait(oldrelease); + syncWait(oldrelease2); + syncWait(oldretire); +} + +} diff --git a/backends/hwcomposer/hwcomposer_backend.h b/backends/hwcomposer/hwcomposer_backend.h new file mode 100644 index 0000000000..0ab8a0aa1d --- /dev/null +++ b/backends/hwcomposer/hwcomposer_backend.h @@ -0,0 +1,82 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#ifndef KWIN_HWCOMPOSER_BACKEND_H +#define KWIN_HWCOMPOSER_BACKEND_H +#include "abstract_backend.h" + +// libhybris +#include +// needed as hwcomposer_window.h includes EGL which on non-arm includes Xlib +#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; + +namespace KWin +{ + +class HwcomposerWindow; + +class HwcomposerBackend : public AbstractBackend +{ + Q_OBJECT + Q_INTERFACES(KWin::AbstractBackend) + Q_PLUGIN_METADATA(IID "org.kde.kwin.AbstractBackend" FILE "hwcomposer.json") +public: + explicit HwcomposerBackend(QObject *parent = nullptr); + virtual ~HwcomposerBackend(); + + void init() override; + Screens *createScreens(QObject *parent = nullptr) override; + OpenGLBackend *createOpenGLBackend() override; + + HwcomposerWindow *createSurface(); + + QSize size() const { + return m_displaySize; + } + + hwc_composer_device_1_t *device() const { + return m_device; + } + +private: + QSize m_displaySize; + hwc_composer_device_1_t *m_device = nullptr; +}; + +class HwcomposerWindow : public HWComposerNativeWindow +{ +public: + virtual ~HwcomposerWindow(); + + void present(); + +private: + friend HwcomposerBackend; + HwcomposerWindow(HwcomposerBackend *backend); + HwcomposerBackend *m_backend; + hwc_display_contents_1_t **m_list; +}; + +} + +#endif diff --git a/backends/hwcomposer/logging.cpp b/backends/hwcomposer/logging.cpp new file mode 100644 index 0000000000..cdd9853fd2 --- /dev/null +++ b/backends/hwcomposer/logging.cpp @@ -0,0 +1,21 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#include "logging.h" +Q_LOGGING_CATEGORY(KWIN_HWCOMPOSER, "kwin_wayland_hwcomposer") diff --git a/backends/hwcomposer/logging.h b/backends/hwcomposer/logging.h new file mode 100644 index 0000000000..78ef28b710 --- /dev/null +++ b/backends/hwcomposer/logging.h @@ -0,0 +1,26 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#ifndef KWIN_FB_LOGGING_H +#define KWIN_FB_LOGGING_H +#include +#include + +Q_DECLARE_LOGGING_CATEGORY(KWIN_HWCOMPOSER) +#endif diff --git a/backends/hwcomposer/screens_hwcomposer.cpp b/backends/hwcomposer/screens_hwcomposer.cpp new file mode 100644 index 0000000000..db79cc3784 --- /dev/null +++ b/backends/hwcomposer/screens_hwcomposer.cpp @@ -0,0 +1,68 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#include "screens_hwcomposer.h" +#include "hwcomposer_backend.h" + +namespace KWin +{ + +HwcomposerScreens::HwcomposerScreens(HwcomposerBackend *backend, QObject *parent) + : Screens(parent) + , m_backend(backend) +{ +} + +HwcomposerScreens::~HwcomposerScreens() = default; + +void HwcomposerScreens::init() +{ + Screens::init(); + updateCount(); + emit changed(); +} + +QRect HwcomposerScreens::geometry(int screen) const +{ + if (screen == 0) { + return QRect(QPoint(0, 0), size(screen)); + } + return QRect(); +} + +QSize HwcomposerScreens::size(int screen) const +{ + if (screen == 0) { + return m_backend->size(); + } + return QSize(); +} + +void HwcomposerScreens::updateCount() +{ + setCount(1); +} + +int HwcomposerScreens::number(const QPoint &pos) const +{ + Q_UNUSED(pos) + return 0; +} + +} diff --git a/backends/hwcomposer/screens_hwcomposer.h b/backends/hwcomposer/screens_hwcomposer.h new file mode 100644 index 0000000000..9ee2baf90f --- /dev/null +++ b/backends/hwcomposer/screens_hwcomposer.h @@ -0,0 +1,46 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2015 Martin Gräßlin + +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 3 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 . +*********************************************************************/ +#ifndef KWIN_SCREENS_FRAMEBUFFER_H +#define KWIN_SCREENS_FRAMEBUFFER_H +#include "screens.h" + +namespace KWin +{ +class HwcomposerBackend; + +class HwcomposerScreens : public Screens +{ + Q_OBJECT +public: + HwcomposerScreens(HwcomposerBackend *backend, QObject *parent = nullptr); + virtual ~HwcomposerScreens(); + void init() override; + QRect geometry(int screen) const override; + int number(const QPoint &pos) const override; + QSize size(int screen) const override; + void updateCount() override; + +private: + HwcomposerBackend *m_backend; +}; + +} + +#endif diff --git a/cmake/modules/Findlibhybris.cmake b/cmake/modules/Findlibhybris.cmake new file mode 100644 index 0000000000..68904d0e9f --- /dev/null +++ b/cmake/modules/Findlibhybris.cmake @@ -0,0 +1,219 @@ +#.rst: +# Findlibhybris +# ------- +# +# Try to find libhybris on a Unix system. + +#============================================================================= +# Copyright 2015 Martin Gräßlin +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +if(CMAKE_VERSION VERSION_LESS 2.8.12) + message(FATAL_ERROR "CMake 2.8.12 is required by Findlibhybris.cmake") +endif() +if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 2.8.12) + message(AUTHOR_WARNING "Your project should require at least CMake 2.8.12 to use Findlibhybris.cmake") +endif() + +if(NOT WIN32) + # Use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + find_package(PkgConfig) + pkg_check_modules(PKG_libhardware QUIET libhardware) + pkg_check_modules(PKG_androidheaders QUIET android-headers) + pkg_check_modules(PKG_hwcomposerwindow QUIET hwcomposer-egl) + pkg_check_modules(PKG_hybriseglplatform QUIET hybris-egl-platform) + pkg_check_modules(PKG_hybrissync QUIET libsync) + + set(libhardware_DEFINITIONS ${PKG_libhardware_CFLAGS_OTHER}) + set(libhardware_VERSION ${PKG_libhardware_VERSION}) + + find_library(libhardware_LIBRARY + NAMES + libhardware.so + HINTS + ${PKG_libhardware_LIBRARY_DIRS} + ) + find_path(libhardware_INCLUDE_DIR + NAMES + android-version.h + HINTS + ${PKG_androidheaders_INCLUDE_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(libhardware + FOUND_VAR + libhardware_FOUND + REQUIRED_VARS + libhardware_LIBRARY + libhardware_INCLUDE_DIR + VERSION_VAR + libhardware_VERSION + ) + + if(libhardware_FOUND AND NOT TARGET libhybris::libhardware) + add_library(libhybris::libhardware UNKNOWN IMPORTED) + set_target_properties(libhybris::libhardware PROPERTIES + IMPORTED_LOCATION "${libhardware_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${libhardware_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${libhardware_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(libhardware_LIBRARY libhardware_INCLUDE_DIR) + + ############################################## + # hwcomposerWindow + ############################################## + set(libhwcomposer_DEFINITIONS ${PKG_hwcomposerwindow_CFLAGS_OTHER}) + set(libhwcomposer_VERSION ${PKG_hwcomposerwindow_VERSION}) + + find_library(libhwcomposer_LIBRARY + NAMES + libhybris-hwcomposerwindow.so + HINTS + ${PKG_hwcomposerwindow_LIBRARY_DIRS} + ) + find_path(libhwcomposer_INCLUDE_DIR + NAMES + hwcomposer_window.h + HINTS + ${PKG_hwcomposerwindow_INCLUDE_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(libhwcomposer + FOUND_VAR + libhwcomposer_FOUND + REQUIRED_VARS + libhwcomposer_LIBRARY + libhwcomposer_INCLUDE_DIR + VERSION_VAR + libhwcomposer_VERSION + ) + + if(libhwcomposer_FOUND AND NOT TARGET libhybris::hwcomposer) + add_library(libhybris::hwcomposer UNKNOWN IMPORTED) + set_target_properties(libhybris::hwcomposer PROPERTIES + IMPORTED_LOCATION "${libhwcomposer_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${libhardware_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${libhwcomposer_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(libhwcomposer_LIBRARY libhwcomposer_INCLUDE_DIR) + + ############################################## + # hybriseglplatform + ############################################## + set(hybriseglplatform_DEFINITIONS ${PKG_hybriseglplatform_CFLAGS_OTHER}) + set(hybriseglplatform_VERSION ${PKG_hybriseglplatform_VERSION}) + + find_library(hybriseglplatform_LIBRARY + NAMES + libhybris-eglplatformcommon.so + HINTS + ${PKG_hybriseglplatform_LIBRARY_DIRS} + ) + find_path(hybriseglplatform_INCLUDE_DIR + NAMES + eglplatformcommon.h + HINTS + ${PKG_hybriseglplatform_INCLUDE_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(hybriseglplatform + FOUND_VAR + hybriseglplatform_FOUND + REQUIRED_VARS + hybriseglplatform_LIBRARY + hybriseglplatform_INCLUDE_DIR + VERSION_VAR + hybriseglplatform_VERSION + ) + + if(hybriseglplatform_FOUND AND NOT TARGET libhybris::hybriseglplatform) + add_library(libhybris::hybriseglplatform UNKNOWN IMPORTED) + set_target_properties(libhybris::hybriseglplatform PROPERTIES + IMPORTED_LOCATION "${hybriseglplatform_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${hybriseglplatform_DEFINITIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${hybriseglplatform_INCLUDE_DIR}" + ) + endif() + + mark_as_advanced(hybriseglplatform_LIBRARY hybriseglplatform_INCLUDE_DIR) + + ############################################## + # hybrissync + ############################################## + set(hybrissync_DEFINITIONS ${PKG_hybrissync_CFLAGS_OTHER}) + set(hybrissync_VERSION ${PKG_hybrissync_VERSION}) + + find_library(hybrissync_LIBRARY + NAMES + libsync.so + HINTS + ${PKG_hybrissync_LIBRARY_DIRS} + ) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(hybrissync + FOUND_VAR + hybrissync_FOUND + REQUIRED_VARS + hybrissync_LIBRARY + VERSION_VAR + hybrissync_VERSION + ) + + if(hybrissync_FOUND AND NOT TARGET libhybris::sync) + add_library(libhybris::sync UNKNOWN IMPORTED) + set_target_properties(libhybris::sync PROPERTIES + IMPORTED_LOCATION "${hybrissync_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${hybrissync_DEFINITIONS}" + ) + endif() + + mark_as_advanced(hybrissync_LIBRARY) + + if(libhardware_FOUND AND libhwcomposer_FOUND AND hybriseglplatform_FOUND AND hybrissync_FOUND) + set(libhybris_FOUND TRUE) + else() + set(libhybris_FOUND FALSE) + endif() + +else() + message(STATUS "Findlibhardware.cmake cannot find libhybris on Windows systems.") + set(libhybris_FOUND FALSE) +endif() + +include(FeatureSummary) +set_package_properties(libhybris PROPERTIES + URL "https://github.com/libhybris/libhybris" + DESCRIPTION "libhybris allows to run bionic-based HW adaptations in glibc systems." +) diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake index 699d65cd47..0c7f43d6a8 100644 --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -17,6 +17,7 @@ #cmakedefine01 HAVE_X11_XCB #cmakedefine01 HAVE_DRM #cmakedefine01 HAVE_GBM +#cmakedefine01 HAVE_LIBHYBRIS /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H 1 diff --git a/main_wayland.cpp b/main_wayland.cpp index 602227c758..0c22555f2b 100644 --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -411,6 +411,10 @@ KWIN_EXPORT int kdemain(int argc, char * argv[]) parser.addOption(framebufferDeviceOption); parser.addOption(widthOption); parser.addOption(heightOption); +#if HAVE_LIBHYBRIS + QCommandLineOption hwcomposerOption(QStringLiteral("hwcomposer"), i18n("Use libhybris hwcomposer")); + parser.addOption(hwcomposerOption); +#endif #if HAVE_INPUT QCommandLineOption libinputOption(QStringLiteral("libinput"), i18n("Enable libinput support for input events processing. Note: never use in a nested session.")); @@ -483,6 +487,11 @@ KWIN_EXPORT int kdemain(int argc, char * argv[]) pluginName = QStringLiteral("KWinWaylandFbdevBackend"); deviceIdentifier = parser.value(framebufferDeviceOption).toUtf8(); } +#if HAVE_LIBHYBRIS + if (parser.isSet(hwcomposerOption)) { + pluginName = QStringLiteral("KWinWaylandHwcomposerBackend"); + } +#endif const auto pluginCandidates = KPluginLoader::findPlugins(QStringLiteral("org.kde.kwin.waylandbackends"), [&pluginName] (const KPluginMetaData &plugin) {