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
icc-effect-5.26.4
parent
ae440bdc25
commit
7e5c16989e
|
@ -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"
|
||||
|
|
|
@ -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."
|
||||
)
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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/
|
||||
)
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
Loading…
Reference in New Issue