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) {