Drop hwcomposer backend

Plasma Mobile announced that they plan to drop support for Halium
devices, see the announcement blog post [1] for the reasons that led to
such a decision.

But just to summarize, here are some of the key points from the post:

 * Some of our team members no longer have access to reference LG Nexus
   5X device anymore
 * After KDE Neon switched to using Ubuntu 20.04 we no longer are
   updating the rootfs for halium devices
 * After several important architecture changes in upstream KWin, the
   hwcomposer backend might be broken and we have no way of verifying it

If the community members are interested in reviving the hwcomposer
backend,

  * it pretty much needs rewrite/re-thinking given differences of hwc1
    and hwc2 API for hwcomposer part of it, see also [2]
  * It also needs removal of Android 5 based libhardware API as we don't
    think code can be kept sane with 3 different levels of ifdefs
  * This backend needs better way of fixing difference between
    CAF/non-CAF devices then just recompiling with different headers,
    maybe env vars?
  * This backend does not support various things like transformation/
    rotation etc, and is not exactly feature complete as the DRM backend

[1] https://www.plasma-mobile.org/2020/12/14/plasma-mobile-technical-debt.html
[2] 83f563c339
This commit is contained in:
Vlad Zahorodnii 2020-12-15 10:23:44 +02:00
parent ae440bdc25
commit 7e5c16989e
14 changed files with 0 additions and 1252 deletions

View file

@ -222,10 +222,6 @@ if (HAVE_DRM AND KWIN_BUILD_EGL_STREAM_BACKEND)
set(HAVE_EGL_STREAMS 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"

View file

@ -1,164 +0,0 @@
#.rst:
# Findlibhybris
# -------
#
# Try to find libhybris on a Unix system.
#=============================================================================
# SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
#=============================================================================
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)
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)
if(libhardware_FOUND AND libhwcomposer_FOUND AND hybriseglplatform_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."
)

View file

@ -19,7 +19,6 @@
#cmakedefine01 HAVE_DRM
#cmakedefine01 HAVE_GBM
#cmakedefine01 HAVE_EGL_STREAMS
#cmakedefine01 HAVE_LIBHYBRIS
#cmakedefine01 HAVE_WAYLAND_EGL
#cmakedefine01 HAVE_SYS_PRCTL_H
#cmakedefine01 HAVE_PR_SET_DUMPABLE

View file

@ -7,7 +7,6 @@ libkwinglutils KWin OpenGL utility Library DEFAULT_SEVERITY [CRITICAL] IDENTIFIE
libkwinxrenderutils KWin XRender utility Library DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [LIBKWINXRENDERUTILS]
kwin_wayland_drm KWin Wayland (DRM backend) DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_DRM]
kwin_wayland_framebuffer KWin Wayland (Framebuffer backend) DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_FB]
kwin_wayland_hwcomposer KWin Wayland (hwcomposer backend) DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_HWCOMPOSER]
kwin_wayland_backend KWin Wayland (Wayland backend) DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_WAYLAND_BACKEND]
kwin_wayland_x11windowed KWin Wayland (X11 backend) DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_X11WINDOWED]
kwin_platform_x11_standalone KWin X11 Standalone Platform DEFAULT_SEVERITY [CRITICAL] IDENTIFIER [KWIN_X11STANDALONE]

View file

@ -313,9 +313,6 @@ static const QString s_fbdevPlugin = QStringLiteral("KWinWaylandFbdevBackend");
#if HAVE_DRM
static const QString s_drmPlugin = QStringLiteral("KWinWaylandDrmBackend");
#endif
#if HAVE_LIBHYBRIS
static const QString s_hwcomposerPlugin = QStringLiteral("KWinWaylandHwcomposerBackend");
#endif
static const QString s_virtualPlugin = QStringLiteral("KWinWaylandVirtualBackend");
@ -336,11 +333,6 @@ static QString automaticBackendSelection(SpawnMode spawnMode)
if (qEnvironmentVariableIsSet("DISPLAY")) {
return s_x11Plugin;
}
#if HAVE_LIBHYBRIS
if (qEnvironmentVariableIsSet("ANDROID_ROOT")) {
return s_hwcomposerPlugin;
}
#endif
#if HAVE_DRM
return s_drmPlugin;
#endif
@ -468,9 +460,6 @@ int main(int argc, char * argv[])
#if HAVE_DRM
const bool hasDrmOption = hasPlugin(KWin::s_drmPlugin);
#endif
#if HAVE_LIBHYBRIS
const bool hasHwcomposerOption = hasPlugin(KWin::s_hwcomposerPlugin);
#endif
QCommandLineOption xwaylandOption(QStringLiteral("xwayland"),
i18n("Start a rootless Xwayland server."));
@ -539,12 +528,6 @@ int main(int argc, char * argv[])
if (hasOutputCountOption) {
parser.addOption(outputCountOption);
}
#if HAVE_LIBHYBRIS
QCommandLineOption hwcomposerOption(QStringLiteral("hwcomposer"), i18n("Use libhybris hwcomposer"));
if (hasHwcomposerOption) {
parser.addOption(hwcomposerOption);
}
#endif
QCommandLineOption libinputOption(QStringLiteral("libinput"),
i18n("Enable libinput support for input events processing. Note: never use in a nested session. (deprecated)"));
parser.addOption(libinputOption);
@ -659,11 +642,6 @@ int main(int argc, char * argv[])
pluginName = KWin::s_fbdevPlugin;
deviceIdentifier = parser.value(framebufferDeviceOption).toUtf8();
}
#if HAVE_LIBHYBRIS
if (hasHwcomposerOption && parser.isSet(hwcomposerOption)) {
pluginName = KWin::s_hwcomposerPlugin;
}
#endif
if (hasVirtualOption && parser.isSet(virtualFbOption)) {
pluginName = KWin::s_virtualPlugin;
}

View file

@ -4,9 +4,6 @@ endif()
if (HAVE_LINUX_FB_H)
add_subdirectory(fbdev)
endif()
if (HAVE_LIBHYBRIS)
add_subdirectory(hwcomposer)
endif()
add_subdirectory(virtual)
add_subdirectory(wayland)
add_subdirectory(x11)

View file

@ -1,25 +0,0 @@
set(HWCOMPOSER_SOURCES
egl_hwcomposer_backend.cpp
hwcomposer_backend.cpp
logging.cpp
)
include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl)
add_library(KWinWaylandHwcomposerBackend MODULE ${HWCOMPOSER_SOURCES})
set_target_properties(KWinWaylandHwcomposerBackend PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/org.kde.kwin.waylandbackends/")
target_link_libraries(KWinWaylandHwcomposerBackend
kwin
SceneOpenGLBackend
libhybris::hwcomposer
libhybris::hybriseglplatform
libhybris::libhardware
)
install(
TARGETS
KWinWaylandHwcomposerBackend
DESTINATION
${PLUGIN_INSTALL_DIR}/org.kde.kwin.waylandbackends/
)

View file

@ -1,177 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "egl_hwcomposer_backend.h"
#include "hwcomposer_backend.h"
#include "logging.h"
namespace KWin
{
EglHwcomposerBackend::EglHwcomposerBackend(HwcomposerBackend *backend)
: AbstractEglBackend()
, m_backend(backend)
{
// EGL is always direct rendering
setIsDirectRendering(true);
setSyncsToVBlank(true);
}
EglHwcomposerBackend::~EglHwcomposerBackend()
{
cleanup();
}
bool EglHwcomposerBackend::initializeEgl()
{
// cannot use initClientExtensions as that crashes in libhybris
qputenv("EGL_PLATFORM", QByteArrayLiteral("hwcomposer"));
EGLDisplay display = m_backend->sceneEglDisplay();
if (display == EGL_NO_DISPLAY) {
display = eglGetDisplay(nullptr);
}
if (display == EGL_NO_DISPLAY) {
return false;
}
setEglDisplay(display);
return initEglAPI();
}
void EglHwcomposerBackend::init()
{
if (!initializeEgl()) {
setFailed("Failed to initialize egl");
return;
}
if (!initRenderingContext()) {
setFailed("Could not initialize rendering context");
return;
}
initKWinGL();
initBufferAge();
initWayland();
}
bool EglHwcomposerBackend::initBufferConfigs()
{
const EGLint config_attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
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;
}
if (!createContext()) {
return false;
}
m_nativeSurface = m_backend->createSurface();
EGLSurface surface = eglCreateWindowSurface(eglDisplay(), config(), (EGLNativeWindowType)static_cast<ANativeWindow*>(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;
}
const QSize overall = m_backend->size();
glViewport(0, 0, overall.width(), overall.height());
return true;
}
void EglHwcomposerBackend::present()
{
if (lastDamage().isEmpty()) {
return;
}
eglSwapBuffers(eglDisplay(), surface());
setLastDamage(QRegion());
}
void EglHwcomposerBackend::screenGeometryChanged(const QSize &size)
{
Q_UNUSED(size)
}
QRegion EglHwcomposerBackend::beginFrame(int screenId)
{
Q_UNUSED(screenId)
present();
// TODO: buffer age?
// triggers always a full repaint
return QRegion(QRect(QPoint(0, 0), m_backend->size()));
}
void EglHwcomposerBackend::endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion)
{
Q_UNUSED(screenId)
Q_UNUSED(damagedRegion)
setLastDamage(renderedRegion);
}
SceneOpenGLTexturePrivate *EglHwcomposerBackend::createBackendTexture(SceneOpenGLTexture *texture)
{
return new EglHwcomposerTexture(texture, this);
}
bool EglHwcomposerBackend::usesOverlayWindow() const
{
return false;
}
EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGLTexture *texture, EglHwcomposerBackend *backend)
: AbstractEglTexture(texture, backend)
{
}
EglHwcomposerTexture::~EglHwcomposerTexture() = default;
}

View file

@ -1,55 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#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;
SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override;
void screenGeometryChanged(const QSize &size) override;
QRegion beginFrame(int screenId) override;
void endFrame(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) override;
void init() override;
protected:
void present() override;
private:
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(SceneOpenGLTexture *texture, EglHwcomposerBackend *backend);
};
}
#endif

View file

@ -1,83 +0,0 @@
{
"KPlugin": {
"Description": "Render through hwcomposer through libhybris.",
"Description[az]": "Libhybris vasitəsi ilə hwcomposer içindən formalaşdırmaq.",
"Description[ca@valencia]": "Renderitza mitjançant «hwcomposer» mitjançant «libhybris».",
"Description[ca]": "Renderitza mitjançant el «hwcomposer» mitjançant «libhybris».",
"Description[da]": "Rendér igennem hwcomposer igennem libhybris.",
"Description[de]": "In hwcomposer mit libhybris rendern.",
"Description[el]": "Αποτύπωση μέσω hwcomposer μέσω libhybris.",
"Description[en_GB]": "Render through hwcomposer through libhybris.",
"Description[es]": "Renderizar a través «hwcomposer» mediante «libhybris».",
"Description[et]": "Renderdamine hwcomposeris libhybrise abil.",
"Description[eu]": "Errendatu hwcomposer libhybris bidez erabiliz.",
"Description[fi]": "Hahmonna hwcomposerin läpi libhybristä käyttäen.",
"Description[fr]": "Rendre par le biais de « hwcomposer » via « libhybris ».",
"Description[gl]": "Renderizar a través de hwcomposer a través de libhybris.",
"Description[hu]": "Renderelés hwcomposerrel libhybrisen keresztül.",
"Description[id]": "Render melalui hwcomposer melalui libhybris.",
"Description[it]": "Resa tramite hwcomposer attraverso libhybris.",
"Description[ko]": "libhybris를 통하여 hwcomposer로 렌더링합니다.",
"Description[lt]": "Atvaizduoti per hwcomposer per libhybris.",
"Description[nl]": "Render via hwcomposer via libhybris.",
"Description[nn]": "Teikn opp via hwcomposer gjennom libhybris.",
"Description[pl]": "Wyświetlaj przez sprzętowy kompozytor przez libhybris.",
"Description[pt]": "Desenhar através do Hwcomposer, usando a libhybris.",
"Description[pt_BR]": "Renderizar através do hwcomposer e libhybris.",
"Description[ro]": "Randează prin hwcomposer prin libhybris.",
"Description[ru]": "Отрисовка через hwcomposer с использованием libhybris.",
"Description[sk]": "Renderovať cez hwcomposer cez libhybris.",
"Description[sl]": "Izriši preko hwcomposer-ja in libhybris.",
"Description[sr@ijekavian]": "Рендеровање кроз ХВ‑композер кроз libhybris.",
"Description[sr@ijekavianlatin]": "Renderovanje kroz HWcomposer kroz libhybris.",
"Description[sr@latin]": "Renderovanje kroz HWcomposer kroz libhybris.",
"Description[sr]": "Рендеровање кроз ХВ‑композер кроз libhybris.",
"Description[sv]": "Återge via på hårdvarusammansättare via libhybris.",
"Description[tr]": "libhybris aracılığıyla hwcomposer içinden gerçekle.",
"Description[uk]": "Обробляти за допомогою апаратного засобу композиції через libhybris.",
"Description[x-test]": "xxRender through hwcomposer through libhybris.xx",
"Description[zh_CN]": "使用 libhybris 通过 hwcomposer 渲染。",
"Description[zh_TW]": "透過 libhybris 成像到 hwcomposer。",
"Id": "KWinWaylandHwcomposerBackend",
"Name": "hwcomposer",
"Name[az]": "hwcomposer",
"Name[ca@valencia]": "hwcomposer",
"Name[ca]": "hwcomposer",
"Name[cs]": "hwcomposer",
"Name[da]": "hwcomposer",
"Name[de]": "hwcomposer",
"Name[el]": "hwcomposer",
"Name[en_GB]": "hwcomposer",
"Name[es]": "hwcomposer",
"Name[et]": "hwcomposer",
"Name[eu]": "hwcomposer",
"Name[fi]": "hwcomposer",
"Name[fr]": "hwcomposer",
"Name[gl]": "hwcomposer",
"Name[hu]": "hwcomposer",
"Name[id]": "hwcomposer",
"Name[it]": "hwcomposer",
"Name[ko]": "hwcomposer",
"Name[lt]": "hwcomposer",
"Name[nl]": "hwcomposer",
"Name[nn]": "hwcomposer",
"Name[pl]": "sprzętowy kompozytor",
"Name[pt]": "Hwcomposer",
"Name[pt_BR]": "hwcomposer",
"Name[ro]": "hwcomposer",
"Name[ru]": "hwcomposer",
"Name[sk]": "hwcomposer",
"Name[sl]": "hwcomposer",
"Name[sr@ijekavian]": "ХВ‑композер",
"Name[sr@ijekavianlatin]": "HWcomposer",
"Name[sr@latin]": "HWcomposer",
"Name[sr]": "ХВ‑композер",
"Name[sv]": "hårdvarusammansättare",
"Name[tr]": "hwcomposer",
"Name[uk]": "hwcomposer",
"Name[x-test]": "xxhwcomposerxx",
"Name[zh_CN]": "hwcomposer",
"Name[zh_TW]": "hwcomposer"
},
"input": false
}

View file

@ -1,538 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "egl_hwcomposer_backend.h"
#include "hwcomposer_backend.h"
#include "logging.h"
#include "composite.h"
#include "main.h"
#include "wayland_server.h"
// KWayland
#include <KWaylandServer/output_interface.h>
// KDE
#include <KConfigGroup>
// Qt
#include <QKeyEvent>
#include <QDBusConnection>
// hybris/android
#include <hardware/hardware.h>
#include <hardware/lights.h>
// linux
#include <linux/input.h>
// based on test_hwcomposer.c from libhybris project (Apache 2 licensed)
using namespace KWaylandServer;
namespace KWin
{
BacklightInputEventFilter::BacklightInputEventFilter(HwcomposerBackend *backend)
: InputEventFilter()
, m_backend(backend)
{
}
BacklightInputEventFilter::~BacklightInputEventFilter() = default;
bool BacklightInputEventFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton)
{
Q_UNUSED(event)
Q_UNUSED(nativeButton)
if (!m_backend->isBacklightOff()) {
return false;
}
toggleBacklight();
return true;
}
bool BacklightInputEventFilter::wheelEvent(QWheelEvent *event)
{
Q_UNUSED(event)
if (!m_backend->isBacklightOff()) {
return false;
}
toggleBacklight();
return true;
}
bool BacklightInputEventFilter::keyEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_PowerOff && event->type() == QEvent::KeyRelease) {
toggleBacklight();
return true;
}
return m_backend->isBacklightOff();
}
bool BacklightInputEventFilter::touchDown(qint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(pos)
Q_UNUSED(time)
if (!m_backend->isBacklightOff()) {
return false;
}
if (m_touchPoints.isEmpty()) {
if (!m_doubleTapTimer.isValid()) {
// this is the first tap
m_doubleTapTimer.start();
} else {
if (m_doubleTapTimer.elapsed() < qApp->doubleClickInterval()) {
m_secondTap = true;
} else {
// took too long. Let's consider it a new click
m_doubleTapTimer.restart();
}
}
} else {
// not a double tap
m_doubleTapTimer.invalidate();
m_secondTap = false;
}
m_touchPoints << id;
return true;
}
bool BacklightInputEventFilter::touchUp(qint32 id, quint32 time)
{
Q_UNUSED(time)
m_touchPoints.removeAll(id);
if (!m_backend->isBacklightOff()) {
return false;
}
if (m_touchPoints.isEmpty() && m_doubleTapTimer.isValid() && m_secondTap) {
if (m_doubleTapTimer.elapsed() < qApp->doubleClickInterval()) {
toggleBacklight();
}
m_doubleTapTimer.invalidate();
m_secondTap = false;
}
return true;
}
bool BacklightInputEventFilter::touchMotion(qint32 id, const QPointF &pos, quint32 time)
{
Q_UNUSED(id)
Q_UNUSED(pos)
Q_UNUSED(time)
return m_backend->isBacklightOff();
}
void BacklightInputEventFilter::toggleBacklight()
{
// queued to not modify the list of event filters while filtering
QMetaObject::invokeMethod(m_backend, "toggleBlankOutput", Qt::QueuedConnection);
}
HwcomposerBackend::HwcomposerBackend(QObject *parent)
: Platform(parent)
{
if (!QDBusConnection::sessionBus().connect(QStringLiteral("org.kde.Solid.PowerManagement"),
QStringLiteral("/org/kde/Solid/PowerManagement/Actions/BrightnessControl"),
QStringLiteral("org.kde.Solid.PowerManagement.Actions.BrightnessControl"),
QStringLiteral("brightnessChanged"), this,
SLOT(screenBrightnessChanged(int)))) {
qCWarning(KWIN_HWCOMPOSER) << "Failed to connect to brightness control";
}
setPerScreenRenderingEnabled(false);
}
HwcomposerBackend::~HwcomposerBackend()
{
if (!m_outputBlank) {
toggleBlankOutput();
}
if (sceneEglDisplay() != EGL_NO_DISPLAY) {
eglTerminate(sceneEglDisplay());
}
}
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?
m_device = hwcDevice;
m_hwcVersion = m_device->common.version;
if ((m_hwcVersion & 0xffff0000) == 0) {
// Assume header version is always 1
uint32_t header_version = 1;
// Legacy version encoding
m_hwcVersion = (m_hwcVersion << 16) | header_version;
}
// register callbacks
hwc_procs_t *procs = new hwc_procs_t;
procs->invalidate = [] (const struct hwc_procs* procs) {
Q_UNUSED(procs)
};
procs->vsync = [] (const struct hwc_procs* procs, int disp, int64_t timestamp) {
Q_UNUSED(procs)
if (disp != 0) {
return;
}
dynamic_cast<HwcomposerBackend*>(kwinApp()->platform())->wakeVSync();
};
procs->hotplug = [] (const struct hwc_procs* procs, int disp, int connected) {
Q_UNUSED(procs)
Q_UNUSED(disp)
Q_UNUSED(connected)
};
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
m_output.reset(new HwcomposerOutput(hwcDevice));
if (!m_output->isValid()) {
emit initFailed();
return;
}
if (m_output->refreshRate() != 0) {
m_vsyncInterval = 1000000/m_output->refreshRate();
}
emit outputAdded(m_output.data());
emit outputEnabled(m_output.data());
if (m_lights) {
using namespace KWaylandServer;
auto updateDpms = [this] {
if (!m_output || !m_output->waylandOutput()) {
m_output->waylandOutput()->setDpmsMode(m_outputBlank ? OutputInterface::DpmsMode::Off : OutputInterface::DpmsMode::On);
}
};
connect(this, &HwcomposerBackend::outputBlankChanged, this, updateDpms);
connect(m_output.data(), &HwcomposerOutput::dpmsModeRequested, this,
[this] (KWaylandServer::OutputInterface::DpmsMode mode) {
if (mode == OutputInterface::DpmsMode::On) {
if (m_outputBlank) {
toggleBlankOutput();
}
} else {
if (!m_outputBlank) {
toggleBlankOutput();
}
}
}
);
}
emit screensQueried();
setReady(true);
}
QSize HwcomposerBackend::size() const
{
if (m_output) {
return m_output->pixelSize();
}
return QSize();
}
QSize HwcomposerBackend::screenSize() const
{
if (m_output) {
return m_output->pixelSize() / m_output->scale();
}
return QSize();
}
int HwcomposerBackend::scale() const
{
if (m_output) {
return m_output->scale();
}
return 1;
}
void HwcomposerBackend::initLights()
{
hw_module_t *lightsModule = nullptr;
if (hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (const hw_module_t **)&lightsModule) != 0) {
qCWarning(KWIN_HWCOMPOSER) << "Failed to get lights module";
return;
}
light_device_t *lightsDevice = nullptr;
if (lightsModule->methods->open(lightsModule, LIGHT_ID_BACKLIGHT, (hw_device_t **)&lightsDevice) != 0) {
qCWarning(KWIN_HWCOMPOSER) << "Failed to create lights device";
return;
}
m_lights = lightsDevice;
}
void HwcomposerBackend::toggleBlankOutput()
{
if (!m_device) {
return;
}
m_outputBlank = !m_outputBlank;
toggleScreenBrightness();
#if defined(HWC_DEVICE_API_VERSION_1_4) || defined(HWC_DEVICE_API_VERSION_1_5)
if (m_hwcVersion > HWC_DEVICE_API_VERSION_1_3)
m_device->setPowerMode(m_device, 0, m_outputBlank ? HWC_POWER_MODE_OFF : HWC_POWER_MODE_NORMAL);
else
#endif
m_device->blank(m_device, 0, m_outputBlank ? 1 : 0);
// only disable Vsync, enable happens after next frame rendered
if (m_outputBlank) {
enableVSync(false);
}
// enable/disable compositor repainting when blanked
setOutputsEnabled(!m_outputBlank);
if (Compositor *compositor = Compositor::self()) {
if (!m_outputBlank) {
compositor->addRepaintFull();
}
}
emit outputBlankChanged();
}
void HwcomposerBackend::toggleScreenBrightness()
{
if (!m_lights) {
return;
}
const int brightness = m_outputBlank ? 0 : m_oldScreenBrightness;
struct light_state_t state;
state.flashMode = LIGHT_FLASH_NONE;
state.brightnessMode = BRIGHTNESS_MODE_USER;
state.color = (int)((0xffU << 24) | (brightness << 16) |
(brightness << 8) | brightness);
m_lights->set_light(m_lights, &state);
}
void HwcomposerBackend::enableVSync(bool enable)
{
if (m_hasVsync == enable) {
return;
}
const int result = m_device->eventControl(m_device, 0, HWC_EVENT_VSYNC, enable ? 1: 0);
m_hasVsync = enable && (result == 0);
}
HwcomposerWindow *HwcomposerBackend::createSurface()
{
return new HwcomposerWindow(this);
}
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);
}
void HwcomposerBackend::waitVSync()
{
if (!m_hasVsync) {
return;
}
m_vsyncMutex.lock();
m_vsyncWaitCondition.wait(&m_vsyncMutex, m_vsyncInterval);
m_vsyncMutex.unlock();
}
void HwcomposerBackend::wakeVSync()
{
m_vsyncMutex.lock();
m_vsyncWaitCondition.wakeAll();
m_vsyncMutex.unlock();
}
static void initLayer(hwc_layer_1_t *layer, const hwc_rect_t &rect, int layerCompositionType)
{
memset(layer, 0, sizeof(hwc_layer_1_t));
layer->compositionType = layerCompositionType;
layer->hints = 0;
layer->flags = 0;
layer->handle = 0;
layer->transform = 0;
layer->blending = HWC_BLENDING_NONE;
#ifdef HWC_DEVICE_API_VERSION_1_3
layer->sourceCropf.top = 0.0f;
layer->sourceCropf.left = 0.0f;
layer->sourceCropf.bottom = (float) rect.bottom;
layer->sourceCropf.right = (float) rect.right;
#else
layer->sourceCrop = rect;
#endif
layer->displayFrame = rect;
layer->visibleRegionScreen.numRects = 1;
layer->visibleRegionScreen.rects = &layer->displayFrame;
layer->acquireFenceFd = -1;
layer->releaseFenceFd = -1;
layer->planeAlpha = 0xFF;
#ifdef HWC_DEVICE_API_VERSION_1_5
layer->surfaceDamage.numRects = 0;
#endif
}
HwcomposerWindow::HwcomposerWindow(HwcomposerBackend *backend)
: HWComposerNativeWindow(backend->size().width(), backend->size().height(), HAL_PIXEL_FORMAT_RGBA_8888)
, m_backend(backend)
{
setBufferCount(3);
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] = nullptr;
}
// Assign buffer only to the first item, otherwise you get tearing
// if passed the same to multiple places
// see https://github.com/mer-hybris/qt5-qpa-hwcomposer-plugin/commit/f1d802151e8a4f5d10d60eb8de8e07552b93a34a
m_list[0] = list;
const hwc_rect_t rect = {
0,
0,
m_backend->size().width(),
m_backend->size().height()
};
initLayer(&list->hwLayers[0], rect, HWC_FRAMEBUFFER);
initLayer(&list->hwLayers[1], rect, HWC_FRAMEBUFFER_TARGET);
list->retireFenceFd = -1;
list->flags = HWC_GEOMETRY_CHANGED;
list->numHwLayers = 2;
}
HwcomposerWindow::~HwcomposerWindow()
{
// TODO: cleanup
}
void HwcomposerWindow::present(HWComposerNativeWindowBuffer *buffer)
{
m_backend->waitVSync();
hwc_composer_device_1_t *device = m_backend->device();
auto fblayer = &m_list[0]->hwLayers[1];
fblayer->handle = buffer->handle;
fblayer->acquireFenceFd = getFenceBufferFd(buffer);
fblayer->releaseFenceFd = -1;
int err = device->prepare(device, 1, m_list);
Q_ASSERT(err == 0);
err = device->set(device, 1, m_list);
Q_ASSERT(err == 0);
m_backend->enableVSync(true);
setFenceBufferFd(buffer, fblayer->releaseFenceFd);
if (m_list[0]->retireFenceFd != -1) {
close(m_list[0]->retireFenceFd);
m_list[0]->retireFenceFd = -1;
}
m_list[0]->flags = 0;
}
HwcomposerOutput::HwcomposerOutput(hwc_composer_device_1_t *device)
: AbstractWaylandOutput()
, 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 pixelSize(attr_values[0], attr_values[1]);
if (pixelSize.isEmpty()) {
return;
}
QSizeF physicalSize;
if (attr_values[2] != 0 && attr_values[3] != 0) {
static const qreal factor = 25.4;
physicalSize = QSizeF(qreal(pixelSize.width() * 1000) / qreal(attr_values[2]) * factor,
qreal(pixelSize.height() * 1000) / qreal(attr_values[3]) * factor);
} else {
// couldn't read physical size, assume 96 dpi
physicalSize = pixelSize / 3.8;
}
OutputDeviceInterface::Mode mode;
mode.id = 0;
mode.size = pixelSize;
mode.flags = OutputDeviceInterface::ModeFlag::Current | OutputDeviceInterface::ModeFlag::Preferred;
mode.refreshRate = (attr_values[4] == 0) ? 60000 : 10E11/attr_values[4];
initInterfaces(QString(), QString(), QByteArray(), physicalSize.toSize(), {mode});
setInternal(true);
setDpmsSupported(true);
const auto outputGroup = kwinApp()->config()->group("HWComposerOutputs").group("0");
setScale(outputGroup.readEntry("Scale", 1));
setWaylandMode(pixelSize, mode.refreshRate);
}
HwcomposerOutput::~HwcomposerOutput()
{
hwc_close_1(m_device);
}
bool HwcomposerOutput::isValid() const
{
return isEnabled();
}
void HwcomposerOutput::updateDpms(KWaylandServer::OutputInterface::DpmsMode mode)
{
emit dpmsModeRequested(mode);
}
}

View file

@ -1,154 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef KWIN_HWCOMPOSER_BACKEND_H
#define KWIN_HWCOMPOSER_BACKEND_H
#include "platform.h"
#include "abstract_wayland_output.h"
#include "input.h"
#include <QElapsedTimer>
#include <QMutex>
#include <QWaitCondition>
#include <android-config.h>
// libhybris
#include <hardware/hwcomposer.h>
#include <hwcomposer_window.h>
// needed as hwcomposer_window.h includes EGL which on non-arm includes Xlib
#include <fixx11h.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;
struct light_device_t;
class HWComposerNativeWindowBuffer;
namespace KWin
{
class HwcomposerWindow;
class BacklightInputEventFilter;
class HwcomposerOutput : public AbstractWaylandOutput
{
Q_OBJECT
public:
HwcomposerOutput(hwc_composer_device_1_t *device);
~HwcomposerOutput() override;
bool isValid() const;
void updateDpms(KWaylandServer::OutputInterface::DpmsMode mode) override;
Q_SIGNALS:
void dpmsModeRequested(KWaylandServer::OutputInterface::DpmsMode mode);
private:
QSize m_pixelSize;
hwc_composer_device_1_t *m_device;
};
class HwcomposerBackend : public Platform
{
Q_OBJECT
Q_INTERFACES(KWin::Platform)
Q_PLUGIN_METADATA(IID "org.kde.kwin.Platform" FILE "hwcomposer.json")
public:
explicit HwcomposerBackend(QObject *parent = nullptr);
virtual ~HwcomposerBackend();
void init() override;
OpenGLBackend *createOpenGLBackend() override;
Outputs outputs() const override;
Outputs enabledOutputs() const override;
QSize size() const;
QSize screenSize() const override;
int scale() const;
HwcomposerWindow *createSurface();
hwc_composer_device_1_t *device() const {
return m_device;
}
void enableVSync(bool enable);
void waitVSync();
void wakeVSync();
bool isBacklightOff() const {
return m_outputBlank;
}
QVector<CompositingType> supportedCompositors() const override {
return QVector<CompositingType>{OpenGLCompositing};
}
Q_SIGNALS:
void outputBlankChanged();
private Q_SLOTS:
void toggleBlankOutput();
void screenBrightnessChanged(int brightness) {
m_oldScreenBrightness = brightness;
}
private:
void initLights();
void toggleScreenBrightness();
hwc_composer_device_1_t *m_device = nullptr;
light_device_t *m_lights = nullptr;
bool m_outputBlank = true;
int m_vsyncInterval = 16;
uint32_t m_hwcVersion;
int m_oldScreenBrightness = 0x7f;
bool m_hasVsync = false;
QMutex m_vsyncMutex;
QWaitCondition m_vsyncWaitCondition;
QScopedPointer<BacklightInputEventFilter> m_filter;
QScopedPointer<HwcomposerOutput> m_output;
};
class HwcomposerWindow : public HWComposerNativeWindow
{
public:
virtual ~HwcomposerWindow();
void present(HWComposerNativeWindowBuffer *buffer);
private:
friend HwcomposerBackend;
HwcomposerWindow(HwcomposerBackend *backend);
HwcomposerBackend *m_backend;
hwc_display_contents_1_t **m_list;
};
class BacklightInputEventFilter : public InputEventFilter
{
public:
BacklightInputEventFilter(HwcomposerBackend *backend);
virtual ~BacklightInputEventFilter();
bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override;
bool wheelEvent(QWheelEvent *event) override;
bool keyEvent(QKeyEvent *event) override;
bool touchDown(qint32 id, const QPointF &pos, quint32 time) override;
bool touchMotion(qint32 id, const QPointF &pos, quint32 time) override;
bool touchUp(qint32 id, quint32 time) override;
private:
void toggleBacklight();
HwcomposerBackend *m_backend;
QElapsedTimer m_doubleTapTimer;
QVector<qint32> m_touchPoints;
bool m_secondTap = false;
};
}
#endif

View file

@ -1,10 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "logging.h"
Q_LOGGING_CATEGORY(KWIN_HWCOMPOSER, "kwin_wayland_hwcomposer", QtCriticalMsg)

View file

@ -1,15 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-3.0-or-later
*/
#ifndef KWIN_FB_LOGGING_H
#define KWIN_FB_LOGGING_H
#include <QDebug>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(KWIN_HWCOMPOSER)
#endif