1
0
mirror of https://invent.kde.org/network/krfb synced 2024-07-03 08:28:35 +00:00

Implement GBM framebuffer for KWin wayland server

This commit creates a new plugin for KWin-on-Wayland integration. It is
independent from X11 and uses GBM and custom Wayland protocol to pass buffers
from KWin side to KRfb.

It also introduces mentioned components as an optional dependencies to
KRfb and is build only if all of them are present (which is highly
likely on a modern system)

- No support for input yet
- No support for multi-screen yet
- No support for resizing yet
This commit is contained in:
Oleg Chernovskiy 2016-02-14 23:32:37 +03:00
parent 469782625a
commit d517bf8573
15 changed files with 1004 additions and 4 deletions

View File

@ -6,7 +6,7 @@ include(FeatureSummary)
find_package(Qt5 REQUIRED COMPONENTS Core DBus Widgets X11Extras)
find_package(ECM 1.7.0 NO_MODULE REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
include(KDEInstallDirs)
include(KDECMakeSettings)
@ -29,6 +29,39 @@ find_package(KF5 REQUIRED COMPONENTS
XmlGui
)
find_package(KF5Wayland CONFIG)
set_package_properties(KF5Wayland PROPERTIES DESCRIPTION "KDE Frameworks Wayland integration package"
URL "https://github.com/KDE/kwayland"
TYPE OPTIONAL
PURPOSE "Required for wayland integration with KWin server"
)
find_package(epoxy)
set_package_properties(epoxy PROPERTIES DESCRIPTION "libepoxy"
URL "http://github.com/anholt/libepoxy"
TYPE OPTIONAL
PURPOSE "OpenGL dispatch library for GBM backend"
)
find_package(Libdrm)
set_package_properties(Libdrm PROPERTIES DESCRIPTION "Libdrm"
TYPE OPTIONAL
PURPOSE "Required for GBM access to compositor buffers on Wayland"
)
set(HAVE_DRM FALSE)
if(KF5Wayland_FOUND AND Libdrm_FOUND AND epoxy_FOUND)
set(HAVE_DRM TRUE)
endif()
find_package(gbm)
set_package_properties(gbm PROPERTIES TYPE OPTIONAL PURPOSE "Required for egl ouput of drm backend.")
set(HAVE_GBM FALSE)
if(HAVE_DRM AND gbm_FOUND)
set(HAVE_GBM TRUE)
endif()
find_package(X11 REQUIRED)
if(WIN32)

View File

@ -0,0 +1,126 @@
#.rst:
# FindLibdrm
# -------
#
# Try to find libdrm on a Unix system.
#
# This will define the following variables:
#
# ``Libdrm_FOUND``
# True if (the requested version of) libdrm is available
# ``Libdrm_VERSION``
# The version of libdrm
# ``Libdrm_LIBRARIES``
# This can be passed to target_link_libraries() instead of the ``Libdrm::Libdrm``
# target
# ``Libdrm_INCLUDE_DIRS``
# This should be passed to target_include_directories() if the target is not
# used for linking
# ``Libdrm_DEFINITIONS``
# This should be passed to target_compile_options() if the target is not
# used for linking
#
# If ``Libdrm_FOUND`` is TRUE, it will also define the following imported target:
#
# ``Libdrm::Libdrm``
# The libdrm library
#
# In general we recommend using the imported target, as it is easier to use.
# Bear in mind, however, that if the target is in the link interface of an
# exported library, it must be made available by the package config file.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# 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 FindLibdrm.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 FindLibdrm.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_Libdrm QUIET libdrm)
set(Libdrm_DEFINITIONS ${PKG_Libdrm_CFLAGS_OTHER})
set(Libdrm_VERSION ${PKG_Libdrm_VERSION})
find_path(Libdrm_INCLUDE_DIR
NAMES
xf86drm.h
HINTS
${PKG_Libdrm_INCLUDE_DIRS}
)
find_library(Libdrm_LIBRARY
NAMES
drm
HINTS
${PKG_Libdrm_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libdrm
FOUND_VAR
Libdrm_FOUND
REQUIRED_VARS
Libdrm_LIBRARY
Libdrm_INCLUDE_DIR
VERSION_VAR
Libdrm_VERSION
)
if(Libdrm_FOUND AND NOT TARGET Libdrm::Libdrm)
add_library(Libdrm::Libdrm UNKNOWN IMPORTED)
set_target_properties(Libdrm::Libdrm PROPERTIES
IMPORTED_LOCATION "${Libdrm_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${Libdrm_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}"
INTERFACE_INCLUDE_DIRECTORIES "${Libdrm_INCLUDE_DIR}/libdrm"
)
endif()
mark_as_advanced(Libdrm_LIBRARY Libdrm_INCLUDE_DIR)
# compatibility variables
set(Libdrm_LIBRARIES ${Libdrm_LIBRARY})
set(Libdrm_INCLUDE_DIRS ${Libdrm_INCLUDE_DIR})
set(Libdrm_VERSION_STRING ${Libdrm_VERSION})
else()
message(STATUS "FindLibdrm.cmake cannot find libdrm on Windows systems.")
set(Libdrm_FOUND FALSE)
endif()
include(FeatureSummary)
set_package_properties(Libdrm PROPERTIES
URL "https://wiki.freedesktop.org/dri/"
DESCRIPTION "Userspace interface to kernel DRM services."
)

View File

@ -0,0 +1,56 @@
# - Try to find libepoxy
# Once done this will define
#
# epoxy_FOUND - System has libepoxy
# epoxy_LIBRARY - The libepoxy library
# epoxy_INCLUDE_DIR - The libepoxy include dir
# epoxy_DEFINITIONS - Compiler switches required for using libepoxy
# epoxy_HAS_GLX - Whether GLX support is available
# Copyright (c) 2014 Fredrik Höglund <fredrik@kde.org>
#
# 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 above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 (NOT WIN32)
find_package(PkgConfig)
pkg_check_modules(PKG_epoxy QUIET epoxy)
set(epoxy_DEFINITIONS ${PKG_epoxy_CFLAGS})
find_path(epoxy_INCLUDE_DIR NAMES epoxy/gl.h HINTS ${PKG_epoxy_INCLUDEDIR} ${PKG_epoxy_INCLUDE_DIRS})
find_library(epoxy_LIBRARY NAMES epoxy HINTS ${PKG_epoxy_LIBDIR} ${PKG_epoxy_LIBRARY_DIRS})
find_file(epoxy_GLX_HEADER NAMES epoxy/glx.h HINTS ${epoxy_INCLUDE_DIR})
if (epoxy_GLX_HEADER STREQUAL "epoxy_GLX_HEADER-NOTFOUND")
set(epoxy_HAS_GLX FALSE CACHE BOOL "whether glx is available")
else ()
set(epoxy_HAS_GLX TRUE CACHE BOOL "whether glx is available")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(epoxy DEFAULT_MSG epoxy_LIBRARY epoxy_INCLUDE_DIR)
mark_as_advanced(epoxy_INCLUDE_DIR epoxy_LIBRARY epoxy_HAS_GLX)
endif()

125
cmake/modules/Findgbm.cmake Normal file
View File

@ -0,0 +1,125 @@
#.rst:
# Findgbm
# -------
#
# Try to find gbm on a Unix system.
#
# This will define the following variables:
#
# ``gbm_FOUND``
# True if (the requested version of) gbm is available
# ``gbm_VERSION``
# The version of gbm
# ``gbm_LIBRARIES``
# This can be passed to target_link_libraries() instead of the ``gbm::gbm``
# target
# ``gbm_INCLUDE_DIRS``
# This should be passed to target_include_directories() if the target is not
# used for linking
# ``gbm_DEFINITIONS``
# This should be passed to target_compile_options() if the target is not
# used for linking
#
# If ``gbm_FOUND`` is TRUE, it will also define the following imported target:
#
# ``gbm::gbm``
# The gbm library
#
# In general we recommend using the imported target, as it is easier to use.
# Bear in mind, however, that if the target is in the link interface of an
# exported library, it must be made available by the package config file.
#=============================================================================
# Copyright 2014 Alex Merry <alex.merry@kde.org>
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# 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 Findgbm.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 Findgbm.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_gbm QUIET gbm)
set(gbm_DEFINITIONS ${PKG_gbm_CFLAGS_OTHER})
set(gbm_VERSION ${PKG_gbm_VERSION})
find_path(gbm_INCLUDE_DIR
NAMES
gbm.h
HINTS
${PKG_gbm_INCLUDE_DIRS}
)
find_library(gbm_LIBRARY
NAMES
gbm
HINTS
${PKG_gbm_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gbm
FOUND_VAR
gbm_FOUND
REQUIRED_VARS
gbm_LIBRARY
gbm_INCLUDE_DIR
VERSION_VAR
gbm_VERSION
)
if(gbm_FOUND AND NOT TARGET gbm::gbm)
add_library(gbm::gbm UNKNOWN IMPORTED)
set_target_properties(gbm::gbm PROPERTIES
IMPORTED_LOCATION "${gbm_LIBRARY}"
INTERFACE_COMPILE_OPTIONS "${gbm_DEFINITIONS}"
INTERFACE_INCLUDE_DIRECTORIES "${gbm_INCLUDE_DIR}"
)
endif()
mark_as_advanced(gbm_LIBRARY gbm_INCLUDE_DIR)
# compatibility variables
set(gbm_LIBRARIES ${gbm_LIBRARY})
set(gbm_INCLUDE_DIRS ${gbm_INCLUDE_DIR})
set(gbm_VERSION_STRING ${gbm_VERSION})
else()
message(STATUS "Findgbm.cmake cannot find gbm on Windows systems.")
set(gbm_FOUND FALSE)
endif()
include(FeatureSummary)
set_package_properties(gbm PROPERTIES
URL "http://www.mesa3d.org"
DESCRIPTION "Mesa gbm library."
)

View File

@ -1,3 +1,5 @@
add_subdirectory (qt)
add_subdirectory (x11)
if(HAVE_GBM)
add_subdirectory (gbm)
endif()

View File

@ -0,0 +1,29 @@
include_directories (${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set (krfb_framebuffer_gbm_SRCS
logging.cpp
gbmframebuffer.cpp
gbmframebufferplugin.cpp
)
add_library(krfb_framebuffer_gbm
MODULE
${krfb_framebuffer_gbm_SRCS}
)
target_link_libraries (krfb_framebuffer_gbm
Qt5::Core
Qt5::Gui
KF5::CoreAddons
KF5::WaylandClient
${epoxy_LIBRARY}
Libdrm::Libdrm
gbm::gbm
krfbprivate
)
install (TARGETS krfb_framebuffer_gbm
DESTINATION ${PLUGIN_INSTALL_DIR}/krfb
)

View File

@ -0,0 +1,330 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "gbmframebuffer.h"
#include "logging.h"
#include "gbmframebuffer.moc"
// KWayland
#include <KWayland/Client/registry.h>
#include <KWayland/Client/connection_thread.h>
#include <KWayland/Client/remote_access.h>
// Qt
#include <QApplication>
#include <QScreen>
#include <QtCore/QThread>
// system
#include <fcntl.h>
#include <sys/mman.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <libdrm/drm_mode.h>
static QString formatGLError(GLenum err)
{
switch(err) {
case GL_NO_ERROR: return QStringLiteral("GL_NO_ERROR");
case GL_INVALID_ENUM: return QStringLiteral("GL_INVALID_ENUM");
case GL_INVALID_VALUE: return QStringLiteral("GL_INVALID_VALUE");
case GL_INVALID_OPERATION: return QStringLiteral("GL_INVALID_OPERATION");
case GL_STACK_OVERFLOW: return QStringLiteral("GL_STACK_OVERFLOW");
case GL_STACK_UNDERFLOW: return QStringLiteral("GL_STACK_UNDERFLOW");
case GL_OUT_OF_MEMORY: return QStringLiteral("GL_OUT_OF_MEMORY");
default: return QLatin1String("0x") + QString::number(err, 16);
}
}
GbmFrameBuffer::GbmFrameBuffer(WId id, QObject *parent)
: FrameBuffer(id, parent)
{
// TODO: check out the case when new resolution was applied on KWin side
// TODO: check possibility of multi-screen configuration
QSize size = QApplication::screens().first()->size();
m_img = new QImage(size, QImage::Format_ARGB32);
fb = reinterpret_cast<char*>(m_img->bits());
// open DRM device
setupDrm();
// get EGL client extensions
initClientEglExtensions();
// initialize EGL context and display
initEgl();
// get KWin connection
initWaylandConnection();
}
void GbmFrameBuffer::setupDrm()
{
m_drmFd = open("/dev/dri/card0", O_RDWR);
m_gbmDevice = gbm_create_device(m_drmFd);
if(!m_gbmDevice) {
qCCritical(KRFB_GBM) << "Cannot create GBM device:" << strerror(errno);
m_valid = false;
return;
}
}
// cloned from KWin AbstractEglBackend
void GbmFrameBuffer::initClientEglExtensions()
{
if(!m_valid)
return;
// Get the list of client extensions
const char* clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
if (clientExtensionsString.isEmpty()) {
// If eglQueryString() returned NULL, the implementation doesn't support
// EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
qCCritical(KRFB_GBM) << "No client extensions defined!" << formatGLError(eglGetError());
m_valid = false;
}
m_egl.extensions = clientExtensionsString.split(' ');
}
void GbmFrameBuffer::initEgl()
{
if(!m_valid)
return;
// Use eglGetPlatformDisplayEXT() to get the display pointer
// if the implementation supports it.
if (!m_egl.extensions.contains(QByteArrayLiteral("EGL_EXT_platform_base")) ||
!m_egl.extensions.contains(QByteArrayLiteral("EGL_MESA_platform_gbm"))) {
qCCritical(KRFB_GBM) << "One of required EGL extensions is missing";
m_valid = false;
return;
}
m_egl.display = eglGetPlatformDisplayEXT(EGL_PLATFORM_GBM_MESA, m_gbmDevice, nullptr);
if (m_egl.display == EGL_NO_DISPLAY) {
qCCritical(KRFB_GBM) << "Error during obtaining EGL display:" << formatGLError(eglGetError());
m_valid = false;
return;
}
EGLint major, minor;
if (eglInitialize(m_egl.display, &major, &minor) == EGL_FALSE) {
qCCritical(KRFB_GBM) << "Error during eglInitialize:" << formatGLError(eglGetError());
m_valid = false;
return;
}
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KRFB_GBM) << "bind OpenGL API failed";
m_valid = false;
return;
}
qCDebug(KRFB_GBM) << "Egl Initialize succeeded";
qCDebug(KRFB_GBM) << QString("EGL version: %1.%2").arg(major).arg(minor);
m_egl.context = eglCreateContext(m_egl.display, nullptr, EGL_NO_CONTEXT, nullptr);
if(m_egl.context == EGL_NO_CONTEXT) {
qCCritical(KRFB_GBM) << "Couldn't create EGL context:" << formatGLError(eglGetError());
m_valid = false;
}
}
void GbmFrameBuffer::initWaylandConnection()
{
if(!m_valid)
return;
using namespace KWayland::Client;
ConnectionThread *conn = ConnectionThread::fromApplication(this);
if(!conn) { // trying to instantiate wayland not having a wayland platform?
m_valid = false;
return;
}
// what do we do if server dies?
// since we use foreign connection, the whole application will be disconnected,
// not only plugin, let's assume application will die anyway
Registry *registry = new Registry(this);
registry->create(conn);
connect(registry, &Registry::remoteAccessManagerAnnounced, this,
[this, registry] (qint32 name, qint32 version) {
m_interface = registry->createRemoteAccessManager(name, version, this);
connect(m_interface, &RemoteAccessManager::bufferReady, this, &GbmFrameBuffer::obtainBuffer);
}
);
registry->setup();
}
void GbmFrameBuffer::obtainBuffer(KWayland::Client::RemoteBuffer *rbuf)
{
using namespace KWayland::Client;
connect(rbuf, &RemoteBuffer::paramsObtained, this,
[this, rbuf] (qint32 fd, quint32 width, quint32 height, quint32 stride, quint32 format) {
updateHandle(fd, width, height, stride, format);
// deleteLater() is not working due to QTBUG-18434 (or similar)
// TODO: try with Qt 5.8.0
delete rbuf;
}
);
}
void GbmFrameBuffer::updateHandle(qint32 gbmHandle, quint32 width, quint32 height, quint32 stride, quint32 format)
{
qCDebug(KRFB_GBM) << QString("Incoming GBM fd %1, %2x%3, stride %4, fourcc 0x%5")
.arg(gbmHandle).arg(width).arg(height).arg(stride).arg(QString::number(format, 16));
if(!gbm_device_is_format_supported(m_gbmDevice, format, GBM_BO_USE_SCANOUT)) {
qCCritical(KRFB_GBM) << "GBM format is not supported by device!";
return;
}
if(this->width() != (int) width || this->height() != (int) height) {
qCCritical(KRFB_GBM) << QString("Size of GBM buffer (%3x%4) is not equal to expected (%1x%2)!")
.arg(this->width()).arg(this->height()).arg(width).arg(height);
return;
}
// import GBM buffer that was passed from KWin
gbm_import_fd_data importInfo = {gbmHandle, width, height, stride, format};
gbm_bo *imported = gbm_bo_import(m_gbmDevice, GBM_BO_IMPORT_FD, &importInfo, GBM_BO_USE_SCANOUT);
if(!imported) {
qCCritical(KRFB_GBM) << "Cannot import passed GBM fd:" << strerror(errno);
return;
}
// bind context to render thread
eglMakeCurrent(m_egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, m_egl.context);
// create EGL image from imported BO
EGLImageKHR image = eglCreateImageKHR(m_egl.display, NULL, EGL_NATIVE_PIXMAP_KHR, imported, NULL);
if (image == EGL_NO_IMAGE_KHR) {
qCCritical(KRFB_GBM) << "Error creating EGLImageKHR" << formatGLError(glGetError());
return;
}
// create GL 2D texture for framebuffer
GLuint texture;
glGenTextures(1, &texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, texture);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
// bind framebuffer to copy pixels from
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
const GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
qCCritical(KRFB_GBM) << "glCheckFramebufferStatus failed:" << formatGLError(glGetError());
glDeleteTextures(1, &texture);
glDeleteFramebuffers(1, &framebuffer);
eglDestroyImageKHR(m_egl.display, image);
return;
}
glViewport(0, 0, width, height);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_img->bits());
tiles.append(m_img->rect());
// unbind all
glDeleteTextures(1, &texture);
glDeleteFramebuffers(1, &framebuffer);
eglDestroyImageKHR(m_egl.display, image);
// from this point buffer object can be safely freed
close(gbmHandle);
}
GbmFrameBuffer::~GbmFrameBuffer()
{
fb = nullptr;
delete m_img;
m_img = nullptr;
if(m_egl.context != EGL_NO_CONTEXT) {
eglDestroyContext(m_egl.display, m_egl.context);
}
if(m_gbmDevice) {
gbm_device_destroy(m_gbmDevice);
}
if(m_drmFd) {
close(m_drmFd);
}
}
int GbmFrameBuffer::depth()
{
return m_img->depth();
}
int GbmFrameBuffer::height()
{
return m_img->height();
}
int GbmFrameBuffer::width()
{
return m_img->width();
}
void GbmFrameBuffer::getServerFormat(rfbPixelFormat &format)
{
format.bitsPerPixel = 32;
format.depth = 32;
format.trueColour = true;
format.bigEndian = false;
// GL images have different shift
format.redShift = 0;
format.greenShift = 8;
format.blueShift = 16;
format.redMax = 0xff;
format.greenMax = 0xff;
format.blueMax = 0xff;
}
void GbmFrameBuffer::updateFrameBuffer()
{
// do nothing
}
int GbmFrameBuffer::paddedWidth()
{
return m_img->bytesPerLine();
}
void GbmFrameBuffer::startMonitor()
{
// not needed - we get events as a signals from Wayland interface
// no other updates are possible
}
void GbmFrameBuffer::stopMonitor()
{
}

View File

@ -0,0 +1,85 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFER_H
#define KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFER_H
#include "framebuffer.h"
// Qt
#include <QImage>
// system
#include <gbm.h>
#include <epoxy/egl.h>
#include <epoxy/gl.h>
namespace KWayland
{
namespace Client
{
class RemoteAccessManager;
class RemoteBuffer;
}
}
/**
@author Oleg Chernovskiy <adonai@xaker.ru>
*/
class GbmFrameBuffer : public FrameBuffer
{
Q_OBJECT
public:
explicit GbmFrameBuffer(WId id, QObject *parent = 0);
~GbmFrameBuffer();
int depth() override;
int height() override;
int width() override;
int paddedWidth() override;
void getServerFormat(rfbPixelFormat &format) override;
void startMonitor() override;
void stopMonitor() override;
inline bool isValid() { return m_valid; };
public Q_SLOTS:
void updateFrameBuffer();
private:
void initWaylandConnection();
void setupDrm();
void initClientEglExtensions();
void initEgl();
void obtainBuffer(KWayland::Client::RemoteBuffer *rbuf);
void updateHandle(qint32 gbmHandle, quint32 width, quint32 height, quint32 stride, quint32 format);
qint32 m_drmFd = 0; // for GBM buffer mmap
gbm_device *m_gbmDevice = nullptr; // for passed GBM buffer retrieval
struct {
QList<QByteArray> extensions;
EGLDisplay display = EGL_NO_DISPLAY;
EGLContext context = EGL_NO_CONTEXT;
} m_egl;
KWayland::Client::RemoteAccessManager *m_interface = nullptr;
QImage *m_img;
bool m_valid = true;
};
#endif

View File

@ -0,0 +1,50 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "gbmframebufferplugin.h"
#include "gbmframebuffer.h"
#include <KPluginFactory>
K_PLUGIN_FACTORY_WITH_JSON(GbmFrameBufferPluginFactory, "krfb_framebuffer_gbm.json",
registerPlugin<GbmFrameBufferPlugin>();)
GbmFrameBufferPlugin::GbmFrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
{
}
GbmFrameBufferPlugin::~GbmFrameBufferPlugin()
{
}
FrameBuffer *GbmFrameBufferPlugin::frameBuffer(WId id)
{
auto p = new GbmFrameBuffer(id);
if (!p->isValid()) {
delete p;
return nullptr;
}
return p;
}
#include "gbmframebufferplugin.moc"

View File

@ -0,0 +1,45 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFERPLUGIN_H
#define KRFB_FRAMEBUFFER_GBM_GBMFRAMEBUFFERPLUGIN_H
#include "framebufferplugin.h"
#include <QWidget>
class FrameBuffer;
class GbmFrameBufferPlugin : public FrameBufferPlugin
{
Q_OBJECT
public:
GbmFrameBufferPlugin(QObject *parent, const QVariantList &args);
virtual ~GbmFrameBufferPlugin();
FrameBuffer *frameBuffer(WId id) override;
private:
Q_DISABLE_COPY(GbmFrameBufferPlugin)
};
#endif // Header guard

View File

@ -0,0 +1,62 @@
{
"Encoding": "UTF-8",
"KPlugin": {
"Description": "GBM based Framebuffer for KRfb.",
"Description[ca@valencia]": "«Framebuffer» basat en GBM per al KRfb.",
"Description[ca]": "«Framebuffer» basat en GBM per al KRfb.",
"Description[cs]": "Framebuffer založený na GBM pro KRfb.",
"Description[de]": "GBM-basierter Framebuffer für KRfb",
"Description[es]": "Framebuffer basado en GBM para KRfb.",
"Description[fi]": "QT-perustainen Kehyspuskuri KRfb:lle",
"Description[gl]": "Framebuffer baseado en GBM para KRfb.",
"Description[it]": "Framebuffer basato su GBM per KRfb.",
"Description[ko]": "KRfb용 GBM 기반 프레임버퍼입니다.",
"Description[nl]": "Op GBM gebaseerd framebuffer voor KRfb.",
"Description[pl]": "Bufor ramki na podstawie GBM dla KRfb.",
"Description[pt]": "'Framebuffer' baseado no GBM para o KRfb.",
"Description[pt_BR]": "Framebuffer baseado no GBM para o KRfb.",
"Description[sk]": "Framebuffer založený na GBM pre KRfb.",
"Description[sl]": "Slikovni medpomnilnik za KRfb, ki temelji na GBM",
"Description[sr@ijekavian]": "Кадробафер за КРФБ на основу КуТу",
"Description[sr@ijekavianlatin]": "Kadrobafer za KRFB na osnovu GBMu",
"Description[sr@latin]": "Kadrobafer za KRFB na osnovu GBMu",
"Description[sr]": "Кадробафер за КРФБ на основу КуТу",
"Description[sv]": "X11-rambuffert för Krfb.",
"Description[uk]": "Заснований на GBM буфер кадрів для KRfb.",
"Description[x-test]": "xxGBM based Framebuffer for KRfb.xx",
"Description[zh_CN]": "KRfb 的基于 GBM 的帧缓冲。",
"EnabledByDefault": true,
"Id": "gbm",
"License": "GPL",
"Name": "GBM Framebuffer for KRfb",
"Name[ast]": "Framebuffer GBM pa KRfb",
"Name[ca@valencia]": "«Framebuffer» GBM per al KRfb.",
"Name[ca]": "«Framebuffer» GBM per al KRfb.",
"Name[cs]": "GBM Framebuffer pro KRfb",
"Name[de]": "GBM-Framebuffer für KRfb",
"Name[es]": "Framebuffer de GBM para KRfb",
"Name[fi]": "QT-kehyspuskuri KRfb:lle",
"Name[gl]": "Framebuffer de GBM para KRfb",
"Name[it]": "Framebuffer GBM per KRfb",
"Name[ko]": "KRfb용 GBM 프레임버퍼",
"Name[nl]": "GBM-framebuffer voor KRfb",
"Name[pl]": "Bufor ramki GBM dla KRfb",
"Name[pt]": "'Framebuffer' do GBM para o KRfb",
"Name[pt_BR]": "Framebuffer do GBM para o KRfb",
"Name[sk]": "GBM Framebuffer pre KRfb",
"Name[sl]": "Slikovni medpomnilnik GBM za KRfb",
"Name[sr@ijekavian]": "КуТ‑ов кадробафер за КРФБ",
"Name[sr@ijekavianlatin]": "GBMov kadrobafer za KRFB",
"Name[sr@latin]": "GBMov kadrobafer za KRFB",
"Name[sr]": "КуТ‑ов кадробафер за КРФБ",
"Name[sv]": "X11-rambuffert för Krfb",
"Name[uk]": "Буфер кадрів на GBM для KRfb",
"Name[x-test]": "xxGBM Framebuffer for KRfbxx",
"Name[zh_CN]": "KRfb 的 GBM 帧缓冲",
"ServiceTypes": [
"krfb/framebuffer"
],
"Version": "0.1",
"Website": "http://www.kde.org"
}
}

View File

@ -0,0 +1,21 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "logging.h"
Q_LOGGING_CATEGORY(KRFB_GBM, "krfb-gbm", QtCriticalMsg)

View File

@ -0,0 +1,26 @@
/* This file is part of the KDE project
Copyright (C) 2016 Oleg Chernovskiy <adonai@xaker.ru>
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; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KRFB_FRAMEBUFFER_GBM_LOGGING
#define KRFB_FRAMEBUFFER_GBM_LOGGING
#include <QDebug>
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(KRFB_GBM)
#endif

View File

@ -23,9 +23,10 @@
#include "qtframebuffer.h"
#include <KPluginFactory>
#include <QX11Info>
K_PLUGIN_FACTORY_WITH_JSON(QtFrameBufferPluginFactory, "krfb_framebuffer_qt.json",
registerPlugin<QtFrameBufferPlugin>();)
registerPlugin<QtFrameBufferPlugin>();)
QtFrameBufferPlugin::QtFrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
@ -38,6 +39,10 @@ QtFrameBufferPlugin::~QtFrameBufferPlugin()
FrameBuffer *QtFrameBufferPlugin::frameBuffer(WId id)
{
// works only under X11
if(!QX11Info::isPlatformX11())
return nullptr;
return new QtFrameBuffer(id);
}

View File

@ -23,9 +23,10 @@
#include "x11framebuffer.h"
#include <KPluginFactory>
#include <QX11Info>
K_PLUGIN_FACTORY_WITH_JSON(X11FrameBufferPluginFactory, "krfb_framebuffer_x11.json",
registerPlugin<X11FrameBufferPlugin>();)
registerPlugin<X11FrameBufferPlugin>();)
X11FrameBufferPlugin::X11FrameBufferPlugin(QObject *parent, const QVariantList &args)
: FrameBufferPlugin(parent, args)
@ -38,6 +39,10 @@ X11FrameBufferPlugin::~X11FrameBufferPlugin()
FrameBuffer *X11FrameBufferPlugin::frameBuffer(WId id)
{
// works only under X11
if(!QX11Info::isPlatformX11())
return nullptr;
return new X11FrameBuffer(id);
}