From kde-commits Mon Sep 11 14:40:01 2017 From: =?utf-8?q?Martin_Fl=C3=B6ser?= Date: Mon, 11 Sep 2017 14:40:01 +0000 To: kde-commits Subject: [kwin/scene-opengl-plugin] /: Move SceneOpenGL into a dedicated plugin Message-Id: X-MARC-Message: https://marc.info/?l=kde-commits&m=150514081911590 Git commit e0f7f58397a613a34312e93b53ade2c72ebc202b by Martin Fl=C3=B6ser. Committed on 08/09/2017 at 20:42. Pushed by graesslin into branch 'scene-opengl-plugin'. Move SceneOpenGL into a dedicated plugin Summary: Unfortunately a rather large change which required more refactoring than initially expected. The main problem was that some parts needed to go into platformsupport so that the platform plugins can link them. Due to the rather monolithic nature of scene_opengl.h a few changes were required: * SceneOpenGL::Texture -> SceneOpenGLTexture * SceneOpenGL::TexturePrivate -> SceneOpenGLTexturePrivate * texture based code into dedicated files * SwapProfiler code into dedicated files * SwapProfiler only used in x11 variants * Safety checks for OpenGL scene moved into the new plugin * signal declared in SceneOpenGL moved to Scene, so that we don't need to include SceneOpenGL in composite Test Plan: Nested OpenGL compositor works Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D7740 M +0 -2 CMakeLists.txt M +3 -42 composite.cpp M +1 -0 data/org_kde_kwin.categories M +2 -1 lanczosfilter.h M +2 -0 libkwineffects/kwingltexture_p.h M +1 -0 platformsupport/scenes/CMakeLists.txt A +23 -0 platformsupport/scenes/opengl/CMakeLists.txt R +16 -12 platformsupport/scenes/opengl/abstract_egl_backend.cpp [from= : abstract_egl_backend.cpp - 094% similarity] R +15 -5 platformsupport/scenes/opengl/abstract_egl_backend.h [from: = abstract_egl_backend.h - 089% similarity] A +119 -0 platformsupport/scenes/opengl/backend.cpp [License: GPL = (v2)] A +325 -0 platformsupport/scenes/opengl/backend.h [License: GPL (v= 2)] A +57 -0 platformsupport/scenes/opengl/swap_profiler.cpp [License= : GPL (v2)] A +53 -0 platformsupport/scenes/opengl/swap_profiler.h [License: = GPL (v2)] A +80 -0 platformsupport/scenes/opengl/texture.cpp [License: GPL = (v2)] A +76 -0 platformsupport/scenes/opengl/texture.h [License: GPL (v= 2)] M +3 -1 plugins/platforms/drm/CMakeLists.txt M +2 -2 plugins/platforms/drm/egl_gbm_backend.cpp M +2 -3 plugins/platforms/drm/egl_gbm_backend.h M +2 -0 plugins/platforms/hwcomposer/CMakeLists.txt M +2 -2 plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp M +2 -2 plugins/platforms/hwcomposer/egl_hwcomposer_backend.h M +2 -1 plugins/platforms/virtual/CMakeLists.txt M +3 -2 plugins/platforms/virtual/egl_gbm_backend.cpp M +2 -3 plugins/platforms/virtual/egl_gbm_backend.h M +1 -0 plugins/platforms/virtual/virtual_backend.cpp M +2 -1 plugins/platforms/wayland/CMakeLists.txt M +2 -2 plugins/platforms/wayland/egl_wayland_backend.cpp M +2 -3 plugins/platforms/wayland/egl_wayland_backend.h M +1 -0 plugins/platforms/x11/common/CMakeLists.txt M +6 -2 plugins/platforms/x11/common/eglonxbackend.cpp M +6 -3 plugins/platforms/x11/common/eglonxbackend.h M +3 -1 plugins/platforms/x11/standalone/CMakeLists.txt M +8 -4 plugins/platforms/x11/standalone/glxbackend.cpp M +9 -5 plugins/platforms/x11/standalone/glxbackend.h M +2 -1 plugins/platforms/x11/windowed/CMakeLists.txt M +2 -0 plugins/platforms/x11/windowed/x11windowed_backend.cpp M +1 -0 plugins/scenes/CMakeLists.txt A +26 -0 plugins/scenes/opengl/CMakeLists.txt A +9 -0 plugins/scenes/opengl/opengl.json R +58 -210 plugins/scenes/opengl/scene_opengl.cpp [from: scene_opengl.c= pp - 092% similarity] A +357 -0 plugins/scenes/opengl/scene_opengl.h [License: GPL (v2)] M +1 -0 scene.h D +0 -697 scene_opengl.h https://commits.kde.org/kwin/e0f7f58397a613a34312e93b53ade2c72ebc202b diff --git a/CMakeLists.txt b/CMakeLists.txt index 055a87a07..fa4ef71d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -410,7 +410,6 @@ set(kwin_KDEINIT_SRCS toplevel.cpp unmanaged.cpp scene.cpp - scene_opengl.cpp screenlockerwatcher.cpp thumbnailitem.cpp lanczosfilter.cpp @@ -440,7 +439,6 @@ set(kwin_KDEINIT_SRCS decorations/settings.cpp decorations/decorationrenderer.cpp decorations/decorations_logging.cpp - abstract_egl_backend.cpp platform.cpp shell_client.cpp wayland_server.cpp diff --git a/composite.cpp b/composite.cpp index 767f0850d..c238a489d 100644 --- a/composite.cpp +++ b/composite.cpp @@ -29,7 +29,6 @@ along with this program. If not, see . #include "effects.h" #include "overlaywindow.h" #include "scene.h" -#include "scene_opengl.h" #include "screens.h" #include "shadow.h" #include "useractions.h" @@ -39,6 +38,8 @@ along with this program. If not, see . #include "wayland_server.h" #include "decorations/decoratedclient.h" = +#include + #include = #include @@ -220,47 +221,6 @@ void Compositor::slotCompositingOptionsInitialized() } } = - if (!m_scene) { - switch(options->compositingMode()) { - case OpenGLCompositing: { - qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; - - // Some broken drivers crash on glXQuery() so to prevent const= ant KWin crashes: - if (kwinApp()->platform()->openGLCompositingIsBroken()) - qCWarning(KWIN_CORE) << "KWin has detected that your OpenG= L library is unsafe to use"; - else { - kwinApp()->platform()->createOpenGLSafePoint(Platform::Ope= nGLSafePoint::PreInit); - - m_scene =3D SceneOpenGL::createScene(this); - - kwinApp()->platform()->createOpenGLSafePoint(Platform::Ope= nGLSafePoint::PostInit); - - if (m_scene && !m_scene->initFailed()) { - connect(static_cast(m_scene), &SceneOpen= GL::resetCompositing, this, &Compositor::restart); - break; // --> - } - delete m_scene; - m_scene =3D NULL; - } - - // Do not Fall back to XRender - it causes problems when selfc= heck fails during startup, but works later on - break; - } - default: - qCDebug(KWIN_CORE) << "No compositing enabled"; - m_starting =3D false; - if (cm_selection) { - cm_selection->owning =3D false; - cm_selection->release(); - } - if (kwinApp()->platform()->requiresCompositing()) { - qCCritical(KWIN_CORE) << "The used windowing system requir= es compositing"; - qCCritical(KWIN_CORE) << "We are going to quit KWin now as= it is broken"; - qApp->quit(); - } - return; - } - } if (m_scene =3D=3D NULL || m_scene->initFailed()) { qCCritical(KWIN_CORE) << "Failed to initialize compositing, compos= iting disabled"; delete m_scene; @@ -277,6 +237,7 @@ void Compositor::slotCompositingOptionsInitialized() } return; } + connect(m_scene, &Scene::resetCompositing, this, &Compositor::restart); emit sceneCreated(); = if (Workspace::self()) { diff --git a/data/org_kde_kwin.categories b/data/org_kde_kwin.categories index e73674fc1..a256fa2c5 100644 --- a/data/org_kde_kwin.categories +++ b/data/org_kde_kwin.categories @@ -18,3 +18,4 @@ kwin_xkbcommon KWin xkbcommon integration kwin_qpa_plugin KWin QtPlatformAbstraction plugin kwin_scene_xrender KWin XRender based compositor scene plugin kwin_scene_qpainter KWin QPainter based compositor scene plugin +kwin_scene_opengl KWin OpenGL based compositor scene plugins diff --git a/lanczosfilter.h b/lanczosfilter.h index fff5cf28e..90dff420c 100644 --- a/lanczosfilter.h +++ b/lanczosfilter.h @@ -29,6 +29,7 @@ along with this program. If not, see . #include = #include +#include = namespace KWin { @@ -40,7 +41,7 @@ class GLTexture; class GLRenderTarget; class GLShader; = -class LanczosFilter +class KWIN_EXPORT LanczosFilter : public QObject { Q_OBJECT diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltextur= e_p.h index 440d2ce94..cec4c6c1f 100644 --- a/libkwineffects/kwingltexture_p.h +++ b/libkwineffects/kwingltexture_p.h @@ -29,6 +29,8 @@ along with this program. If not, see . #include #include #include +#include +#include = namespace KWin { diff --git a/platformsupport/scenes/CMakeLists.txt b/platformsupport/scenes= /CMakeLists.txt index 2e1df3548..6e560cbcd 100644 --- a/platformsupport/scenes/CMakeLists.txt +++ b/platformsupport/scenes/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(qpainter) +add_subdirectory(opengl) diff --git a/platformsupport/scenes/opengl/CMakeLists.txt b/platformsupport= /scenes/opengl/CMakeLists.txt new file mode 100644 index 000000000..26123568d --- /dev/null +++ b/platformsupport/scenes/opengl/CMakeLists.txt @@ -0,0 +1,23 @@ +set(SCENE_OPENGL_BACKEND_SRCS + abstract_egl_backend.cpp + backend.cpp + swap_profiler.cpp + texture.cpp +) + +include_directories(${CMAKE_SOURCE_DIR}) + +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category(SCENE_OPENGL_BACKEND_SRCS + HEADER + logging.h + IDENTIFIER + KWIN_OPENGL + CATEGORY_NAME + kwin_scene_opengl + DEFAULT_SEVERITY + Critical +) + +add_library(SceneOpenGLBackend STATIC ${SCENE_OPENGL_BACKEND_SRCS}) +target_link_libraries(SceneOpenGLBackend Qt5::Core Qt5::Widgets KF5::CoreA= ddons KF5::ConfigCore KF5::WindowSystem) diff --git a/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstr= act_egl_backend.cpp similarity index 94% rename from abstract_egl_backend.cpp rename to platformsupport/scenes/opengl/abstract_egl_backend.cpp index 209d37261..91729b480 100644 --- a/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -18,16 +18,20 @@ You should have received a copy of the GNU General Publ= ic License along with this program. If not, see . *********************************************************************/ #include "abstract_egl_backend.h" +#include "texture.h" #include "composite.h" #include "egl_context_attribute_builder.h" #include "options.h" #include "platform.h" +#include "scene.h" #include "wayland_server.h" #include #include #include // kwin libs +#include #include +#include // Qt #include #include @@ -93,25 +97,25 @@ bool AbstractEglBackend::initEglAPI() { EGLint major, minor; if (eglInitialize(m_display, &major, &minor) =3D=3D EGL_FALSE) { - qCWarning(KWIN_CORE) << "eglInitialize failed"; + qCWarning(KWIN_OPENGL) << "eglInitialize failed"; EGLint error =3D eglGetError(); if (error !=3D EGL_SUCCESS) { - qCWarning(KWIN_CORE) << "Error during eglInitialize " << error; + qCWarning(KWIN_OPENGL) << "Error during eglInitialize " << err= or; } return false; } EGLint error =3D eglGetError(); if (error !=3D EGL_SUCCESS) { - qCWarning(KWIN_CORE) << "Error during eglInitialize " << error; + qCWarning(KWIN_OPENGL) << "Error during eglInitialize " << error; return false; } - qCDebug(KWIN_CORE) << "Egl Initialize succeeded"; + qCDebug(KWIN_OPENGL) << "Egl Initialize succeeded"; = if (eglBindAPI(isOpenGLES() ? EGL_OPENGL_ES_API : EGL_OPENGL_API) =3D= =3D EGL_FALSE) { - qCCritical(KWIN_CORE) << "bind OpenGL API failed"; + qCCritical(KWIN_OPENGL) << "bind OpenGL API failed"; return false; } - qCDebug(KWIN_CORE) << "EGL version: " << major << "." << minor; + qCDebug(KWIN_OPENGL) << "EGL version: " << major << "." << minor; const QByteArray eglExtensions =3D eglQueryString(m_display, EGL_EXTEN= SIONS); setExtensions(eglExtensions.split(' ')); return true; @@ -250,13 +254,13 @@ bool AbstractEglBackend::createContext() const auto attribs =3D (*it)->build(); ctx =3D eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attr= ibs.data()); if (ctx !=3D EGL_NO_CONTEXT) { - qCDebug(KWIN_CORE) << "Created EGL context with attributes:" <= < (*it).get(); + qCDebug(KWIN_OPENGL) << "Created EGL context with attributes:"= << (*it).get(); break; } } = if (ctx =3D=3D EGL_NO_CONTEXT) { - qCCritical(KWIN_CORE) << "Create Context failed"; + qCCritical(KWIN_OPENGL) << "Create Context failed"; return false; } m_context =3D ctx; @@ -281,8 +285,8 @@ void AbstractEglBackend::setSurface(const EGLSurface &s= urface) kwinApp()->platform()->setSceneEglSurface(surface); } = -AbstractEglTexture::AbstractEglTexture(SceneOpenGL::Texture *texture, Abst= ractEglBackend *backend) - : SceneOpenGL::TexturePrivate() +AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, Abstra= ctEglBackend *backend) + : SceneOpenGLTexturePrivate() , q(texture) , m_backend(backend) , m_image(EGL_NO_IMAGE_KHR) @@ -453,7 +457,7 @@ bool AbstractEglTexture::loadEglTexture(const QPointer<= KWayland::Server::Buffer q->unbind(); = if (EGL_NO_IMAGE_KHR =3D=3D m_image) { - qCDebug(KWIN_CORE) << "failed to create egl image"; + qCDebug(KWIN_OPENGL) << "failed to create egl image"; q->discard(); return false; } @@ -466,7 +470,7 @@ EGLImageKHR AbstractEglTexture::attach(const QPointer< = KWayland::Server::BufferI EGLint format, yInverted; eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), E= GL_TEXTURE_FORMAT, &format); if (format !=3D EGL_TEXTURE_RGB && format !=3D EGL_TEXTURE_RGBA) { - qCDebug(KWIN_CORE) << "Unsupported texture format: " << format; + qCDebug(KWIN_OPENGL) << "Unsupported texture format: " << format; return EGL_NO_IMAGE_KHR; } if (!eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource= (), EGL_WAYLAND_Y_INVERTED_WL, &yInverted)) { diff --git a/abstract_egl_backend.h b/platformsupport/scenes/opengl/abstrac= t_egl_backend.h similarity index 89% rename from abstract_egl_backend.h rename to platformsupport/scenes/opengl/abstract_egl_backend.h index 35b4f3bb9..50d1a8282 100644 --- a/abstract_egl_backend.h +++ b/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -19,13 +19,23 @@ along with this program. If not, see . *********************************************************************/ #ifndef KWIN_ABSTRACT_EGL_BACKEND_H #define KWIN_ABSTRACT_EGL_BACKEND_H -#include "scene_opengl.h" +#include "backend.h" +#include "texture.h" = +#include #include #include = class QOpenGLFramebufferObject; = +namespace KWayland +{ +namespace Server +{ +class BufferInterface; +} +} + namespace KWin { = @@ -77,7 +87,7 @@ private: QList m_clientExtensions; }; = -class KWIN_EXPORT AbstractEglTexture : public SceneOpenGL::TexturePrivate +class KWIN_EXPORT AbstractEglTexture : public SceneOpenGLTexturePrivate { public: virtual ~AbstractEglTexture(); @@ -86,14 +96,14 @@ public: OpenGLBackend *backend() override; = protected: - AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *= backend); + AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *ba= ckend); EGLImageKHR image() const { return m_image; } void setImage(const EGLImageKHR &img) { m_image =3D img; } - SceneOpenGL::Texture *texture() const { + SceneOpenGLTexture *texture() const { return q; } = @@ -102,7 +112,7 @@ private: bool loadEglTexture(const QPointer = &buffer); EGLImageKHR attach(const QPointer &= buffer); bool updateFromFBO(const QSharedPointer &fbo= ); - SceneOpenGL::Texture *q; + SceneOpenGLTexture *q; AbstractEglBackend *m_backend; EGLImageKHR m_image; }; diff --git a/platformsupport/scenes/opengl/backend.cpp b/platformsupport/sc= enes/opengl/backend.cpp new file mode 100644 index 000000000..cb0a23d53 --- /dev/null +++ b/platformsupport/scenes/opengl/backend.cpp @@ -0,0 +1,119 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 "backend.h" +#include +#include + +#include "screens.h" + +#include + +namespace KWin +{ + +OpenGLBackend::OpenGLBackend() + : m_syncsToVBlank(false) + , m_blocksForRetrace(false) + , m_directRendering(false) + , m_haveBufferAge(false) + , m_failed(false) +{ +} + +OpenGLBackend::~OpenGLBackend() +{ +} + +void OpenGLBackend::setFailed(const QString &reason) +{ + qCWarning(KWIN_OPENGL) << "Creating the OpenGL rendering failed: " << = reason; + m_failed =3D true; +} + +void OpenGLBackend::idle() +{ + if (hasPendingFlush()) { + effects->makeOpenGLContextCurrent(); + present(); + } +} + +void OpenGLBackend::addToDamageHistory(const QRegion ®ion) +{ + if (m_damageHistory.count() > 10) + m_damageHistory.removeLast(); + + m_damageHistory.prepend(region); +} + +QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const +{ + QRegion region; + + // Note: An age of zero means the buffer contents are undefined + if (bufferAge > 0 && bufferAge <=3D m_damageHistory.count()) { + for (int i =3D 0; i < bufferAge - 1; i++) + region |=3D m_damageHistory[i]; + } else { + const QSize &s =3D screens()->size(); + region =3D QRegion(0, 0, s.width(), s.height()); + } + + return region; +} + +OverlayWindow* OpenGLBackend::overlayWindow() +{ + return NULL; +} + +QRegion OpenGLBackend::prepareRenderingForScreen(int screenId) +{ + // fallback to repaint complete screen + return screens()->geometry(screenId); +} + +void OpenGLBackend::endRenderingFrameForScreen(int screenId, const QRegion= &damage, const QRegion &damagedRegion) +{ + Q_UNUSED(screenId) + Q_UNUSED(damage) + Q_UNUSED(damagedRegion) +} + +bool OpenGLBackend::perScreenRendering() const +{ + return false; +} + +void OpenGLBackend::copyPixels(const QRegion ®ion) +{ + const int height =3D screens()->size().height(); + foreach (const QRect &r, region.rects()) { + const int x0 =3D r.x(); + const int y0 =3D height - r.y() - r.height(); + const int x1 =3D r.x() + r.width(); + const int y1 =3D height - r.y(); + + glBlitFramebuffer(x0, y0, x1, y1, x0, y0, x1, y1, GL_COLOR_BUFFER_= BIT, GL_NEAREST); + } +} + +} diff --git a/platformsupport/scenes/opengl/backend.h b/platformsupport/scen= es/opengl/backend.h new file mode 100644 index 000000000..483c71186 --- /dev/null +++ b/platformsupport/scenes/opengl/backend.h @@ -0,0 +1,325 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 KWIN_SCENE_OPENGL_BACKEND_H +#define KWIN_SCENE_OPENGL_BACKEND_H + +#include +#include + +#include + +namespace KWin +{ +class OpenGLBackend; +class OverlayWindow; +class SceneOpenGL; +class SceneOpenGLTexture; +class SceneOpenGLTexturePrivate; +class WindowPixmap; + +/** + * @brief The OpenGLBackend creates and holds the OpenGL context and is re= sponsible for Texture from Pixmap. + * + * The OpenGLBackend is an abstract base class used by the SceneOpenGL to = abstract away the differences + * between various OpenGL windowing systems such as GLX and EGL. + * + * A concrete implementation has to create and release the OpenGL context = in a way so that the + * SceneOpenGL does not have to care about it. + * + * In addition a major task for this class is to generate the SceneOpenGLT= exturePrivate which is + * able to perform the texture from pixmap operation in the given backend. + * + * @author Martin Gr=C3=A4=C3=9Flin + **/ +class KWIN_EXPORT OpenGLBackend +{ +public: + OpenGLBackend(); + virtual ~OpenGLBackend(); + + virtual void init() =3D 0; + /** + * @return Time passes since start of rendering current frame. + * @see startRenderTimer + **/ + qint64 renderTime() { + return m_renderTimer.nsecsElapsed(); + } + virtual void screenGeometryChanged(const QSize &size) =3D 0; + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTex= ture *texture) =3D 0; + + /** + * @brief Backend specific code to prepare the rendering of a frame in= cluding flushing the + * previously rendered frame to the screen if the backend works this w= ay. + * + * @return A region that if not empty will be repainted in addition to= the damaged region + **/ + virtual QRegion prepareRenderingFrame() =3D 0; + + /** + * @brief Backend specific code to handle the end of rendering a frame. + * + * @param renderedRegion The possibly larger region that has been rend= ered + * @param damagedRegion The damaged region that should be posted + **/ + virtual void endRenderingFrame(const QRegion &damage, const QRegion &d= amagedRegion) =3D 0; + virtual void endRenderingFrameForScreen(int screenId, const QRegion &d= amage, const QRegion &damagedRegion); + virtual bool makeCurrent() =3D 0; + virtual void doneCurrent() =3D 0; + virtual bool usesOverlayWindow() const =3D 0; + /** + * Whether the rendering needs to be split per screen. + * Default implementation returns @c false. + **/ + virtual bool perScreenRendering() const; + virtual QRegion prepareRenderingForScreen(int screenId); + /** + * @brief Compositor is going into idle mode, flushes any pending pain= ts. + **/ + void idle(); + + /** + * @return bool Whether the scene needs to flush a frame. + **/ + bool hasPendingFlush() const { + return !m_lastDamage.isEmpty(); + } + + /** + * @brief Returns the OverlayWindow used by the backend. + * + * A backend does not have to use an OverlayWindow, this is mostly for= the X world. + * In case the backend does not use an OverlayWindow it is allowed to = return @c null. + * It's the task of the caller to check whether it is @c null. + * + * @return :OverlayWindow* + **/ + virtual OverlayWindow *overlayWindow(); + /** + * @brief Whether the creation of the Backend failed. + * + * The SceneOpenGL should test whether the Backend got constructed cor= rectly. If this method + * returns @c true, the SceneOpenGL should not try to start the render= ing. + * + * @return bool @c true if the creation of the Backend failed, @c fals= e otherwise. + **/ + bool isFailed() const { + return m_failed; + } + /** + * @brief Whether the Backend provides VSync. + * + * Currently only the GLX backend can provide VSync. + * + * @return bool @c true if VSync support is available, @c false otherw= ise + **/ + bool syncsToVBlank() const { + return m_syncsToVBlank; + } + /** + * @brief Whether VSync blocks execution until the screen is in the re= trace + * + * Case for waitVideoSync and non triple buffering buffer swaps + * + **/ + bool blocksForRetrace() const { + return m_blocksForRetrace; + } + /** + * @brief Whether the backend uses direct rendering. + * + * Some OpenGLScene modes require direct rendering. E.g. the OpenGL 2 = should not be used + * if direct rendering is not supported by the Scene. + * + * @return bool @c true if the GL context is direct, @c false if indir= ect + **/ + bool isDirectRendering() const { + return m_directRendering; + } + + bool supportsBufferAge() const { + return m_haveBufferAge; + } + + /** + * @returns whether the context is surfaceless + **/ + bool isSurfaceLessContext() const { + return m_surfaceLessContext; + } + + /** + * Returns the damage that has accumulated since a buffer of the given= age was presented. + */ + QRegion accumulatedDamageHistory(int bufferAge) const; + + /** + * Saves the given region to damage history. + */ + void addToDamageHistory(const QRegion ®ion); + + /** + * The backend specific extensions (e.g. EGL/GLX extensions). + * + * Not the OpenGL (ES) extension! + **/ + QList extensions() const { + return m_extensions; + } + + /** + * @returns whether the backend specific extensions contains @p extens= ion. + **/ + bool hasExtension(const QByteArray &extension) const { + return m_extensions.contains(extension); + } + + /** + * Copy a region of pixels from the current read to the current draw b= uffer + */ + void copyPixels(const QRegion ®ion); + +protected: + /** + * @brief Backend specific flushing of frame to screen. + **/ + virtual void present() =3D 0; + /** + * @brief Sets the backend initialization to failed. + * + * This method should be called by the concrete subclass in case the i= nitialization failed. + * The given @p reason is logged as a warning. + * + * @param reason The reason why the initialization failed. + **/ + void setFailed(const QString &reason); + /** + * @brief Sets whether the backend provides VSync. + * + * Should be called by the concrete subclass once it is determined whe= ther VSync is supported. + * If the subclass does not call this method, the backend defaults to = @c false. + * @param enabled @c true if VSync support available, @c false otherwi= se. + **/ + void setSyncsToVBlank(bool enabled) { + m_syncsToVBlank =3D enabled; + } + /** + * @brief Sets whether the VSync iplementation blocks + * + * Should be called by the concrete subclass once it is determined how= VSync works. + * If the subclass does not call this method, the backend defaults to = @c false. + * @param enabled @c true if VSync blocks, @c false otherwise. + **/ + void setBlocksForRetrace(bool enabled) { + m_blocksForRetrace =3D enabled; + } + /** + * @brief Sets whether the OpenGL context is direct. + * + * Should be called by the concrete subclass once it is determined whe= ther the OpenGL context is + * direct or indirect. + * If the subclass does not call this method, the backend defaults to = @c false. + * + * @param direct @c true if the OpenGL context is direct, @c false if = indirect + **/ + void setIsDirectRendering(bool direct) { + m_directRendering =3D direct; + } + + void setSupportsBufferAge(bool value) { + m_haveBufferAge =3D value; + } + + /** + * @return const QRegion& Damage of previously rendered frame + **/ + const QRegion &lastDamage() const { + return m_lastDamage; + } + void setLastDamage(const QRegion &damage) { + m_lastDamage =3D damage; + } + /** + * @brief Starts the timer for how long it takes to render the frame. + * + * @see renderTime + **/ + void startRenderTimer() { + m_renderTimer.start(); + } + + /** + * @param set whether the context is surface less + **/ + void setSurfaceLessContext(bool set) { + m_surfaceLessContext =3D set; + } + + /** + * Sets the platform-specific @p extensions. + * + * These are the EGL/GLX extensions, not the OpenGL extensions + **/ + void setExtensions(const QList &extensions) { + m_extensions =3D extensions; + } + +private: + /** + * @brief Whether VSync is available and used, defaults to @c false. + **/ + bool m_syncsToVBlank; + /** + * @brief Whether present() will block execution until the next vertic= al retrace @c false. + **/ + bool m_blocksForRetrace; + /** + * @brief Whether direct rendering is used, defaults to @c false. + **/ + bool m_directRendering; + /** + * @brief Whether the backend supports GLX_EXT_buffer_age / EGL_EXT_bu= ffer_age. + */ + bool m_haveBufferAge; + /** + * @brief Whether the initialization failed, of course default to @c f= alse. + **/ + bool m_failed; + /** + * @brief Damaged region of previously rendered frame. + **/ + QRegion m_lastDamage; + /** + * @brief The damage history for the past 10 frames. + */ + QList m_damageHistory; + /** + * @brief Timer to measure how long a frame renders. + **/ + QElapsedTimer m_renderTimer; + bool m_surfaceLessContext =3D false; + + QList m_extensions; +}; + +} + +#endif diff --git a/platformsupport/scenes/opengl/swap_profiler.cpp b/platformsupp= ort/scenes/opengl/swap_profiler.cpp new file mode 100644 index 000000000..619a2ae65 --- /dev/null +++ b/platformsupport/scenes/opengl/swap_profiler.cpp @@ -0,0 +1,57 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 "swap_profiler.h" +#include + +namespace KWin +{ + +SwapProfiler::SwapProfiler() +{ + init(); +} + +void SwapProfiler::init() +{ + m_time =3D 2 * 1000*1000; // we start with a long time mean of 2ms ... + m_counter =3D 0; +} + +void SwapProfiler::begin() +{ + m_timer.start(); +} + +char SwapProfiler::end() +{ + // .. and blend in actual values. + // this way we prevent extremes from killing our long time mean + m_time =3D (10*m_time + m_timer.nsecsElapsed())/11; + if (++m_counter > 500) { + const bool blocks =3D m_time > 1000 * 1000; // 1ms, i get ~250=C2= =B5s and ~7ms w/o triple buffering... + qCDebug(KWIN_OPENGL) << "Triple buffering detection:" << QString(b= locks ? QStringLiteral("NOT available") : QStringLiteral("Available")) << + " - Mean block time:" << m_time/(1000.0*1000.0) <<= "ms"; + return blocks ? 'd' : 't'; + } + return 0; +} + +} diff --git a/platformsupport/scenes/opengl/swap_profiler.h b/platformsuppor= t/scenes/opengl/swap_profiler.h new file mode 100644 index 000000000..8415b0a8d --- /dev/null +++ b/platformsupport/scenes/opengl/swap_profiler.h @@ -0,0 +1,53 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 KWIN_SCENE_OPENGL_SWAP_PROFILER_H +#define KWIN_SCENE_OPENGL_SWAP_PROFILER_H + +#include +#include + +namespace KWin +{ + +/** + * @short Profiler to detect whether we have triple buffering + * The strategy is to start setBlocksForRetrace(false) but assume blocking= and have the system prove that assumption wrong + **/ +class KWIN_EXPORT SwapProfiler +{ +public: + SwapProfiler(); + void init(); + void begin(); + /** + * @return char being 'd' for double, 't' for triple (or more - but no= n-blocking) buffering and + * 0 (NOT '0') otherwise, so you can act on "if (char result =3D SwapP= rofiler::end()) { fooBar(); } + **/ + char end(); +private: + QElapsedTimer m_timer; + qint64 m_time; + int m_counter; +}; + +} + +#endif diff --git a/platformsupport/scenes/opengl/texture.cpp b/platformsupport/sc= enes/opengl/texture.cpp new file mode 100644 index 000000000..936272002 --- /dev/null +++ b/platformsupport/scenes/opengl/texture.cpp @@ -0,0 +1,80 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 "texture.h" +#include "backend.h" +#include "scene.h" + +namespace KWin +{ + +SceneOpenGLTexture::SceneOpenGLTexture(OpenGLBackend *backend) + : GLTexture(*backend->createBackendTexture(this)) +{ +} + +SceneOpenGLTexture::~SceneOpenGLTexture() +{ +} + +SceneOpenGLTexture& SceneOpenGLTexture::operator =3D (const SceneOpenGLTex= ture& tex) +{ + d_ptr =3D tex.d_ptr; + return *this; +} + +void SceneOpenGLTexture::discard() +{ + d_ptr =3D d_func()->backend()->createBackendTexture(this); +} + +bool SceneOpenGLTexture::load(WindowPixmap *pixmap) +{ + if (!pixmap->isValid()) { + return false; + } + + // decrease the reference counter for the old texture + d_ptr =3D d_func()->backend()->createBackendTexture(this); //new Textu= rePrivate(); + + Q_D(SceneOpenGLTexture); + return d->loadTexture(pixmap); +} + +void SceneOpenGLTexture::updateFromPixmap(WindowPixmap *pixmap) +{ + Q_D(SceneOpenGLTexture); + d->updateTexture(pixmap); +} + +SceneOpenGLTexturePrivate::SceneOpenGLTexturePrivate() +{ +} + +SceneOpenGLTexturePrivate::~SceneOpenGLTexturePrivate() +{ +} + +void SceneOpenGLTexturePrivate::updateTexture(WindowPixmap *pixmap) +{ + Q_UNUSED(pixmap) +} + +} diff --git a/platformsupport/scenes/opengl/texture.h b/platformsupport/scen= es/opengl/texture.h new file mode 100644 index 000000000..d574b0cb5 --- /dev/null +++ b/platformsupport/scenes/opengl/texture.h @@ -0,0 +1,76 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 KWIN_SCENE_OPENGL_TEXTURE_H +#define KWIN_SCENE_OPENGL_TEXTURE_H + +#include +#include + +namespace KWin +{ + +class OpenGLBackend; +class WindowPixmap; +class SceneOpenGLTexturePrivate; + +class SceneOpenGLTexture + : public GLTexture +{ +public: + SceneOpenGLTexture(OpenGLBackend *backend); + virtual ~SceneOpenGLTexture(); + + SceneOpenGLTexture & operator =3D (const SceneOpenGLTexture& tex); + + void discard() override final; + +protected: + bool load(WindowPixmap *pixmap); + void updateFromPixmap(WindowPixmap *pixmap); + + SceneOpenGLTexture(SceneOpenGLTexturePrivate& dd); + +private: + Q_DECLARE_PRIVATE(SceneOpenGLTexture) + + friend class OpenGLWindowPixmap; +}; + +class SceneOpenGLTexturePrivate + : public GLTexturePrivate +{ +public: + virtual ~SceneOpenGLTexturePrivate(); + + virtual bool loadTexture(WindowPixmap *pixmap) =3D 0; + virtual void updateTexture(WindowPixmap *pixmap); + virtual OpenGLBackend *backend() =3D 0; + +protected: + SceneOpenGLTexturePrivate(); + +private: + Q_DISABLE_COPY(SceneOpenGLTexturePrivate) +}; + +} + +#endif diff --git a/plugins/platforms/drm/CMakeLists.txt b/plugins/platforms/drm/C= MakeLists.txt index 8db5207a7..f3b7e7c3f 100644 --- a/plugins/platforms/drm/CMakeLists.txt +++ b/plugins/platforms/drm/CMakeLists.txt @@ -16,8 +16,10 @@ if(HAVE_GBM) set(DRM_SOURCES ${DRM_SOURCES} egl_gbm_backend.cpp drm_buffer_gbm.cpp) endif() = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) + add_library(KWinWaylandDrmBackend MODULE ${DRM_SOURCES}) -target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm SceneQPain= terBackend) +target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm SceneQPain= terBackend SceneOpenGLBackend) = if(HAVE_GBM) target_link_libraries(KWinWaylandDrmBackend gbm::gbm) diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/= drm/egl_gbm_backend.cpp index 646e77566..685bf065d 100644 --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -253,7 +253,7 @@ void EglGbmBackend::screenGeometryChanged(const QSize &= size) // TODO, create new buffer? } = -SceneOpenGL::TexturePrivate *EglGbmBackend::createBackendTexture(SceneOpen= GL::Texture *texture) +SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGL= Texture *texture) { return new EglGbmTexture(texture, this); } @@ -343,7 +343,7 @@ bool EglGbmBackend::perScreenRendering() const * EglTexture ************************************************/ = -EglGbmTexture::EglGbmTexture(KWin::SceneOpenGL::Texture *texture, EglGbmBa= ckend *backend) +EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBack= end *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/drm/egl_gbm_backend.h b/plugins/platforms/dr= m/egl_gbm_backend.h index 30e17e682..490ee14f0 100644 --- a/plugins/platforms/drm/egl_gbm_backend.h +++ b/plugins/platforms/drm/egl_gbm_backend.h @@ -20,7 +20,6 @@ along with this program. If not, see . #ifndef KWIN_EGL_GBM_BACKEND_H #define KWIN_EGL_GBM_BACKEND_H #include "abstract_egl_backend.h" -#include "scene_opengl.h" = struct gbm_surface; = @@ -40,7 +39,7 @@ public: EglGbmBackend(DrmBackend *b); virtual ~EglGbmBackend(); void screenGeometryChanged(const QSize &size) override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture= *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *te= xture) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &d= amagedRegion) override; void endRenderingFrameForScreen(int screenId, const QRegion &damage, c= onst QRegion &damagedRegion) override; @@ -87,7 +86,7 @@ public: = private: friend class EglGbmBackend; - EglGbmTexture(SceneOpenGL::Texture *texture, EglGbmBackend *backend); + EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend); }; = } // namespace diff --git a/plugins/platforms/hwcomposer/CMakeLists.txt b/plugins/platform= s/hwcomposer/CMakeLists.txt index 9b2405587..85d7c04ba 100644 --- a/plugins/platforms/hwcomposer/CMakeLists.txt +++ b/plugins/platforms/hwcomposer/CMakeLists.txt @@ -5,12 +5,14 @@ set(HWCOMPOSER_SOURCES screens_hwcomposer.cpp ) = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) add_library(KWinWaylandHwcomposerBackend MODULE ${HWCOMPOSER_SOURCES}) target_link_libraries(KWinWaylandHwcomposerBackend kwin libhybris::libhardware libhybris::hwcomposer libhybris::hybriseglplatform + SceneOpenGLBackend ) = install( diff --git a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp b/plug= ins/platforms/hwcomposer/egl_hwcomposer_backend.cpp index 7b649bf8e..3c96db118 100644 --- a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp +++ b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp @@ -164,7 +164,7 @@ void EglHwcomposerBackend::endRenderingFrame(const QReg= ion &renderedRegion, cons setLastDamage(renderedRegion); } = -SceneOpenGL::TexturePrivate *EglHwcomposerBackend::createBackendTexture(Sc= eneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglHwcomposerBackend::createBackendTexture(Scen= eOpenGLTexture *texture) { return new EglHwcomposerTexture(texture, this); } @@ -174,7 +174,7 @@ bool EglHwcomposerBackend::usesOverlayWindow() const return false; } = -EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGL::Texture *texture, = EglHwcomposerBackend *backend) +EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGLTexture *texture, Eg= lHwcomposerBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h b/plugin= s/platforms/hwcomposer/egl_hwcomposer_backend.h index 1fbbaabfa..3270104d6 100644 --- a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h +++ b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h @@ -33,7 +33,7 @@ public: EglHwcomposerBackend(HwcomposerBackend *backend); virtual ~EglHwcomposerBackend(); bool usesOverlayWindow() const override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture= *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *te= xture) override; void screenGeometryChanged(const QSize &size) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &d= amagedRegion) override; @@ -58,7 +58,7 @@ public: = private: friend class EglHwcomposerBackend; - EglHwcomposerTexture(SceneOpenGL::Texture *texture, EglHwcomposerBacke= nd *backend); + EglHwcomposerTexture(SceneOpenGLTexture *texture, EglHwcomposerBackend= *backend); }; = } diff --git a/plugins/platforms/virtual/CMakeLists.txt b/plugins/platforms/v= irtual/CMakeLists.txt index 24923620b..665463376 100644 --- a/plugins/platforms/virtual/CMakeLists.txt +++ b/plugins/platforms/virtual/CMakeLists.txt @@ -5,6 +5,7 @@ set(VIRTUAL_SOURCES screens_virtual.cpp ) = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) include(ECMQtDeclareLoggingCategory) ecm_qt_declare_logging_category(VIRTUAL_SOURCES HEADER logging.h IDENTIFIE= R KWIN_VIRTUAL CATEGORY_NAME kwin_platform_virtual DEFAULT_SEVERITY Critica= l) = @@ -12,7 +13,7 @@ add_library(KWinWaylandVirtualBackend MODULE ${VIRTUAL_SO= URCES}) target_link_libraries(KWinWaylandVirtualBackend kwin SceneQPainterBackend) = if(HAVE_GBM) - target_link_libraries(KWinWaylandVirtualBackend gbm::gbm) + target_link_libraries(KWinWaylandVirtualBackend SceneOpenGLBackend gbm= ::gbm) endif() = install( diff --git a/plugins/platforms/virtual/egl_gbm_backend.cpp b/plugins/platfo= rms/virtual/egl_gbm_backend.cpp index f009003ce..d7a4a4e02 100644 --- a/plugins/platforms/virtual/egl_gbm_backend.cpp +++ b/plugins/platforms/virtual/egl_gbm_backend.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . #include // kwin libs #include +#include // Qt #include // system @@ -214,7 +215,7 @@ void EglGbmBackend::screenGeometryChanged(const QSize &= size) // TODO, create new buffer? } = -SceneOpenGL::TexturePrivate *EglGbmBackend::createBackendTexture(SceneOpen= GL::Texture *texture) +SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGL= Texture *texture) { return new EglGbmTexture(texture, this); } @@ -282,7 +283,7 @@ bool EglGbmBackend::usesOverlayWindow() const * EglTexture ************************************************/ = -EglGbmTexture::EglGbmTexture(KWin::SceneOpenGL::Texture *texture, EglGbmBa= ckend *backend) +EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBack= end *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/virtual/egl_gbm_backend.h b/plugins/platform= s/virtual/egl_gbm_backend.h index b4560ed25..3940e9e24 100644 --- a/plugins/platforms/virtual/egl_gbm_backend.h +++ b/plugins/platforms/virtual/egl_gbm_backend.h @@ -20,7 +20,6 @@ along with this program. If not, see . #ifndef KWIN_EGL_GBM_BACKEND_H #define KWIN_EGL_GBM_BACKEND_H #include "abstract_egl_backend.h" -#include "scene_opengl.h" = namespace KWin { @@ -37,7 +36,7 @@ public: EglGbmBackend(VirtualBackend *b); virtual ~EglGbmBackend(); void screenGeometryChanged(const QSize &size) override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture= *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *te= xture) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &d= amagedRegion) override; bool usesOverlayWindow() const override; @@ -68,7 +67,7 @@ public: = private: friend class EglGbmBackend; - EglGbmTexture(SceneOpenGL::Texture *texture, EglGbmBackend *backend); + EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend); }; = } // namespace diff --git a/plugins/platforms/virtual/virtual_backend.cpp b/plugins/platfo= rms/virtual/virtual_backend.cpp index c8b20d6d5..1f2c384ae 100644 --- a/plugins/platforms/virtual/virtual_backend.cpp +++ b/plugins/platforms/virtual/virtual_backend.cpp @@ -29,6 +29,7 @@ along with this program. If not, see . // system #include #include +#include #if HAVE_GBM #include #endif diff --git a/plugins/platforms/wayland/CMakeLists.txt b/plugins/platforms/w= ayland/CMakeLists.txt index bdef9cff2..1fc8e3639 100644 --- a/plugins/platforms/wayland/CMakeLists.txt +++ b/plugins/platforms/wayland/CMakeLists.txt @@ -8,11 +8,12 @@ if(HAVE_WAYLAND_EGL) set(WAYLAND_BACKEND_SOURCES egl_wayland_backend.cpp ${WAYLAND_BACKEND_= SOURCES}) endif() = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) add_library(KWinWaylandWaylandBackend MODULE ${WAYLAND_BACKEND_SOURCES}) target_link_libraries(KWinWaylandWaylandBackend kwin KF5::WaylandClient Sc= eneQPainterBackend) = if(HAVE_WAYLAND_EGL) - target_link_libraries(KWinWaylandWaylandBackend Wayland::Egl) + target_link_libraries(KWinWaylandWaylandBackend SceneOpenGLBackend Way= land::Egl) endif() = install( diff --git a/plugins/platforms/wayland/egl_wayland_backend.cpp b/plugins/pl= atforms/wayland/egl_wayland_backend.cpp index 3107780f3..16f64888b 100644 --- a/plugins/platforms/wayland/egl_wayland_backend.cpp +++ b/plugins/platforms/wayland/egl_wayland_backend.cpp @@ -213,7 +213,7 @@ void EglWaylandBackend::screenGeometryChanged(const QSi= ze &size) m_bufferAge =3D 0; } = -SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(Scene= OpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglWaylandBackend::createBackendTexture(SceneOp= enGLTexture *texture) { return new EglWaylandTexture(texture, this); } @@ -280,7 +280,7 @@ bool EglWaylandBackend::usesOverlayWindow() const * EglTexture ************************************************/ = -EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, = KWin::EglWaylandBackend *backend) +EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGLTexture *texture, KW= in::EglWaylandBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/wayland/egl_wayland_backend.h b/plugins/plat= forms/wayland/egl_wayland_backend.h index 0b2893d86..e42da7df3 100644 --- a/plugins/platforms/wayland/egl_wayland_backend.h +++ b/plugins/platforms/wayland/egl_wayland_backend.h @@ -20,7 +20,6 @@ along with this program. If not, see . #ifndef KWIN_EGL_WAYLAND_BACKEND_H #define KWIN_EGL_WAYLAND_BACKEND_H #include "abstract_egl_backend.h" -#include "scene_opengl.h" // wayland #include = @@ -54,7 +53,7 @@ public: EglWaylandBackend(Wayland::WaylandBackend *b); virtual ~EglWaylandBackend(); virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL:= :Texture *texture); + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTex= ture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &renderedRegion, const QR= egion &damagedRegion); virtual bool usesOverlayWindow() const override; @@ -88,7 +87,7 @@ public: = private: friend class EglWaylandBackend; - EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *ba= ckend); + EglWaylandTexture(SceneOpenGLTexture *texture, EglWaylandBackend *back= end); }; = } // namespace diff --git a/plugins/platforms/x11/common/CMakeLists.txt b/plugins/platform= s/x11/common/CMakeLists.txt index 5a1ab6d0a..677f9f6c9 100644 --- a/plugins/platforms/x11/common/CMakeLists.txt +++ b/plugins/platforms/x11/common/CMakeLists.txt @@ -4,5 +4,6 @@ endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-int-to-void-pointer-cast") endif() +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) add_library(eglx11common STATIC eglonxbackend.cpp) target_link_libraries(eglx11common kwin) diff --git a/plugins/platforms/x11/common/eglonxbackend.cpp b/plugins/platf= orms/x11/common/eglonxbackend.cpp index 6eaf518a3..1990fc49b 100644 --- a/plugins/platforms/x11/common/eglonxbackend.cpp +++ b/plugins/platforms/x11/common/eglonxbackend.cpp @@ -23,11 +23,15 @@ along with this program. If not, see . #include "options.h" #include "overlaywindow.h" #include "platform.h" +#include "scene.h" #include "screens.h" #include "xcbutils.h" +#include "texture.h" // kwin libs #include +#include // Qt +#include #include #include // system @@ -386,7 +390,7 @@ void EglOnXBackend::screenGeometryChanged(const QSize &= size) m_bufferAge =3D 0; } = -SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpen= GL::Texture *texture) +SceneOpenGLTexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL= Texture *texture) { return new EglTexture(texture, this); } @@ -473,7 +477,7 @@ bool EglOnXBackend::makeContextCurrent(const EGLSurface= &surface) * EglTexture ************************************************/ = -EglTexture::EglTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglOnXBa= ckend *backend) +EglTexture::EglTexture(KWin::SceneOpenGLTexture *texture, KWin::EglOnXBack= end *backend) : AbstractEglTexture(texture, backend) , m_backend(backend) { diff --git a/plugins/platforms/x11/common/eglonxbackend.h b/plugins/platfor= ms/x11/common/eglonxbackend.h index 941f660d6..0063971bf 100644 --- a/plugins/platforms/x11/common/eglonxbackend.h +++ b/plugins/platforms/x11/common/eglonxbackend.h @@ -20,7 +20,9 @@ along with this program. If not, see . #ifndef KWIN_EGL_ON_X_BACKEND_H #define KWIN_EGL_ON_X_BACKEND_H #include "abstract_egl_backend.h" -#include "scene_opengl.h" +#include "swap_profiler.h" + +#include = namespace KWin { @@ -35,7 +37,7 @@ public: explicit EglOnXBackend(xcb_connection_t *connection, Display *display,= xcb_window_t rootWindow, int screenNumber, xcb_window_t renderingWindow); virtual ~EglOnXBackend(); virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL:= :Texture *texture); + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTex= ture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &damage, const QRegion &d= amagedRegion); virtual OverlayWindow* overlayWindow() override; @@ -80,6 +82,7 @@ private: xcb_window_t m_renderingWindow =3D XCB_WINDOW_NONE; bool m_havePlatformBase =3D false; bool m_x11TextureFromPixmapSupported =3D true; + SwapProfiler m_swapProfiler; friend class EglTexture; }; = @@ -96,7 +99,7 @@ public: private: bool loadTexture(xcb_pixmap_t pix, const QSize &size); friend class EglOnXBackend; - EglTexture(SceneOpenGL::Texture *texture, EglOnXBackend *backend); + EglTexture(SceneOpenGLTexture *texture, EglOnXBackend *backend); EglOnXBackend *m_backend; }; = diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/plat= forms/x11/standalone/CMakeLists.txt index 20bab3f5a..2b1ee845d 100644 --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -19,8 +19,10 @@ if(HAVE_EPOXY_GLX) set(X11PLATFORM_SOURCES ${X11PLATFORM_SOURCES} glxbackend.cpp glx_cont= ext_attribute_builder.cpp) endif() = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) + add_library(KWinX11Platform MODULE ${X11PLATFORM_SOURCES}) -target_link_libraries(KWinX11Platform eglx11common kwin Qt5::X11Extras XCB= ::CURSOR) +target_link_libraries(KWinX11Platform eglx11common kwin SceneOpenGLBackend= Qt5::X11Extras XCB::CURSOR) if(X11_Xinput_FOUND) target_link_libraries(KWinX11Platform ${X11_Xinput_LIB}) endif() diff --git a/plugins/platforms/x11/standalone/glxbackend.cpp b/plugins/plat= forms/x11/standalone/glxbackend.cpp index f61bb6801..ff22ec719 100644 --- a/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/plugins/platforms/x11/standalone/glxbackend.cpp @@ -31,10 +31,13 @@ along with this program. If not, see . #include "overlaywindow.h" #include "composite.h" #include "platform.h" +#include "scene.h" #include "screens.h" #include "xcbutils.h" +#include "texture.h" // kwin libs #include +#include #include // Qt #include @@ -48,6 +51,7 @@ along with this program. If not, see . #if HAVE_DL_LIBRARY #include #endif +#include = #ifndef XCB_GLX_BUFFER_SWAP_COMPLETE #define XCB_GLX_BUFFER_SWAP_COMPLETE 1 @@ -722,7 +726,7 @@ void GlxBackend::present() } } else { // Copy Pixels (horribly slow on Mesa) glDrawBuffer(GL_FRONT); - SceneOpenGL::copyPixels(lastDamage()); + copyPixels(lastDamage()); glDrawBuffer(GL_BACK); } = @@ -748,7 +752,7 @@ void GlxBackend::screenGeometryChanged(const QSize &siz= e) m_bufferAge =3D 0; } = -SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL:= :Texture *texture) +SceneOpenGLTexturePrivate *GlxBackend::createBackendTexture(SceneOpenGLTex= ture *texture) { return new GlxTexture(texture, this); } @@ -844,8 +848,8 @@ bool GlxBackend::usesOverlayWindow() const /******************************************************** * GlxTexture *******************************************************/ -GlxTexture::GlxTexture(SceneOpenGL::Texture *texture, GlxBackend *backend) - : SceneOpenGL::TexturePrivate() +GlxTexture::GlxTexture(SceneOpenGLTexture *texture, GlxBackend *backend) + : SceneOpenGLTexturePrivate() , q(texture) , m_backend(backend) , m_glxpixmap(None) diff --git a/plugins/platforms/x11/standalone/glxbackend.h b/plugins/platfo= rms/x11/standalone/glxbackend.h index 59787419e..ff3a0d8f2 100644 --- a/plugins/platforms/x11/standalone/glxbackend.h +++ b/plugins/platforms/x11/standalone/glxbackend.h @@ -19,11 +19,14 @@ along with this program. If not, see . *********************************************************************/ #ifndef KWIN_GLX_BACKEND_H #define KWIN_GLX_BACKEND_H -#include "scene_opengl.h" +#include "backend.h" +#include "texture.h" +#include "swap_profiler.h" #include "x11eventfilter.h" = #include #include +#include #include = namespace KWin @@ -68,7 +71,7 @@ public: GlxBackend(Display *display); virtual ~GlxBackend(); virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL:= :Texture *texture); + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTex= ture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &damage, const QRegion &d= amagedRegion); virtual bool makeCurrent() override; @@ -116,13 +119,14 @@ private: bool haveSwapInterval =3D false; bool haveWaitSync =3D false; Display *m_x11Display; + SwapProfiler m_swapProfiler; friend class GlxTexture; }; = /** * @brief Texture using an GLXPixmap. **/ -class GlxTexture : public SceneOpenGL::TexturePrivate +class GlxTexture : public SceneOpenGLTexturePrivate { public: virtual ~GlxTexture(); @@ -132,12 +136,12 @@ public: = private: friend class GlxBackend; - GlxTexture(SceneOpenGL::Texture *texture, GlxBackend *backend); + GlxTexture(SceneOpenGLTexture *texture, GlxBackend *backend); bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t v= isual); Display *display() const { return m_backend->m_x11Display; } - SceneOpenGL::Texture *q; + SceneOpenGLTexture *q; GlxBackend *m_backend; GLXPixmap m_glxpixmap; // the glx pixmap the texture is bound to }; diff --git a/plugins/platforms/x11/windowed/CMakeLists.txt b/plugins/platfo= rms/x11/windowed/CMakeLists.txt index 2647bcc1f..5042f5cd5 100644 --- a/plugins/platforms/x11/windowed/CMakeLists.txt +++ b/plugins/platforms/x11/windowed/CMakeLists.txt @@ -5,8 +5,9 @@ set(X11BACKEND_SOURCES x11windowed_backend.cpp ) = +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) add_library(KWinWaylandX11Backend MODULE ${X11BACKEND_SOURCES}) -target_link_libraries(KWinWaylandX11Backend eglx11common kwin X11::XCB Sce= neQPainterBackend) +target_link_libraries(KWinWaylandX11Backend eglx11common kwin X11::XCB Sce= neQPainterBackend SceneOpenGLBackend) = install( TARGETS diff --git a/plugins/platforms/x11/windowed/x11windowed_backend.cpp b/plugi= ns/platforms/x11/windowed/x11windowed_backend.cpp index 302bac7f4..95306b027 100644 --- a/plugins/platforms/x11/windowed/x11windowed_backend.cpp +++ b/plugins/platforms/x11/windowed/x11windowed_backend.cpp @@ -27,8 +27,10 @@ along with this program. If not, see . #include // KDE #include +#include #include #include +#include #include // kwayland #include diff --git a/plugins/scenes/CMakeLists.txt b/plugins/scenes/CMakeLists.txt index 8ef7930be..eb84a43ce 100644 --- a/plugins/scenes/CMakeLists.txt +++ b/plugins/scenes/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(opengl) add_subdirectory(qpainter) if( KWIN_BUILD_XRENDER_COMPOSITING ) add_subdirectory(xrender) diff --git a/plugins/scenes/opengl/CMakeLists.txt b/plugins/scenes/opengl/C= MakeLists.txt new file mode 100644 index 000000000..47684dfe0 --- /dev/null +++ b/plugins/scenes/opengl/CMakeLists.txt @@ -0,0 +1,26 @@ +set(SCENE_OPENGL_SRCS scene_opengl.cpp) + +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category( + SCENE_OPENGL_SRCS HEADER + logging.h + IDENTIFIER + KWIN_OPENGL + CATEGORY_NAME + kwin_scene_opengl + DEFAULT_SEVERITY + Critical +) + +add_library(KWinSceneOpenGL MODULE scene_opengl.cpp) +target_link_libraries(KWinSceneOpenGL + kwin + SceneOpenGLBackend +) + +install( + TARGETS + KWinSceneOpenGL + DESTINATION + ${PLUGIN_INSTALL_DIR}/org.kde.kwin.scenes/ +) diff --git a/plugins/scenes/opengl/opengl.json b/plugins/scenes/opengl/open= gl.json new file mode 100644 index 000000000..e31a6d8e0 --- /dev/null +++ b/plugins/scenes/opengl/opengl.json @@ -0,0 +1,9 @@ +{ + "CompositingType": 1, + "KPlugin": { + "Description": "KWin Compositor plugin rendering through OpenGL", + "Id": "KWinSceneOpenGL", + "Name": "SceneOpenGL" + } +} + diff --git a/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp similarity index 92% rename from scene_opengl.cpp rename to plugins/scenes/opengl/scene_opengl.cpp index 94b5bb15c..fef030613 100644 --- a/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -30,6 +30,7 @@ along with this program. If not, see . = #include "platform.h" #include "wayland_server.h" +#include "platformsupport/scenes/opengl/texture.h" = #include = @@ -44,6 +45,7 @@ along with this program. If not, see . #include "screens.h" #include "cursor.h" #include "decorations/decoratedclient.h" +#include = #include #include @@ -180,18 +182,18 @@ bool SyncObject::finish() glGetSynciv(m_sync, GL_SYNC_STATUS, 1, nullptr, &value); = if (value !=3D GL_SIGNALED) { - qCDebug(KWIN_CORE) << "Waiting for X fence to finish"; + qCDebug(KWIN_OPENGL) << "Waiting for X fence to finish"; = // Wait for the fence to become signaled with a one second timeout const GLenum result =3D glClientWaitSync(m_sync, 0, 1000000000); = switch (result) { case GL_TIMEOUT_EXPIRED: - qCWarning(KWIN_CORE) << "Timeout while waiting for X fence"; + qCWarning(KWIN_OPENGL) << "Timeout while waiting for X fence"; return false; = case GL_WAIT_FAILED: - qCWarning(KWIN_CORE) << "glClientWaitSync() failed"; + qCWarning(KWIN_OPENGL) << "glClientWaitSync() failed"; return false; } } @@ -302,85 +304,6 @@ bool SyncManager::updateFences() = // ----------------------------------------------------------------------- = - - -//**************************************** -// SceneOpenGL -//**************************************** -OpenGLBackend::OpenGLBackend() - : m_syncsToVBlank(false) - , m_blocksForRetrace(false) - , m_directRendering(false) - , m_haveBufferAge(false) - , m_failed(false) -{ -} - -OpenGLBackend::~OpenGLBackend() -{ -} - -void OpenGLBackend::setFailed(const QString &reason) -{ - qCWarning(KWIN_CORE) << "Creating the OpenGL rendering failed: " << re= ason; - m_failed =3D true; -} - -void OpenGLBackend::idle() -{ - if (hasPendingFlush()) { - effects->makeOpenGLContextCurrent(); - present(); - } -} - -void OpenGLBackend::addToDamageHistory(const QRegion ®ion) -{ - if (m_damageHistory.count() > 10) - m_damageHistory.removeLast(); - - m_damageHistory.prepend(region); -} - -QRegion OpenGLBackend::accumulatedDamageHistory(int bufferAge) const -{ - QRegion region; - - // Note: An age of zero means the buffer contents are undefined - if (bufferAge > 0 && bufferAge <=3D m_damageHistory.count()) { - for (int i =3D 0; i < bufferAge - 1; i++) - region |=3D m_damageHistory[i]; - } else { - const QSize &s =3D screens()->size(); - region =3D QRegion(0, 0, s.width(), s.height()); - } - - return region; -} - -OverlayWindow* OpenGLBackend::overlayWindow() -{ - return NULL; -} - -QRegion OpenGLBackend::prepareRenderingForScreen(int screenId) -{ - // fallback to repaint complete screen - return screens()->geometry(screenId); -} - -void OpenGLBackend::endRenderingFrameForScreen(int screenId, const QRegion= &damage, const QRegion &damagedRegion) -{ - Q_UNUSED(screenId) - Q_UNUSED(damage) - Q_UNUSED(damagedRegion) -} - -bool OpenGLBackend::perScreenRendering() const -{ - return false; -} - /************************************************ * SceneOpenGL ***********************************************/ @@ -403,12 +326,12 @@ SceneOpenGL::SceneOpenGL(OpenGLBackend *backend, QObj= ect *parent) GLPlatform *glPlatform =3D GLPlatform::instance(); if (!glPlatform->isGLES() && !hasGLExtension(QByteArrayLiteral("GL_ARB= _texture_non_power_of_two")) && !hasGLExtension(QByteArrayLiteral("GL_ARB_texture_rectangle= "))) { - qCCritical(KWIN_CORE) << "GL_ARB_texture_non_power_of_two and GL_A= RB_texture_rectangle missing"; + qCCritical(KWIN_OPENGL) << "GL_ARB_texture_non_power_of_two and GL= _ARB_texture_rectangle missing"; init_ok =3D false; return; // error } if (glPlatform->isMesaDriver() && glPlatform->mesaVersion() < kVersion= Number(10, 0)) { - qCCritical(KWIN_CORE) << "KWin requires at least Mesa 10.0 for Ope= nGL compositing."; + qCCritical(KWIN_OPENGL) << "KWin requires at least Mesa 10.0 for O= penGL compositing."; init_ok =3D false; return; } @@ -432,10 +355,10 @@ SceneOpenGL::SceneOpenGL(OpenGLBackend *backend, QObj= ect *parent) const QByteArray useExplicitSync =3D qgetenv("KWIN_EXPLICIT_SYNC"); = if (useExplicitSync !=3D "0") { - qCDebug(KWIN_CORE) << "Initializing fences for synchronization= with the X command stream"; + qCDebug(KWIN_OPENGL) << "Initializing fences for synchronizati= on with the X command stream"; m_syncManager =3D new SyncManager; } else { - qCDebug(KWIN_CORE) << "Explicit synchronization with the X com= mand stream disabled by environment variable"; + qCDebug(KWIN_OPENGL) << "Explicit synchronization with the X c= ommand stream disabled by environment variable"; } } } @@ -514,7 +437,7 @@ void SceneOpenGL::initDebugOutput() switch (type) { case GL_DEBUG_TYPE_ERROR: case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - qCWarning(KWIN_CORE, "%#x: %.*s", id, length, message); + qCWarning(KWIN_OPENGL, "%#x: %.*s", id, length, message); break; = case GL_DEBUG_TYPE_OTHER: @@ -532,7 +455,7 @@ void SceneOpenGL::initDebugOutput() case GL_DEBUG_TYPE_PORTABILITY: case GL_DEBUG_TYPE_PERFORMANCE: default: - qCDebug(KWIN_CORE, "%#x: %.*s", id, length, message); + qCDebug(KWIN_OPENGL, "%#x: %.*s", id, length, message); break; } }; @@ -584,9 +507,9 @@ SceneOpenGL *SceneOpenGL::createScene(QObject *parent) } if (!scene) { if (GLPlatform::instance()->recommendedCompositor() =3D=3D XRender= Compositing) { - qCCritical(KWIN_CORE) << "OpenGL driver recommends XRender bas= ed compositing. Falling back to XRender."; - qCCritical(KWIN_CORE) << "To overwrite the detection use the e= nvironment variable KWIN_COMPOSE"; - qCCritical(KWIN_CORE) << "For more information see http://comm= unity.kde.org/KWin/Environment_Variables#KWIN_COMPOSE"; + qCCritical(KWIN_OPENGL) << "OpenGL driver recommends XRender b= ased compositing. Falling back to XRender."; + qCCritical(KWIN_OPENGL) << "To overwrite the detection use the= environment variable KWIN_COMPOSE"; + qCCritical(KWIN_OPENGL) << "For more information see http://co= mmunity.kde.org/KWin/Environment_Variables#KWIN_COMPOSE"; QTimer::singleShot(0, Compositor::self(), SLOT(fallbackToXRend= erCompositing())); } delete backend; @@ -621,32 +544,19 @@ bool SceneOpenGL::initFailed() const return !init_ok; } = -void SceneOpenGL::copyPixels(const QRegion ®ion) -{ - const int height =3D screens()->size().height(); - foreach (const QRect &r, region.rects()) { - const int x0 =3D r.x(); - const int y0 =3D height - r.y() - r.height(); - const int x1 =3D r.x() + r.width(); - const int y1 =3D height - r.y(); - - glBlitFramebuffer(x0, y0, x1, y1, x0, y0, x1, y1, GL_COLOR_BUFFER_= BIT, GL_NEAREST); - } -} - void SceneOpenGL::handleGraphicsReset(GLenum status) { switch (status) { case GL_GUILTY_CONTEXT_RESET: - qCDebug(KWIN_CORE) << "A graphics reset attributable to the curren= t GL context occurred."; + qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the curr= ent GL context occurred."; break; = case GL_INNOCENT_CONTEXT_RESET: - qCDebug(KWIN_CORE) << "A graphics reset not attributable to the cu= rrent GL context occurred."; + qCDebug(KWIN_OPENGL) << "A graphics reset not attributable to the = current GL context occurred."; break; = case GL_UNKNOWN_CONTEXT_RESET: - qCDebug(KWIN_CORE) << "A graphics reset of an unknown cause occurr= ed."; + qCDebug(KWIN_OPENGL) << "A graphics reset of an unknown cause occu= rred."; break; = default: @@ -660,7 +570,7 @@ void SceneOpenGL::handleGraphicsReset(GLenum status) while (timer.elapsed() < 10000 && glGetGraphicsResetStatus() !=3D GL_N= O_ERROR) usleep(50); = - qCDebug(KWIN_CORE) << "Attempting to reset compositing."; + qCDebug(KWIN_OPENGL) << "Attempting to reset compositing."; QMetaObject::invokeMethod(this, "resetCompositing", Qt::QueuedConnecti= on); = KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop ef= fects were restarted due to a graphics reset")); @@ -800,7 +710,7 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList = toplevels) options->glPreferBufferSwap() =3D=3D Options::CopyFrontBuf= fer && validRegion !=3D displayRegion) { glReadBuffer(GL_FRONT); - copyPixels(displayRegion - validRegion); + m_backend->copyPixels(displayRegion - validRegion); glReadBuffer(GL_BACK); validRegion =3D displayRegion; } @@ -815,8 +725,8 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList = toplevels) = if (m_currentFence) { if (!m_syncManager->updateFences()) { - qCDebug(KWIN_CORE) << "Aborting explicit synchronization with = the X command stream."; - qCDebug(KWIN_CORE) << "Future frames will be rendered unsynchr= onized."; + qCDebug(KWIN_OPENGL) << "Aborting explicit synchronization wit= h the X command stream."; + qCDebug(KWIN_OPENGL) << "Future frames will be rendered unsync= hronized."; delete m_syncManager; m_syncManager =3D nullptr; } @@ -902,9 +812,9 @@ void SceneOpenGL::extendPaintRegion(QRegion ®ion, bo= ol opaqueFullscreen) } } = -SceneOpenGL::Texture *SceneOpenGL::createTexture() +SceneOpenGLTexture *SceneOpenGL::createTexture() { - return new Texture(m_backend); + return new SceneOpenGLTexture(m_backend); } = bool SceneOpenGL::viewportLimitsMatched(const QSize &size) const { @@ -1034,7 +944,7 @@ bool SceneOpenGL2::supported(OpenGLBackend *backend) const QByteArray forceEnv =3D qgetenv("KWIN_COMPOSE"); if (!forceEnv.isEmpty()) { if (qstrcmp(forceEnv, "O2") =3D=3D 0 || qstrcmp(forceEnv, "O2ES") = =3D=3D 0) { - qCDebug(KWIN_CORE) << "OpenGL 2 compositing enforced by enviro= nment variable"; + qCDebug(KWIN_OPENGL) << "OpenGL 2 compositing enforced by envi= ronment variable"; return true; } else { // OpenGL 2 disabled by environment variable @@ -1045,7 +955,7 @@ bool SceneOpenGL2::supported(OpenGLBackend *backend) return false; } if (GLPlatform::instance()->recommendedCompositor() < OpenGL2Compositi= ng) { - qCDebug(KWIN_CORE) << "Driver does not recommend OpenGL 2 composit= ing"; + qCDebug(KWIN_OPENGL) << "Driver does not recommend OpenGL 2 compos= iting"; return false; } return true; @@ -1062,7 +972,7 @@ SceneOpenGL2::SceneOpenGL2(OpenGLBackend *backend, QOb= ject *parent) = // We only support the OpenGL 2+ shader API, not GL_ARB_shader_objects if (!hasGLVersion(2, 0)) { - qCDebug(KWIN_CORE) << "OpenGL 2.0 is not supported"; + qCDebug(KWIN_OPENGL) << "OpenGL 2.0 is not supported"; init_ok =3D false; return; } @@ -1074,7 +984,7 @@ SceneOpenGL2::SceneOpenGL2(OpenGLBackend *backend, QOb= ject *parent) // push one shader on the stack so that one is always bound ShaderManager::instance()->pushShader(ShaderTrait::MapTexture); if (checkGLError("Init")) { - qCCritical(KWIN_CORE) << "OpenGL 2 compositing setup failed"; + qCCritical(KWIN_OPENGL) << "OpenGL 2 compositing setup failed"; init_ok =3D false; return; // error } @@ -1086,12 +996,12 @@ SceneOpenGL2::SceneOpenGL2(OpenGLBackend *backend, Q= Object *parent) } = if (!ShaderManager::instance()->selfTest()) { - qCCritical(KWIN_CORE) << "ShaderManager self test failed"; + qCCritical(KWIN_OPENGL) << "ShaderManager self test failed"; init_ok =3D false; return; } = - qCDebug(KWIN_CORE) << "OpenGL 2 compositing successfully initialized"; + qCDebug(KWIN_OPENGL) << "OpenGL 2 compositing successfully initialized= "; init_ok =3D true; } = @@ -1200,65 +1110,6 @@ void SceneOpenGL2::resetLanczosFilter() m_lanczosFilter =3D NULL; } = -//**************************************** -// SceneOpenGL::Texture -//**************************************** - -SceneOpenGL::Texture::Texture(OpenGLBackend *backend) - : GLTexture(*backend->createBackendTexture(this)) -{ -} - -SceneOpenGL::Texture::~Texture() -{ -} - -SceneOpenGL::Texture& SceneOpenGL::Texture::operator =3D (const SceneOpenG= L::Texture& tex) -{ - d_ptr =3D tex.d_ptr; - return *this; -} - -void SceneOpenGL::Texture::discard() -{ - d_ptr =3D d_func()->backend()->createBackendTexture(this); -} - -bool SceneOpenGL::Texture::load(WindowPixmap *pixmap) -{ - if (!pixmap->isValid()) { - return false; - } - - // decrease the reference counter for the old texture - d_ptr =3D d_func()->backend()->createBackendTexture(this); //new Textu= rePrivate(); - - Q_D(Texture); - return d->loadTexture(pixmap); -} - -void SceneOpenGL::Texture::updateFromPixmap(WindowPixmap *pixmap) -{ - Q_D(Texture); - d->updateTexture(pixmap); -} - -//**************************************** -// SceneOpenGL::Texture -//**************************************** -SceneOpenGL::TexturePrivate::TexturePrivate() -{ -} - -SceneOpenGL::TexturePrivate::~TexturePrivate() -{ -} - -void SceneOpenGL::TexturePrivate::updateTexture(WindowPixmap *pixmap) -{ - Q_UNUSED(pixmap) -} - //**************************************** // SceneOpenGL::Window //**************************************** @@ -1273,7 +1124,7 @@ SceneOpenGL::Window::~Window() { } = -static SceneOpenGL::Texture *s_frameTexture =3D NULL; +static SceneOpenGLTexture *s_frameTexture =3D NULL; // Bind the window pixmap to an OpenGL texture. bool SceneOpenGL::Window::bindTexture() { @@ -1750,7 +1601,7 @@ bool OpenGLWindowPixmap::bind() toplevel()->resetDamage(); } } else - qCDebug(KWIN_CORE) << "Failed to bind window"; + qCDebug(KWIN_OPENGL) << "Failed to bind window"; return success; } = @@ -2475,36 +2326,6 @@ bool SceneOpenGLShadow::prepareBackend() return true; } = -SwapProfiler::SwapProfiler() -{ - init(); -} - -void SwapProfiler::init() -{ - m_time =3D 2 * 1000*1000; // we start with a long time mean of 2ms ... - m_counter =3D 0; -} - -void SwapProfiler::begin() -{ - m_timer.start(); -} - -char SwapProfiler::end() -{ - // .. and blend in actual values. - // this way we prevent extremes from killing our long time mean - m_time =3D (10*m_time + m_timer.nsecsElapsed())/11; - if (++m_counter > 500) { - const bool blocks =3D m_time > 1000 * 1000; // 1ms, i get ~250=C2= =B5s and ~7ms w/o triple buffering... - qCDebug(KWIN_CORE) << "Triple buffering detection:" << QString(blo= cks ? QStringLiteral("NOT available") : QStringLiteral("Available")) << - " - Mean block time:" << m_time/(1000.0*1000.0) <<= "ms"; - return blocks ? 'd' : 't'; - } - return 0; -} - SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::D= ecoratedClientImpl *client) : Renderer(client) , m_texture() @@ -2612,4 +2433,31 @@ void SceneOpenGLDecorationRenderer::reparent(Deleted= *deleted) Renderer::reparent(deleted); } = + +OpenGLFactory::OpenGLFactory(QObject *parent) + : SceneFactory(parent) +{ +} + +OpenGLFactory::~OpenGLFactory() =3D default; + +Scene *OpenGLFactory::create(QObject *parent) const +{ + qCDebug(KWIN_OPENGL) << "Initializing OpenGL compositing"; + + // Some broken drivers crash on glXQuery() so to prevent constant KWin= crashes: + if (kwinApp()->platform()->openGLCompositingIsBroken()) { + qCWarning(KWIN_OPENGL) << "KWin has detected that your OpenGL libr= ary is unsafe to use"; + return nullptr; + } + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint= ::PreInit); + auto s =3D SceneOpenGL::createScene(parent); + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint= ::PostInit); + if (s && s->initFailed()) { + delete s; + return nullptr; + } + return s; +} + } // namespace diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/s= cene_opengl.h new file mode 100644 index 000000000..8cc78d404 --- /dev/null +++ b/plugins/scenes/opengl/scene_opengl.h @@ -0,0 +1,357 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2006 Lubos Lunak +Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin + +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 KWIN_SCENE_OPENGL_H +#define KWIN_SCENE_OPENGL_H + +#include "scene.h" +#include "shadow.h" + +#include "kwinglutils.h" + +#include "decorations/decorationrenderer.h" +#include "platformsupport/scenes/opengl/backend.h" + +namespace KWin +{ +class LanczosFilter; +class OpenGLBackend; +class SyncManager; +class SyncObject; + +class KWIN_EXPORT SceneOpenGL + : public Scene +{ + Q_OBJECT +public: + class EffectFrame; + class Window; + virtual ~SceneOpenGL(); + virtual bool initFailed() const; + virtual bool hasPendingFlush() const; + virtual qint64 paint(QRegion damage, ToplevelList windows); + virtual Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame); + virtual Shadow *createShadow(Toplevel *toplevel); + virtual void screenGeometryChanged(const QSize &size); + virtual OverlayWindow *overlayWindow(); + virtual bool usesOverlayWindow() const; + virtual bool blocksForRetrace() const; + virtual bool syncsToVBlank() const; + virtual bool makeOpenGLContextCurrent() override; + virtual void doneOpenGLContextCurrent() override; + Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedCl= ientImpl *impl) override; + virtual void triggerFence() override; + virtual QMatrix4x4 projectionMatrix() const =3D 0; + bool animationsSupported() const override; + + void insertWait(); + + void idle(); + + bool debug() const { return m_debug; } + void initDebugOutput(); + + /** + * @brief Factory method to create a backend specific texture. + * + * @return :SceneOpenGL::Texture* + **/ + SceneOpenGLTexture *createTexture(); + + OpenGLBackend *backend() const { + return m_backend; + } + + QVector openGLPlatformInterfaceExtensions() const override; + + static SceneOpenGL *createScene(QObject *parent); + +protected: + SceneOpenGL(OpenGLBackend *backend, QObject *parent =3D nullptr); + virtual void paintBackground(QRegion region); + virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); + QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; + virtual void paintDesktop(int desktop, int mask, const QRegion ®ion= , ScreenPaintData &data); + + void handleGraphicsReset(GLenum status); + + virtual void doPaintBackground(const QVector &vertices) =3D 0; + virtual void updateProjectionMatrix() =3D 0; + +protected: + bool init_ok; +private: + bool viewportLimitsMatched(const QSize &size) const; +private: + bool m_debug; + OpenGLBackend *m_backend; + SyncManager *m_syncManager; + SyncObject *m_currentFence; +}; + +class SceneOpenGL2 : public SceneOpenGL +{ + Q_OBJECT +public: + explicit SceneOpenGL2(OpenGLBackend *backend, QObject *parent =3D null= ptr); + virtual ~SceneOpenGL2(); + virtual CompositingType compositingType() const { + return OpenGL2Compositing; + } + + static bool supported(OpenGLBackend *backend); + + QMatrix4x4 projectionMatrix() const override { return m_projectionMatr= ix; } + QMatrix4x4 screenProjectionMatrix() const override { return m_screenPr= ojectionMatrix; } + +protected: + virtual void paintSimpleScreen(int mask, QRegion region); + virtual void paintGenericScreen(int mask, ScreenPaintData data); + virtual void doPaintBackground(const QVector< float >& vertices); + virtual Scene::Window *createWindow(Toplevel *t); + virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion re= gion, WindowPaintData& data); + virtual void updateProjectionMatrix() override; + void paintCursor() override; + +private Q_SLOTS: + void resetLanczosFilter(); + +private: + void performPaintWindow(EffectWindowImpl* w, int mask, QRegion region,= WindowPaintData& data); + QMatrix4x4 createProjectionMatrix() const; + +private: + LanczosFilter *m_lanczosFilter; + QScopedPointer m_cursorTexture; + QMatrix4x4 m_projectionMatrix; + QMatrix4x4 m_screenProjectionMatrix; + GLuint vao; +}; + +class SceneOpenGL::Window + : public Scene::Window +{ +public: + virtual ~Window(); + bool beginRenderWindow(int mask, const QRegion ®ion, WindowPaintDat= a &data); + virtual void performPaint(int mask, QRegion region, WindowPaintData da= ta) =3D 0; + void endRenderWindow(); + bool bindTexture(); + void setScene(SceneOpenGL *scene) { + m_scene =3D scene; + } + +protected: + virtual WindowPixmap* createWindowPixmap(); + Window(Toplevel* c); + enum TextureType { + Content, + Decoration, + Shadow + }; + + QMatrix4x4 transformation(int mask, const WindowPaintData &data) const; + GLTexture *getDecorationTexture() const; + +protected: + SceneOpenGL *m_scene; + bool m_hardwareClipping; +}; + +class SceneOpenGL2Window : public SceneOpenGL::Window +{ +public: + enum Leaf { ShadowLeaf =3D 0, DecorationLeaf, ContentLeaf, PreviousCon= tentLeaf, LeafCount }; + + struct LeafNode + { + LeafNode() + : texture(0), + firstVertex(0), + vertexCount(0), + opacity(1.0), + hasAlpha(false), + coordinateType(UnnormalizedCoordinates) + { + } + + GLTexture *texture; + int firstVertex; + int vertexCount; + float opacity; + bool hasAlpha; + TextureCoordinateType coordinateType; + }; + + explicit SceneOpenGL2Window(Toplevel *c); + virtual ~SceneOpenGL2Window(); + +protected: + QMatrix4x4 modelViewProjectionMatrix(int mask, const WindowPaintData &= data) const; + QVector4D modulate(float opacity, float brightness) const; + void setBlendEnabled(bool enabled); + void setupLeafNodes(LeafNode *nodes, const WindowQuadList *quads, cons= t WindowPaintData &data); + virtual void performPaint(int mask, QRegion region, WindowPaintData da= ta); + +private: + /** + * Whether prepareStates enabled blending and restore states should di= sable again. + **/ + bool m_blendingEnabled; +}; + +class OpenGLWindowPixmap : public WindowPixmap +{ +public: + explicit OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL *scene); + virtual ~OpenGLWindowPixmap(); + SceneOpenGLTexture *texture() const; + bool bind(); + bool isValid() const override; +protected: + WindowPixmap *createChild(const QPointer &subSurface) override; +private: + explicit OpenGLWindowPixmap(const QPointer &subSurface, WindowPixmap *parent, SceneOpenGL *scene); + QScopedPointer m_texture; + SceneOpenGL *m_scene; +}; + +class SceneOpenGL::EffectFrame + : public Scene::EffectFrame +{ +public: + EffectFrame(EffectFrameImpl* frame, SceneOpenGL *scene); + virtual ~EffectFrame(); + + virtual void free(); + virtual void freeIconFrame(); + virtual void freeTextFrame(); + virtual void freeSelection(); + + virtual void render(QRegion region, double opacity, double frameOpacit= y); + + virtual void crossFadeIcon(); + virtual void crossFadeText(); + + static void cleanup(); + +private: + void updateTexture(); + void updateTextTexture(); + + GLTexture *m_texture; + GLTexture *m_textTexture; + GLTexture *m_oldTextTexture; + QPixmap *m_textPixmap; // need to keep the pixmap around to workaround= some driver problems + GLTexture *m_iconTexture; + GLTexture *m_oldIconTexture; + GLTexture *m_selectionTexture; + GLVertexBuffer *m_unstyledVBO; + SceneOpenGL *m_scene; + + static GLTexture* m_unstyledTexture; + static QPixmap* m_unstyledPixmap; // need to keep the pixmap around to= workaround some driver problems + static void updateUnstyledTexture(); // Update OpenGL unstyled frame t= exture +}; + +/** + * @short OpenGL implementation of Shadow. + * + * This class extends Shadow by the Elements required for OpenGL rendering. + * @author Martin Gr=C3=A4=C3=9Flin + **/ +class SceneOpenGLShadow + : public Shadow +{ +public: + explicit SceneOpenGLShadow(Toplevel *toplevel); + virtual ~SceneOpenGLShadow(); + + GLTexture *shadowTexture() { + return m_texture.data(); + } +protected: + virtual void buildQuads(); + virtual bool prepareBackend(); +private: + QSharedPointer m_texture; +}; + +class SceneOpenGLDecorationRenderer : public Decoration::Renderer +{ + Q_OBJECT +public: + enum class DecorationPart : int { + Left, + Top, + Right, + Bottom, + Count + }; + explicit SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl= *client); + virtual ~SceneOpenGLDecorationRenderer(); + + void render() override; + void reparent(Deleted *deleted) override; + + GLTexture *texture() { + return m_texture.data(); + } + GLTexture *texture() const { + return m_texture.data(); + } + +private: + void resizeTexture(); + QScopedPointer m_texture; +}; + +inline bool SceneOpenGL::hasPendingFlush() const +{ + return m_backend->hasPendingFlush(); +} + +inline bool SceneOpenGL::usesOverlayWindow() const +{ + return m_backend->usesOverlayWindow(); +} + +inline SceneOpenGLTexture* OpenGLWindowPixmap::texture() const +{ + return m_texture.data(); +} + +class KWIN_EXPORT OpenGLFactory : public SceneFactory +{ + Q_OBJECT + Q_INTERFACES(KWin::SceneFactory) + Q_PLUGIN_METADATA(IID "org.kde.kwin.Scene" FILE "opengl.json") + +public: + explicit OpenGLFactory(QObject *parent =3D nullptr); + ~OpenGLFactory() override; + + Scene *create(QObject *parent =3D nullptr) const override; +}; + +} // namespace + +#endif diff --git a/scene.h b/scene.h index d80217b95..8f3b9615f 100644 --- a/scene.h +++ b/scene.h @@ -186,6 +186,7 @@ public: = Q_SIGNALS: void frameRendered(); + void resetCompositing(); = public Q_SLOTS: // a window has been destroyed diff --git a/scene_opengl.h b/scene_opengl.h deleted file mode 100644 index 86360aca2..000000000 --- a/scene_opengl.h +++ /dev/null @@ -1,697 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2006 Lubos Lunak -Copyright (C) 2009, 2010, 2011 Martin Gr=C3=A4=C3=9Flin - -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 KWIN_SCENE_OPENGL_H -#define KWIN_SCENE_OPENGL_H - -#include "scene.h" -#include "shadow.h" - -#include "kwinglutils.h" -#include "kwingltexture_p.h" - -#include "decorations/decorationrenderer.h" - -namespace KWin -{ -class LanczosFilter; -class OpenGLBackend; -class SyncManager; -class SyncObject; - -class KWIN_EXPORT SceneOpenGL - : public Scene -{ - Q_OBJECT -public: - class EffectFrame; - class Texture; - class TexturePrivate; - class Window; - virtual ~SceneOpenGL(); - virtual bool initFailed() const; - virtual bool hasPendingFlush() const; - virtual qint64 paint(QRegion damage, ToplevelList windows); - virtual Scene::EffectFrame *createEffectFrame(EffectFrameImpl *frame); - virtual Shadow *createShadow(Toplevel *toplevel); - virtual void screenGeometryChanged(const QSize &size); - virtual OverlayWindow *overlayWindow(); - virtual bool usesOverlayWindow() const; - virtual bool blocksForRetrace() const; - virtual bool syncsToVBlank() const; - virtual bool makeOpenGLContextCurrent() override; - virtual void doneOpenGLContextCurrent() override; - Decoration::Renderer *createDecorationRenderer(Decoration::DecoratedCl= ientImpl *impl) override; - virtual void triggerFence() override; - virtual QMatrix4x4 projectionMatrix() const =3D 0; - bool animationsSupported() const override; - - void insertWait(); - - void idle(); - - bool debug() const { return m_debug; } - void initDebugOutput(); - - /** - * @brief Factory method to create a backend specific texture. - * - * @return :SceneOpenGL::Texture* - **/ - Texture *createTexture(); - - OpenGLBackend *backend() const { - return m_backend; - } - - QVector openGLPlatformInterfaceExtensions() const override; - - /** - * Copy a region of pixels from the current read to the current draw b= uffer - */ - static void copyPixels(const QRegion ®ion); - - static SceneOpenGL *createScene(QObject *parent); - -protected: - SceneOpenGL(OpenGLBackend *backend, QObject *parent =3D nullptr); - virtual void paintBackground(QRegion region); - virtual void extendPaintRegion(QRegion ®ion, bool opaqueFullscreen); - QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; - virtual void paintDesktop(int desktop, int mask, const QRegion ®ion= , ScreenPaintData &data); - - void handleGraphicsReset(GLenum status); - - virtual void doPaintBackground(const QVector &vertices) =3D 0; - virtual void updateProjectionMatrix() =3D 0; - -Q_SIGNALS: - void resetCompositing(); - -protected: - bool init_ok; -private: - bool viewportLimitsMatched(const QSize &size) const; -private: - bool m_debug; - OpenGLBackend *m_backend; - SyncManager *m_syncManager; - SyncObject *m_currentFence; -}; - -class SceneOpenGL2 : public SceneOpenGL -{ - Q_OBJECT -public: - explicit SceneOpenGL2(OpenGLBackend *backend, QObject *parent =3D null= ptr); - virtual ~SceneOpenGL2(); - virtual CompositingType compositingType() const { - return OpenGL2Compositing; - } - - static bool supported(OpenGLBackend *backend); - - QMatrix4x4 projectionMatrix() const override { return m_projectionMatr= ix; } - QMatrix4x4 screenProjectionMatrix() const override { return m_screenPr= ojectionMatrix; } - -protected: - virtual void paintSimpleScreen(int mask, QRegion region); - virtual void paintGenericScreen(int mask, ScreenPaintData data); - virtual void doPaintBackground(const QVector< float >& vertices); - virtual Scene::Window *createWindow(Toplevel *t); - virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion re= gion, WindowPaintData& data); - virtual void updateProjectionMatrix() override; - void paintCursor() override; - -private Q_SLOTS: - void resetLanczosFilter(); - -private: - void performPaintWindow(EffectWindowImpl* w, int mask, QRegion region,= WindowPaintData& data); - QMatrix4x4 createProjectionMatrix() const; - -private: - LanczosFilter *m_lanczosFilter; - QScopedPointer m_cursorTexture; - QMatrix4x4 m_projectionMatrix; - QMatrix4x4 m_screenProjectionMatrix; - GLuint vao; -}; - -class SceneOpenGL::TexturePrivate - : public GLTexturePrivate -{ -public: - virtual ~TexturePrivate(); - - virtual bool loadTexture(WindowPixmap *pixmap) =3D 0; - virtual void updateTexture(WindowPixmap *pixmap); - virtual OpenGLBackend *backend() =3D 0; - -protected: - TexturePrivate(); - -private: - Q_DISABLE_COPY(TexturePrivate) -}; - -class SceneOpenGL::Texture - : public GLTexture -{ -public: - Texture(OpenGLBackend *backend); - virtual ~Texture(); - - Texture & operator =3D (const Texture& tex); - - void discard() override final; - -protected: - bool load(WindowPixmap *pixmap); - void updateFromPixmap(WindowPixmap *pixmap); - - Texture(TexturePrivate& dd); - -private: - Q_DECLARE_PRIVATE(Texture) - - friend class OpenGLWindowPixmap; -}; - -class SceneOpenGL::Window - : public Scene::Window -{ -public: - virtual ~Window(); - bool beginRenderWindow(int mask, const QRegion ®ion, WindowPaintDat= a &data); - virtual void performPaint(int mask, QRegion region, WindowPaintData da= ta) =3D 0; - void endRenderWindow(); - bool bindTexture(); - void setScene(SceneOpenGL *scene) { - m_scene =3D scene; - } - -protected: - virtual WindowPixmap* createWindowPixmap(); - Window(Toplevel* c); - enum TextureType { - Content, - Decoration, - Shadow - }; - - QMatrix4x4 transformation(int mask, const WindowPaintData &data) const; - GLTexture *getDecorationTexture() const; - -protected: - SceneOpenGL *m_scene; - bool m_hardwareClipping; -}; - -class SceneOpenGL2Window : public SceneOpenGL::Window -{ -public: - enum Leaf { ShadowLeaf =3D 0, DecorationLeaf, ContentLeaf, PreviousCon= tentLeaf, LeafCount }; - - struct LeafNode - { - LeafNode() - : texture(0), - firstVertex(0), - vertexCount(0), - opacity(1.0), - hasAlpha(false), - coordinateType(UnnormalizedCoordinates) - { - } - - GLTexture *texture; - int firstVertex; - int vertexCount; - float opacity; - bool hasAlpha; - TextureCoordinateType coordinateType; - }; - - explicit SceneOpenGL2Window(Toplevel *c); - virtual ~SceneOpenGL2Window(); - -protected: - QMatrix4x4 modelViewProjectionMatrix(int mask, const WindowPaintData &= data) const; - QVector4D modulate(float opacity, float brightness) const; - void setBlendEnabled(bool enabled); - void setupLeafNodes(LeafNode *nodes, const WindowQuadList *quads, cons= t WindowPaintData &data); - virtual void performPaint(int mask, QRegion region, WindowPaintData da= ta); - -private: - /** - * Whether prepareStates enabled blending and restore states should di= sable again. - **/ - bool m_blendingEnabled; -}; - -class OpenGLWindowPixmap : public WindowPixmap -{ -public: - explicit OpenGLWindowPixmap(Scene::Window *window, SceneOpenGL *scene); - virtual ~OpenGLWindowPixmap(); - SceneOpenGL::Texture *texture() const; - bool bind(); - bool isValid() const override; -protected: - WindowPixmap *createChild(const QPointer &subSurface) override; -private: - explicit OpenGLWindowPixmap(const QPointer &subSurface, WindowPixmap *parent, SceneOpenGL *scene); - QScopedPointer m_texture; - SceneOpenGL *m_scene; -}; - -class SceneOpenGL::EffectFrame - : public Scene::EffectFrame -{ -public: - EffectFrame(EffectFrameImpl* frame, SceneOpenGL *scene); - virtual ~EffectFrame(); - - virtual void free(); - virtual void freeIconFrame(); - virtual void freeTextFrame(); - virtual void freeSelection(); - - virtual void render(QRegion region, double opacity, double frameOpacit= y); - - virtual void crossFadeIcon(); - virtual void crossFadeText(); - - static void cleanup(); - -private: - void updateTexture(); - void updateTextTexture(); - - GLTexture *m_texture; - GLTexture *m_textTexture; - GLTexture *m_oldTextTexture; - QPixmap *m_textPixmap; // need to keep the pixmap around to workaround= some driver problems - GLTexture *m_iconTexture; - GLTexture *m_oldIconTexture; - GLTexture *m_selectionTexture; - GLVertexBuffer *m_unstyledVBO; - SceneOpenGL *m_scene; - - static GLTexture* m_unstyledTexture; - static QPixmap* m_unstyledPixmap; // need to keep the pixmap around to= workaround some driver problems - static void updateUnstyledTexture(); // Update OpenGL unstyled frame t= exture -}; - -/** - * @short OpenGL implementation of Shadow. - * - * This class extends Shadow by the Elements required for OpenGL rendering. - * @author Martin Gr=C3=A4=C3=9Flin - **/ -class SceneOpenGLShadow - : public Shadow -{ -public: - explicit SceneOpenGLShadow(Toplevel *toplevel); - virtual ~SceneOpenGLShadow(); - - GLTexture *shadowTexture() { - return m_texture.data(); - } -protected: - virtual void buildQuads(); - virtual bool prepareBackend(); -private: - QSharedPointer m_texture; -}; - -/** - * @short Profiler to detect whether we have triple buffering - * The strategy is to start setBlocksForRetrace(false) but assume blocking= and have the system prove that assumption wrong - **/ -class KWIN_EXPORT SwapProfiler -{ -public: - SwapProfiler(); - void init(); - void begin(); - /** - * @return char being 'd' for double, 't' for triple (or more - but no= n-blocking) buffering and - * 0 (NOT '0') otherwise, so you can act on "if (char result =3D SwapP= rofiler::end()) { fooBar(); } - **/ - char end(); -private: - QElapsedTimer m_timer; - qint64 m_time; - int m_counter; -}; - -/** - * @brief The OpenGLBackend creates and holds the OpenGL context and is re= sponsible for Texture from Pixmap. - * - * The OpenGLBackend is an abstract base class used by the SceneOpenGL to = abstract away the differences - * between various OpenGL windowing systems such as GLX and EGL. - * - * A concrete implementation has to create and release the OpenGL context = in a way so that the - * SceneOpenGL does not have to care about it. - * - * In addition a major task for this class is to generate the SceneOpenGL:= :TexturePrivate which is - * able to perform the texture from pixmap operation in the given backend. - * - * @author Martin Gr=C3=A4=C3=9Flin - **/ -class KWIN_EXPORT OpenGLBackend -{ -public: - OpenGLBackend(); - virtual ~OpenGLBackend(); - - virtual void init() =3D 0; - /** - * @return Time passes since start of rendering current frame. - * @see startRenderTimer - **/ - qint64 renderTime() { - return m_renderTimer.nsecsElapsed(); - } - virtual void screenGeometryChanged(const QSize &size) =3D 0; - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL:= :Texture *texture) =3D 0; - - /** - * @brief Backend specific code to prepare the rendering of a frame in= cluding flushing the - * previously rendered frame to the screen if the backend works this w= ay. - * - * @return A region that if not empty will be repainted in addition to= the damaged region - **/ - virtual QRegion prepareRenderingFrame() =3D 0; - - /** - * @brief Backend specific code to handle the end of rendering a frame. - * - * @param renderedRegion The possibly larger region that has been rend= ered - * @param damagedRegion The damaged region that should be posted - **/ - virtual void endRenderingFrame(const QRegion &damage, const QRegion &d= amagedRegion) =3D 0; - virtual void endRenderingFrameForScreen(int screenId, const QRegion &d= amage, const QRegion &damagedRegion); - virtual bool makeCurrent() =3D 0; - virtual void doneCurrent() =3D 0; - virtual bool usesOverlayWindow() const =3D 0; - /** - * Whether the rendering needs to be split per screen. - * Default implementation returns @c false. - **/ - virtual bool perScreenRendering() const; - virtual QRegion prepareRenderingForScreen(int screenId); - /** - * @brief Compositor is going into idle mode, flushes any pending pain= ts. - **/ - void idle(); - - /** - * @return bool Whether the scene needs to flush a frame. - **/ - bool hasPendingFlush() const { - return !m_lastDamage.isEmpty(); - } - - /** - * @brief Returns the OverlayWindow used by the backend. - * - * A backend does not have to use an OverlayWindow, this is mostly for= the X world. - * In case the backend does not use an OverlayWindow it is allowed to = return @c null. - * It's the task of the caller to check whether it is @c null. - * - * @return :OverlayWindow* - **/ - virtual OverlayWindow *overlayWindow(); - /** - * @brief Whether the creation of the Backend failed. - * - * The SceneOpenGL should test whether the Backend got constructed cor= rectly. If this method - * returns @c true, the SceneOpenGL should not try to start the render= ing. - * - * @return bool @c true if the creation of the Backend failed, @c fals= e otherwise. - **/ - bool isFailed() const { - return m_failed; - } - /** - * @brief Whether the Backend provides VSync. - * - * Currently only the GLX backend can provide VSync. - * - * @return bool @c true if VSync support is available, @c false otherw= ise - **/ - bool syncsToVBlank() const { - return m_syncsToVBlank; - } - /** - * @brief Whether VSync blocks execution until the screen is in the re= trace - * - * Case for waitVideoSync and non triple buffering buffer swaps - * - **/ - bool blocksForRetrace() const { - return m_blocksForRetrace; - } - /** - * @brief Whether the backend uses direct rendering. - * - * Some OpenGLScene modes require direct rendering. E.g. the OpenGL 2 = should not be used - * if direct rendering is not supported by the Scene. - * - * @return bool @c true if the GL context is direct, @c false if indir= ect - **/ - bool isDirectRendering() const { - return m_directRendering; - } - - bool supportsBufferAge() const { - return m_haveBufferAge; - } - - /** - * @returns whether the context is surfaceless - **/ - bool isSurfaceLessContext() const { - return m_surfaceLessContext; - } - - /** - * Returns the damage that has accumulated since a buffer of the given= age was presented. - */ - QRegion accumulatedDamageHistory(int bufferAge) const; - - /** - * Saves the given region to damage history. - */ - void addToDamageHistory(const QRegion ®ion); - - /** - * The backend specific extensions (e.g. EGL/GLX extensions). - * - * Not the OpenGL (ES) extension! - **/ - QList extensions() const { - return m_extensions; - } - - /** - * @returns whether the backend specific extensions contains @p extens= ion. - **/ - bool hasExtension(const QByteArray &extension) const { - return m_extensions.contains(extension); - } - -protected: - /** - * @brief Backend specific flushing of frame to screen. - **/ - virtual void present() =3D 0; - /** - * @brief Sets the backend initialization to failed. - * - * This method should be called by the concrete subclass in case the i= nitialization failed. - * The given @p reason is logged as a warning. - * - * @param reason The reason why the initialization failed. - **/ - void setFailed(const QString &reason); - /** - * @brief Sets whether the backend provides VSync. - * - * Should be called by the concrete subclass once it is determined whe= ther VSync is supported. - * If the subclass does not call this method, the backend defaults to = @c false. - * @param enabled @c true if VSync support available, @c false otherwi= se. - **/ - void setSyncsToVBlank(bool enabled) { - m_syncsToVBlank =3D enabled; - } - /** - * @brief Sets whether the VSync iplementation blocks - * - * Should be called by the concrete subclass once it is determined how= VSync works. - * If the subclass does not call this method, the backend defaults to = @c false. - * @param enabled @c true if VSync blocks, @c false otherwise. - **/ - void setBlocksForRetrace(bool enabled) { - m_blocksForRetrace =3D enabled; - } - /** - * @brief Sets whether the OpenGL context is direct. - * - * Should be called by the concrete subclass once it is determined whe= ther the OpenGL context is - * direct or indirect. - * If the subclass does not call this method, the backend defaults to = @c false. - * - * @param direct @c true if the OpenGL context is direct, @c false if = indirect - **/ - void setIsDirectRendering(bool direct) { - m_directRendering =3D direct; - } - - void setSupportsBufferAge(bool value) { - m_haveBufferAge =3D value; - } - - /** - * @return const QRegion& Damage of previously rendered frame - **/ - const QRegion &lastDamage() const { - return m_lastDamage; - } - void setLastDamage(const QRegion &damage) { - m_lastDamage =3D damage; - } - /** - * @brief Starts the timer for how long it takes to render the frame. - * - * @see renderTime - **/ - void startRenderTimer() { - m_renderTimer.start(); - } - - /** - * @param set whether the context is surface less - **/ - void setSurfaceLessContext(bool set) { - m_surfaceLessContext =3D set; - } - - /** - * Sets the platform-specific @p extensions. - * - * These are the EGL/GLX extensions, not the OpenGL extensions - **/ - void setExtensions(const QList &extensions) { - m_extensions =3D extensions; - } - - SwapProfiler m_swapProfiler; - -private: - /** - * @brief Whether VSync is available and used, defaults to @c false. - **/ - bool m_syncsToVBlank; - /** - * @brief Whether present() will block execution until the next vertic= al retrace @c false. - **/ - bool m_blocksForRetrace; - /** - * @brief Whether direct rendering is used, defaults to @c false. - **/ - bool m_directRendering; - /** - * @brief Whether the backend supports GLX_EXT_buffer_age / EGL_EXT_bu= ffer_age. - */ - bool m_haveBufferAge; - /** - * @brief Whether the initialization failed, of course default to @c f= alse. - **/ - bool m_failed; - /** - * @brief Damaged region of previously rendered frame. - **/ - QRegion m_lastDamage; - /** - * @brief The damage history for the past 10 frames. - */ - QList m_damageHistory; - /** - * @brief Timer to measure how long a frame renders. - **/ - QElapsedTimer m_renderTimer; - bool m_surfaceLessContext =3D false; - - QList m_extensions; -}; - -class SceneOpenGLDecorationRenderer : public Decoration::Renderer -{ - Q_OBJECT -public: - enum class DecorationPart : int { - Left, - Top, - Right, - Bottom, - Count - }; - explicit SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl= *client); - virtual ~SceneOpenGLDecorationRenderer(); - - void render() override; - void reparent(Deleted *deleted) override; - - GLTexture *texture() { - return m_texture.data(); - } - GLTexture *texture() const { - return m_texture.data(); - } - -private: - void resizeTexture(); - QScopedPointer m_texture; -}; - -inline bool SceneOpenGL::hasPendingFlush() const -{ - return m_backend->hasPendingFlush(); -} - -inline bool SceneOpenGL::usesOverlayWindow() const -{ - return m_backend->usesOverlayWindow(); -} - -inline SceneOpenGL::Texture* OpenGLWindowPixmap::texture() const -{ - return m_texture.data(); -} - -} // namespace - -#endif