diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -1531,6 +1531,12 @@ m_pointer->processMotion(globalPointer() + QPointF(delta.width(), delta.height()), 0); } ); + connect(device, &FakeInputDevice::pointerMotionAbsoluteRequested, this, + [this] (const QPointF &pos) { + // TODO: Fix time + m_pointer->processMotion(pos, 0); + } + ); connect(device, &FakeInputDevice::pointerButtonPressRequested, this, [this] (quint32 button) { // TODO: Fix time diff --git a/main_wayland.cpp b/main_wayland.cpp --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -712,6 +712,7 @@ if (pluginName.isEmpty()) { std::cerr << "No backend specified through command line argument, trying auto resolution" << std::endl; pluginName = KWin::automaticBackendSelection(); + std::cerr << "Selected backend " << pluginName.toStdString() << std::endl; } auto pluginIt = std::find_if(availablePlugins.begin(), availablePlugins.end(), diff --git a/plugins/platforms/drm/CMakeLists.txt b/plugins/platforms/drm/CMakeLists.txt --- a/plugins/platforms/drm/CMakeLists.txt +++ b/plugins/platforms/drm/CMakeLists.txt @@ -13,7 +13,11 @@ ) if(HAVE_GBM) - set(DRM_SOURCES ${DRM_SOURCES} egl_gbm_backend.cpp drm_buffer_gbm.cpp) + set(DRM_SOURCES ${DRM_SOURCES} + egl_gbm_backend.cpp + drm_buffer_gbm.cpp + remoteaccess_manager.cpp + ) endif() add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -172,4 +172,3 @@ } #endif - diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -101,6 +101,7 @@ void DrmBackend::init() { + qCInfo(KWIN_DRM) << "Initializing DRM backend"; LogindIntegration *logind = LogindIntegration::self(); auto takeControl = [logind, this]() { if (logind->hasSessionControl()) { diff --git a/plugins/platforms/drm/drm_buffer.h b/plugins/platforms/drm/drm_buffer.h --- a/plugins/platforms/drm/drm_buffer.h +++ b/plugins/platforms/drm/drm_buffer.h @@ -61,9 +61,11 @@ bool needsModeChange(DrmBuffer *b) const override; bool map(QImage::Format format = QImage::Format_RGB32); + quint32 handle() const { return m_handle; } + QImage *image() const { return m_image; } @@ -83,4 +85,3 @@ } #endif - diff --git a/plugins/platforms/drm/drm_buffer_gbm.h b/plugins/platforms/drm/drm_buffer_gbm.h --- a/plugins/platforms/drm/drm_buffer_gbm.h +++ b/plugins/platforms/drm/drm_buffer_gbm.h @@ -48,6 +48,11 @@ bool hasBo() const { return m_bo != nullptr; } + + gbm_bo* getBo() const { + return m_bo; + } + void releaseGbm() override; private: diff --git a/plugins/platforms/drm/egl_gbm_backend.h b/plugins/platforms/drm/egl_gbm_backend.h --- a/plugins/platforms/drm/egl_gbm_backend.h +++ b/plugins/platforms/drm/egl_gbm_backend.h @@ -20,6 +20,7 @@ #ifndef KWIN_EGL_GBM_BACKEND_H #define KWIN_EGL_GBM_BACKEND_H #include "abstract_egl_backend.h" +#include "remoteaccess_manager.h" #include "scene_opengl.h" struct gbm_surface; @@ -57,6 +58,7 @@ bool initializeEgl(); bool initBufferConfigs(); bool initRenderingContext(); + void initRemotePresent(); struct Output { DrmOutput *output = nullptr; DrmBuffer *buffer = nullptr; @@ -74,6 +76,7 @@ void createOutput(DrmOutput *output); DrmBackend *m_backend; QVector m_outputs; + QScopedPointer m_remoteaccessManager; friend class EglGbmTexture; }; diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -128,6 +128,7 @@ initKWinGL(); initBufferAge(); initWayland(); + initRemotePresent(); } bool EglGbmBackend::initRenderingContext() @@ -152,6 +153,21 @@ return makeContextCurrent(m_outputs.first()); } +void EglGbmBackend::initRemotePresent() +{ + bool supportRemotePresent = false; + const QByteArray remoteOption = qgetenv("KWIN_REMOTE"); + + if (!remoteOption.isEmpty()) { + supportRemotePresent = remoteOption == QByteArrayLiteral("1"); + } + + if(supportRemotePresent) { + qCDebug(KWIN_DRM) << "Support for remote present enabled"; + m_remoteaccessManager.reset(new RemoteAccessManager); + } +} + void EglGbmBackend::createOutput(DrmOutput *drmOutput) { Output o; @@ -241,7 +257,13 @@ { eglSwapBuffers(eglDisplay(), o.eglSurface); o.buffer = m_backend->createBuffer(o.gbmSurface); + if(m_remoteaccessManager && gbm_surface_has_free_buffers(o.gbmSurface)) { + // GBM surface is released on page flip so + // we should pass the buffer before it's presented + m_remoteaccessManager->passBuffer(o.buffer); + } m_backend->present(o.buffer, o.output); + if (supportsBufferAge()) { eglQuerySurface(eglDisplay(), o.eglSurface, EGL_BUFFER_AGE_EXT, &o.bufferAge); } diff --git a/plugins/platforms/drm/remoteaccess_manager.h b/plugins/platforms/drm/remoteaccess_manager.h new file mode 100644 --- /dev/null +++ b/plugins/platforms/drm/remoteaccess_manager.h @@ -0,0 +1,60 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2016 Oleg Chernovskiy + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef REMOTEACCESSMANAGER_H +#define REMOTEACCESSMANAGER_H + +#include "drm_backend.h" +#include "../../../wayland_server.h" +// KWayland +#include +#include +// Qt +#include + +class gbm_bo; +class gbm_surface; + +namespace KWin +{ + +using KWayland::Server::RemoteAccessManagerInterface; +using KWayland::Server::BufferHandle; + +class RemoteAccessManager : public QObject +{ + Q_OBJECT +public: + explicit RemoteAccessManager(QObject *parent = nullptr); + virtual ~RemoteAccessManager(); + + void passBuffer(DrmBuffer *buffer); + +signals: + void bufferNoLongerNeeded(qint32 gbm_handle); + +private: + void releaseBuffer(const BufferHandle *buf); + + RemoteAccessManagerInterface *m_interface = nullptr; +}; + +} // KWin namespace + +#endif // REMOTEACCESSMANAGER_H diff --git a/plugins/platforms/drm/remoteaccess_manager.cpp b/plugins/platforms/drm/remoteaccess_manager.cpp new file mode 100644 --- /dev/null +++ b/plugins/platforms/drm/remoteaccess_manager.cpp @@ -0,0 +1,84 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2016 Oleg Chernovskiy + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "remoteaccess_manager.h" +#include "logging.h" + +// system +#include +#include + +namespace KWin +{ + +RemoteAccessManager::RemoteAccessManager(QObject *parent) + : QObject(parent) +{ + if (waylandServer()) { + m_interface = waylandServer()->display()->createRemoteAccessManager(this); + m_interface->create(); + + connect(m_interface, &RemoteAccessManagerInterface::bufferReleased, + this, &RemoteAccessManager::releaseBuffer); + } +} + +RemoteAccessManager::~RemoteAccessManager() +{ + if (m_interface) { + m_interface->destroy(); + } +} + +void RemoteAccessManager::releaseBuffer(const BufferHandle *buf) +{ + int ret = close(buf->fd()); + if (Q_UNLIKELY(ret)) { + qCWarning(KWIN_DRM) << "Couldn't close released GBM fd:" << strerror(errno); + } + delete buf; +} + +void RemoteAccessManager::passBuffer(DrmBuffer *buffer) +{ + DrmSurfaceBuffer* gbmbuf = static_cast(buffer); + + // no connected RemoteAccess instance + if (!m_interface || !m_interface->isBound()) { + return; + } + + // first buffer may be null + if (!gbmbuf || !gbmbuf->hasBo()) { + return; + } + + qCDebug(KWIN_DRM) << "Handing over GBM object to remote framebuffer"; + auto buf = new BufferHandle; + buf->setFd(gbm_bo_get_fd(gbmbuf->getBo())); + buf->setSize(gbm_bo_get_width(gbmbuf->getBo()), gbm_bo_get_height(gbmbuf->getBo())); + buf->setStride(gbm_bo_get_stride(gbmbuf->getBo())); + buf->setFormat(gbm_bo_get_format(gbmbuf->getBo())); + + qCDebug(KWIN_DRM) << "Buffer passed: bo" << gbmbuf->getBo() << ", fd" << buf->fd(); + + m_interface->sendBufferReady(buf); +} + +} // KWin namespace