From 054d9234112ca4faa0f563be5012c74286b9c806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Thu, 10 Aug 2017 18:13:42 +0200 Subject: [PATCH] Move SceneXRender into a plugin Summary: First step for loading the compositor Scenes through plugins. The general idea is that we currently needlessly pull in all the Scenes although only one will be used. E.g. on X11 we pull in QPainter, although they are not compatible. On Wayland we pull in XRender although they are not compatible. Furthermore our current Scene creation strategy is not really fault tolerant and can create situations where we don't get a compositor. E.g on fbdev backend the default settings won't work as it does not support OpenGL. Long term I want to tackle those conceptional problems together: we try to load all plugins supported by the current platform till we have a scene which works. Thus on Wayland we don't end up in a situation where we don't have a working compositor because the configuration is bad. To make this possible the switch statement in the Scene needs to go and needs to be replaced by a for loop iterating over all the available scenes on the platform. If we go there it makes sense to replace it directly with a plugin based approach. So this is a change which tackles the problem by first introducing the plugin loading. The xrender based scene (as it's the most simple one) is moved into a plugin. It is first tried to find a scene plugin and only if there is none the existing code is used. Test Plan: Tested all scenes Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D7232 --- CMakeLists.txt | 1 - composite.cpp | 102 +++++++++++------- data/org_kde_kwin.categories | 1 + decorations/decorationrenderer.h | 4 +- effects.h | 2 +- plugins/CMakeLists.txt | 1 + plugins/scenes/CMakeLists.txt | 3 + plugins/scenes/xrender/CMakeLists.txt | 25 +++++ .../scenes/xrender/scene_xrender.cpp | 20 +++- .../scenes/xrender/scene_xrender.h | 13 +++ plugins/scenes/xrender/xrender.json | 8 ++ scene.cpp | 9 ++ scene.h | 22 +++- shadow.h | 2 +- 14 files changed, 166 insertions(+), 47 deletions(-) create mode 100644 plugins/scenes/CMakeLists.txt create mode 100644 plugins/scenes/xrender/CMakeLists.txt rename scene_xrender.cpp => plugins/scenes/xrender/scene_xrender.cpp (99%) rename scene_xrender.h => plugins/scenes/xrender/scene_xrender.h (96%) create mode 100644 plugins/scenes/xrender/xrender.json diff --git a/CMakeLists.txt b/CMakeLists.txt index c042ff78f7..108d646693 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -409,7 +409,6 @@ set(kwin_KDEINIT_SRCS toplevel.cpp unmanaged.cpp scene.cpp - scene_xrender.cpp scene_opengl.cpp scene_qpainter.cpp screenlockerwatcher.cpp diff --git a/composite.cpp b/composite.cpp index 4bb816869e..d10913c44d 100644 --- a/composite.cpp +++ b/composite.cpp @@ -30,7 +30,6 @@ along with this program. If not, see . #include "effects.h" #include "overlaywindow.h" #include "scene.h" -#include "scene_xrender.h" #include "scene_opengl.h" #include "scene_qpainter.h" #include "screens.h" @@ -54,6 +53,8 @@ along with this program. If not, see . #include #include #include +#include +#include #include #include @@ -199,54 +200,73 @@ void Compositor::slotCompositingOptionsInitialized() } } - switch(options->compositingMode()) { - case OpenGLCompositing: { - qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; + const auto availablePlugins = KPluginLoader::findPlugins(QStringLiteral("org.kde.kwin.scenes")); - // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: - if (kwinApp()->platform()->openGLCompositingIsBroken()) - qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; - else { - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); + const auto pluginIt = std::find_if(availablePlugins.begin(), availablePlugins.end(), + [] (const auto &plugin) { + const auto &metaData = plugin.rawData(); + auto it = metaData.find(QStringLiteral("CompositingType")); + if (it != metaData.end()) { + if ((*it).toInt() == int{options->compositingMode()}) { + return true; + } + } + return false; + }); + if (pluginIt != availablePlugins.end()) { + std::unique_ptr factory{qobject_cast(pluginIt->instantiate())}; + if (factory) { + m_scene = factory->create(this); + if (m_scene) { + qCDebug(KWIN_CORE) << "Instantiated compositing plugin:" << pluginIt->name(); + } + } + } + + if (!m_scene) { + switch(options->compositingMode()) { + case OpenGLCompositing: { + qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; - m_scene = SceneOpenGL::createScene(this); + // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: + if (kwinApp()->platform()->openGLCompositingIsBroken()) + qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; + else { + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); + m_scene = SceneOpenGL::createScene(this); - if (m_scene && !m_scene->initFailed()) { - connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart); - break; // --> + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); + + if (m_scene && !m_scene->initFailed()) { + connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart); + break; // --> + } + delete m_scene; + m_scene = NULL; } - delete m_scene; - m_scene = NULL; - } - // Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on - break; - } -#ifdef KWIN_HAVE_XRENDER_COMPOSITING - case XRenderCompositing: - qCDebug(KWIN_CORE) << "Initializing XRender compositing"; - m_scene = SceneXrender::createScene(this); - break; -#endif - case QPainterCompositing: - qCDebug(KWIN_CORE) << "Initializing QPainter compositing"; - m_scene = SceneQPainter::createScene(this); - break; - default: - qCDebug(KWIN_CORE) << "No compositing enabled"; - m_starting = false; - if (cm_selection) { - cm_selection->owning = false; - cm_selection->release(); + // Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on + break; } - if (kwinApp()->platform()->requiresCompositing()) { - qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; - qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; - qApp->quit(); + case QPainterCompositing: + qCDebug(KWIN_CORE) << "Initializing QPainter compositing"; + m_scene = SceneQPainter::createScene(this); + break; + default: + qCDebug(KWIN_CORE) << "No compositing enabled"; + m_starting = false; + if (cm_selection) { + cm_selection->owning = false; + cm_selection->release(); + } + if (kwinApp()->platform()->requiresCompositing()) { + qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; + qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; + qApp->quit(); + } + return; } - return; } if (m_scene == NULL || m_scene->initFailed()) { qCCritical(KWIN_CORE) << "Failed to initialize compositing, compositing disabled"; diff --git a/data/org_kde_kwin.categories b/data/org_kde_kwin.categories index 4f5d231d20..8900680251 100644 --- a/data/org_kde_kwin.categories +++ b/data/org_kde_kwin.categories @@ -16,3 +16,4 @@ kwin_scripting KWin Scripting aurorae KWin Aurorae Window Decoration Engine kwin_xkbcommon KWin xkbcommon integration kwin_qpa_plugin KWin QtPlatformAbstraction plugin +kwin_scene_xrender KWin XRender based compositor scene plugin diff --git a/decorations/decorationrenderer.h b/decorations/decorationrenderer.h index e216e2687a..17d184bda9 100644 --- a/decorations/decorationrenderer.h +++ b/decorations/decorationrenderer.h @@ -25,6 +25,8 @@ along with this program. If not, see . #include +#include + class QTimer; namespace KWin @@ -37,7 +39,7 @@ namespace Decoration class DecoratedClientImpl; -class Renderer : public QObject +class KWIN_EXPORT Renderer : public QObject { Q_OBJECT public: diff --git a/effects.h b/effects.h index ba24902b08..b9eb3d36a7 100644 --- a/effects.h +++ b/effects.h @@ -393,7 +393,7 @@ private: Group* group; }; -class EffectFrameImpl +class KWIN_EXPORT EffectFrameImpl : public QObject, public EffectFrame { Q_OBJECT diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 3a06fa63fb..da3eed351a 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(kglobalaccel) add_subdirectory(qpa) add_subdirectory(idletime) add_subdirectory(platforms) +add_subdirectory(scenes) if(KWIN_BUILD_DECORATIONS) add_subdirectory(kdecorations) diff --git a/plugins/scenes/CMakeLists.txt b/plugins/scenes/CMakeLists.txt new file mode 100644 index 0000000000..b93ce5b957 --- /dev/null +++ b/plugins/scenes/CMakeLists.txt @@ -0,0 +1,3 @@ +if( KWIN_BUILD_XRENDER_COMPOSITING ) + add_subdirectory(xrender) +endif() diff --git a/plugins/scenes/xrender/CMakeLists.txt b/plugins/scenes/xrender/CMakeLists.txt new file mode 100644 index 0000000000..8e8c67ed37 --- /dev/null +++ b/plugins/scenes/xrender/CMakeLists.txt @@ -0,0 +1,25 @@ +set(SCENE_XRENDER_SRCS scene_xrender.cpp) + +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category( + SCENE_XRENDER_SRCS HEADER + logging.h + IDENTIFIER + KWIN_XRENDER + CATEGORY_NAME + kwin_scene_xrender + DEFAULT_SEVERITY + Critical +) + +add_library(KWinSceneXRender MODULE ${SCENE_XRENDER_SRCS}) +target_link_libraries(KWinSceneXRender + kwin +) + +install( + TARGETS + KWinSceneXRender + DESTINATION + ${PLUGIN_INSTALL_DIR}/org.kde.kwin.scenes/ +) diff --git a/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp similarity index 99% rename from scene_xrender.cpp rename to plugins/scenes/xrender/scene_xrender.cpp index 4334807874..df1702699d 100644 --- a/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -25,6 +25,7 @@ along with this program. If not, see . #ifdef KWIN_HAVE_XRENDER_COMPOSITING +#include "logging.h" #include "toplevel.h" #include "client.h" #include "composite.h" @@ -96,7 +97,7 @@ void XRenderBackend::setBuffer(xcb_render_picture_t buffer) void XRenderBackend::setFailed(const QString& reason) { - qCCritical(KWIN_CORE) << "Creating the XRender backend failed: " << reason; + qCCritical(KWIN_XRENDER) << "Creating the XRender backend failed: " << reason; m_failed = true; } @@ -1297,6 +1298,23 @@ void SceneXRenderDecorationRenderer::reparent(Deleted *deleted) #undef DOUBLE_TO_FIXED #undef FIXED_TO_DOUBLE +XRenderFactory::XRenderFactory(QObject *parent) + : SceneFactory(parent) +{ +} + +XRenderFactory::~XRenderFactory() = default; + +Scene *XRenderFactory::create(QObject *parent) const +{ + auto s = SceneXrender::createScene(parent); + if (s && s->initFailed()) { + delete s; + s = nullptr; + } + return s; +} + } // namespace #endif diff --git a/scene_xrender.h b/plugins/scenes/xrender/scene_xrender.h similarity index 96% rename from scene_xrender.h rename to plugins/scenes/xrender/scene_xrender.h index d4dacd3610..04bc66caea 100644 --- a/scene_xrender.h +++ b/plugins/scenes/xrender/scene_xrender.h @@ -341,6 +341,19 @@ private: XRenderPicture* m_pictures[int(DecorationPart::Count)]; }; +class KWIN_EXPORT XRenderFactory : public SceneFactory +{ + Q_OBJECT + Q_INTERFACES(KWin::SceneFactory) + Q_PLUGIN_METADATA(IID "org.kde.kwin.Scene" FILE "xrender.json") + +public: + explicit XRenderFactory(QObject *parent = nullptr); + ~XRenderFactory() override; + + Scene *create(QObject *parent = nullptr) const override; +}; + } // namespace #endif diff --git a/plugins/scenes/xrender/xrender.json b/plugins/scenes/xrender/xrender.json new file mode 100644 index 0000000000..d2af878b9b --- /dev/null +++ b/plugins/scenes/xrender/xrender.json @@ -0,0 +1,8 @@ +{ + "KPlugin": { + "Description": "KWin Compositor plugin rendering through XRender", + "Id": "KWinSceneXRender", + "Name": "SceneXRender" + }, + "CompositingType": 2 +} diff --git a/scene.cpp b/scene.cpp index a51bbe9be2..bf5b7778d0 100644 --- a/scene.cpp +++ b/scene.cpp @@ -1124,4 +1124,13 @@ Scene::EffectFrame::~EffectFrame() { } +SceneFactory::SceneFactory(QObject *parent) + : QObject(parent) +{ +} + +SceneFactory::~SceneFactory() +{ +} + } // namespace diff --git a/scene.h b/scene.h index e7c885ac98..5d9865ecac 100644 --- a/scene.h +++ b/scene.h @@ -245,6 +245,24 @@ private: QVector< Window* > stacking_order; }; +/** + * Factory class to create a Scene. Needs to be implemented by the plugins. + **/ +class KWIN_EXPORT SceneFactory : public QObject +{ + Q_OBJECT +public: + virtual ~SceneFactory(); + + /** + * @returns The created Scene, may be @c nullptr. + **/ + virtual Scene *create(QObject *parent = nullptr) const = 0; + +protected: + explicit SceneFactory(QObject *parent); +}; + // The base class for windows representations in composite backends class Scene::Window { @@ -359,7 +377,7 @@ private: * This class is intended to be inherited for the needs of the compositor backends which need further mapping from * the native pixmap to the respective rendering format. */ -class WindowPixmap +class KWIN_EXPORT WindowPixmap { public: virtual ~WindowPixmap(); @@ -643,4 +661,6 @@ const QSize &WindowPixmap::size() const } // namespace +Q_DECLARE_INTERFACE(KWin::SceneFactory, "org.kde.kwin.Scene") + #endif diff --git a/shadow.h b/shadow.h index d47ff88b99..b64cf7a471 100644 --- a/shadow.h +++ b/shadow.h @@ -58,7 +58,7 @@ class Toplevel; * @author Martin Gräßlin * @todo React on Toplevel size changes. **/ -class Shadow : public QObject +class KWIN_EXPORT Shadow : public QObject { Q_OBJECT public: