diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,7 +423,6 @@ toplevel.cpp unmanaged.cpp scene.cpp - scene_opengl.cpp screenlockerwatcher.cpp thumbnailitem.cpp lanczosfilter.cpp @@ -453,7 +452,6 @@ 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 --- a/composite.cpp +++ b/composite.cpp @@ -29,7 +29,6 @@ #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 @@ #include "wayland_server.h" #include "decorations/decoratedclient.h" +#include + #include #include @@ -220,47 +221,6 @@ } } - if (!m_scene) { - switch(options->compositingMode()) { - case OpenGLCompositing: { - qCDebug(KWIN_CORE) << "Initializing OpenGL compositing"; - - // Some broken drivers crash on glXQuery() so to prevent constant KWin crashes: - if (kwinApp()->platform()->openGLCompositingIsBroken()) - qCWarning(KWIN_CORE) << "KWin has detected that your OpenGL library is unsafe to use"; - else { - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); - - m_scene = SceneOpenGL::createScene(this); - - kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); - - if (m_scene && !m_scene->initFailed()) { - connect(static_cast(m_scene), &SceneOpenGL::resetCompositing, this, &Compositor::restart); - break; // --> - } - delete m_scene; - m_scene = NULL; - } - - // Do not Fall back to XRender - it causes problems when selfcheck fails during startup, but works later on - break; - } - default: - qCDebug(KWIN_CORE) << "No compositing enabled"; - m_starting = false; - if (cm_selection) { - cm_selection->owning = false; - cm_selection->release(); - } - if (kwinApp()->platform()->requiresCompositing()) { - qCCritical(KWIN_CORE) << "The used windowing system requires compositing"; - qCCritical(KWIN_CORE) << "We are going to quit KWin now as it is broken"; - qApp->quit(); - } - return; - } - } if (m_scene == NULL || m_scene->initFailed()) { qCCritical(KWIN_CORE) << "Failed to initialize compositing, compositing disabled"; delete m_scene; @@ -277,6 +237,7 @@ } 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 --- a/data/org_kde_kwin.categories +++ b/data/org_kde_kwin.categories @@ -18,3 +18,4 @@ 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 --- a/lanczosfilter.h +++ b/lanczosfilter.h @@ -29,6 +29,7 @@ #include #include +#include namespace KWin { @@ -40,7 +41,7 @@ class GLRenderTarget; class GLShader; -class LanczosFilter +class KWIN_EXPORT LanczosFilter : public QObject { Q_OBJECT diff --git a/libkwineffects/kwingltexture_p.h b/libkwineffects/kwingltexture_p.h --- a/libkwineffects/kwingltexture_p.h +++ b/libkwineffects/kwingltexture_p.h @@ -29,6 +29,8 @@ #include #include #include +#include +#include namespace KWin { diff --git a/platformsupport/scenes/CMakeLists.txt b/platformsupport/scenes/CMakeLists.txt --- 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 --- /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::CoreAddons KF5::ConfigCore KF5::WindowSystem) diff --git a/abstract_egl_backend.h b/platformsupport/scenes/opengl/abstract_egl_backend.h rename from abstract_egl_backend.h rename to platformsupport/scenes/opengl/abstract_egl_backend.h --- a/abstract_egl_backend.h +++ b/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -19,13 +19,23 @@ *********************************************************************/ #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,32 +87,32 @@ QList m_clientExtensions; }; -class KWIN_EXPORT AbstractEglTexture : public SceneOpenGL::TexturePrivate +class KWIN_EXPORT AbstractEglTexture : public SceneOpenGLTexturePrivate { public: virtual ~AbstractEglTexture(); bool loadTexture(WindowPixmap *pixmap) override; void updateTexture(WindowPixmap *pixmap) override; OpenGLBackend *backend() override; protected: - AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend); + AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend); EGLImageKHR image() const { return m_image; } void setImage(const EGLImageKHR &img) { m_image = img; } - SceneOpenGL::Texture *texture() const { + SceneOpenGLTexture *texture() const { return q; } private: bool loadShmTexture(const QPointer &buffer); 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/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp rename from abstract_egl_backend.cpp rename to platformsupport/scenes/opengl/abstract_egl_backend.cpp --- a/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -18,16 +18,20 @@ 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 @@ { EGLint major, minor; if (eglInitialize(m_display, &major, &minor) == EGL_FALSE) { - qCWarning(KWIN_CORE) << "eglInitialize failed"; + qCWarning(KWIN_OPENGL) << "eglInitialize failed"; EGLint error = eglGetError(); if (error != EGL_SUCCESS) { - qCWarning(KWIN_CORE) << "Error during eglInitialize " << error; + qCWarning(KWIN_OPENGL) << "Error during eglInitialize " << error; } return false; } EGLint error = eglGetError(); if (error != 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) == 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 = eglQueryString(m_display, EGL_EXTENSIONS); setExtensions(eglExtensions.split(' ')); return true; @@ -250,13 +254,13 @@ const auto attribs = (*it)->build(); ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs.data()); if (ctx != 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 == EGL_NO_CONTEXT) { - qCCritical(KWIN_CORE) << "Create Context failed"; + qCCritical(KWIN_OPENGL) << "Create Context failed"; return false; } m_context = ctx; @@ -281,8 +285,8 @@ kwinApp()->platform()->setSceneEglSurface(surface); } -AbstractEglTexture::AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend) - : SceneOpenGL::TexturePrivate() +AbstractEglTexture::AbstractEglTexture(SceneOpenGLTexture *texture, AbstractEglBackend *backend) + : SceneOpenGLTexturePrivate() , q(texture) , m_backend(backend) , m_image(EGL_NO_IMAGE_KHR) @@ -453,7 +457,7 @@ q->unbind(); if (EGL_NO_IMAGE_KHR == 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 @@ EGLint format, yInverted; eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_TEXTURE_FORMAT, &format); if (format != EGL_TEXTURE_RGB && format != 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/platformsupport/scenes/opengl/backend.h b/platformsupport/scenes/opengl/backend.h new file mode 100644 --- /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äßlin + +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 responsible 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 SceneOpenGLTexturePrivate which is + * able to perform the texture from pixmap operation in the given backend. + * + * @author Martin Gräßlin + **/ +class KWIN_EXPORT OpenGLBackend +{ +public: + OpenGLBackend(); + virtual ~OpenGLBackend(); + + virtual void init() = 0; + /** + * @return Time passes since start of rendering current frame. + * @see startRenderTimer + **/ + qint64 renderTime() { + return m_renderTimer.nsecsElapsed(); + } + virtual void screenGeometryChanged(const QSize &size) = 0; + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) = 0; + + /** + * @brief Backend specific code to prepare the rendering of a frame including flushing the + * previously rendered frame to the screen if the backend works this way. + * + * @return A region that if not empty will be repainted in addition to the damaged region + **/ + virtual QRegion prepareRenderingFrame() = 0; + + /** + * @brief Backend specific code to handle the end of rendering a frame. + * + * @param renderedRegion The possibly larger region that has been rendered + * @param damagedRegion The damaged region that should be posted + **/ + virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) = 0; + virtual void endRenderingFrameForScreen(int screenId, const QRegion &damage, const QRegion &damagedRegion); + virtual bool makeCurrent() = 0; + virtual void doneCurrent() = 0; + virtual bool usesOverlayWindow() const = 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 paints. + **/ + 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 correctly. If this method + * returns @c true, the SceneOpenGL should not try to start the rendering. + * + * @return bool @c true if the creation of the Backend failed, @c false 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 otherwise + **/ + bool syncsToVBlank() const { + return m_syncsToVBlank; + } + /** + * @brief Whether VSync blocks execution until the screen is in the retrace + * + * 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 indirect + **/ + 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 extension. + **/ + bool hasExtension(const QByteArray &extension) const { + return m_extensions.contains(extension); + } + + /** + * Copy a region of pixels from the current read to the current draw buffer + */ + void copyPixels(const QRegion ®ion); + +protected: + /** + * @brief Backend specific flushing of frame to screen. + **/ + virtual void present() = 0; + /** + * @brief Sets the backend initialization to failed. + * + * This method should be called by the concrete subclass in case the initialization 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 whether 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 otherwise. + **/ + void setSyncsToVBlank(bool enabled) { + m_syncsToVBlank = 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 = enabled; + } + /** + * @brief Sets whether the OpenGL context is direct. + * + * Should be called by the concrete subclass once it is determined whether 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 = direct; + } + + void setSupportsBufferAge(bool value) { + m_haveBufferAge = value; + } + + /** + * @return const QRegion& Damage of previously rendered frame + **/ + const QRegion &lastDamage() const { + return m_lastDamage; + } + void setLastDamage(const QRegion &damage) { + m_lastDamage = 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 = set; + } + + /** + * Sets the platform-specific @p extensions. + * + * These are the EGL/GLX extensions, not the OpenGL extensions + **/ + void setExtensions(const QList &extensions) { + m_extensions = 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 vertical 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_buffer_age. + */ + bool m_haveBufferAge; + /** + * @brief Whether the initialization failed, of course default to @c false. + **/ + 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 = false; + + QList m_extensions; +}; + +} + +#endif diff --git a/platformsupport/scenes/opengl/backend.cpp b/platformsupport/scenes/opengl/backend.cpp new file mode 100644 --- /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äßlin + +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 = 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 <= m_damageHistory.count()) { + for (int i = 0; i < bufferAge - 1; i++) + region |= m_damageHistory[i]; + } else { + const QSize &s = screens()->size(); + region = 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 = screens()->size().height(); + foreach (const QRect &r, region.rects()) { + const int x0 = r.x(); + const int y0 = height - r.y() - r.height(); + const int x1 = r.x() + r.width(); + const int y1 = height - r.y(); + + glBlitFramebuffer(x0, y0, x1, y1, x0, y0, x1, y1, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } +} + +} diff --git a/platformsupport/scenes/opengl/swap_profiler.h b/platformsupport/scenes/opengl/swap_profiler.h new file mode 100644 --- /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äßlin + +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 non-blocking) buffering and + * 0 (NOT '0') otherwise, so you can act on "if (char result = SwapProfiler::end()) { fooBar(); } + **/ + char end(); +private: + QElapsedTimer m_timer; + qint64 m_time; + int m_counter; +}; + +} + +#endif diff --git a/platformsupport/scenes/opengl/swap_profiler.cpp b/platformsupport/scenes/opengl/swap_profiler.cpp new file mode 100644 --- /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äßlin + +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 = 2 * 1000*1000; // we start with a long time mean of 2ms ... + m_counter = 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 = (10*m_time + m_timer.nsecsElapsed())/11; + if (++m_counter > 500) { + const bool blocks = m_time > 1000 * 1000; // 1ms, i get ~250µs and ~7ms w/o triple buffering... + qCDebug(KWIN_OPENGL) << "Triple buffering detection:" << QString(blocks ? 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/texture.h b/platformsupport/scenes/opengl/texture.h new file mode 100644 --- /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äßlin + +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 = (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) = 0; + virtual void updateTexture(WindowPixmap *pixmap); + virtual OpenGLBackend *backend() = 0; + +protected: + SceneOpenGLTexturePrivate(); + +private: + Q_DISABLE_COPY(SceneOpenGLTexturePrivate) +}; + +} + +#endif diff --git a/platformsupport/scenes/opengl/texture.cpp b/platformsupport/scenes/opengl/texture.cpp new file mode 100644 --- /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äßlin + +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 = (const SceneOpenGLTexture& tex) +{ + d_ptr = tex.d_ptr; + return *this; +} + +void SceneOpenGLTexture::discard() +{ + d_ptr = 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 = d_func()->backend()->createBackendTexture(this); //new TexturePrivate(); + + 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/plugins/platforms/drm/CMakeLists.txt b/plugins/platforms/drm/CMakeLists.txt --- a/plugins/platforms/drm/CMakeLists.txt +++ b/plugins/platforms/drm/CMakeLists.txt @@ -16,8 +16,10 @@ 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 SceneQPainterBackend) +target_link_libraries(KWinWaylandDrmBackend kwin Libdrm::Libdrm SceneQPainterBackend SceneOpenGLBackend) if(HAVE_GBM) target_link_libraries(KWinWaylandDrmBackend gbm::gbm) diff --git a/plugins/platforms/drm/egl_gbm_backend.h b/plugins/platforms/drm/egl_gbm_backend.h --- a/plugins/platforms/drm/egl_gbm_backend.h +++ b/plugins/platforms/drm/egl_gbm_backend.h @@ -20,7 +20,6 @@ #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 @@ EglGbmBackend(DrmBackend *b); virtual ~EglGbmBackend(); void screenGeometryChanged(const QSize &size) override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; void endRenderingFrameForScreen(int screenId, const QRegion &damage, const QRegion &damagedRegion) override; @@ -87,7 +86,7 @@ private: friend class EglGbmBackend; - EglGbmTexture(SceneOpenGL::Texture *texture, EglGbmBackend *backend); + EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend); }; } // namespace diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -253,7 +253,7 @@ // TODO, create new buffer? } -SceneOpenGL::TexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new EglGbmTexture(texture, this); } @@ -343,7 +343,7 @@ * EglTexture ************************************************/ -EglGbmTexture::EglGbmTexture(KWin::SceneOpenGL::Texture *texture, EglGbmBackend *backend) +EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/hwcomposer/CMakeLists.txt b/plugins/platforms/hwcomposer/CMakeLists.txt --- a/plugins/platforms/hwcomposer/CMakeLists.txt +++ b/plugins/platforms/hwcomposer/CMakeLists.txt @@ -5,12 +5,14 @@ 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.h b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h --- a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h +++ b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.h @@ -33,7 +33,7 @@ EglHwcomposerBackend(HwcomposerBackend *backend); virtual ~EglHwcomposerBackend(); bool usesOverlayWindow() const override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; void screenGeometryChanged(const QSize &size) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; @@ -58,7 +58,7 @@ private: friend class EglHwcomposerBackend; - EglHwcomposerTexture(SceneOpenGL::Texture *texture, EglHwcomposerBackend *backend); + EglHwcomposerTexture(SceneOpenGLTexture *texture, EglHwcomposerBackend *backend); }; } diff --git a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp --- a/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp +++ b/plugins/platforms/hwcomposer/egl_hwcomposer_backend.cpp @@ -164,7 +164,7 @@ setLastDamage(renderedRegion); } -SceneOpenGL::TexturePrivate *EglHwcomposerBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglHwcomposerBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new EglHwcomposerTexture(texture, this); } @@ -174,7 +174,7 @@ return false; } -EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGL::Texture *texture, EglHwcomposerBackend *backend) +EglHwcomposerTexture::EglHwcomposerTexture(SceneOpenGLTexture *texture, EglHwcomposerBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/virtual/CMakeLists.txt b/plugins/platforms/virtual/CMakeLists.txt --- a/plugins/platforms/virtual/CMakeLists.txt +++ b/plugins/platforms/virtual/CMakeLists.txt @@ -5,14 +5,15 @@ screens_virtual.cpp ) +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) include(ECMQtDeclareLoggingCategory) ecm_qt_declare_logging_category(VIRTUAL_SOURCES HEADER logging.h IDENTIFIER KWIN_VIRTUAL CATEGORY_NAME kwin_platform_virtual DEFAULT_SEVERITY Critical) add_library(KWinWaylandVirtualBackend MODULE ${VIRTUAL_SOURCES}) 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.h b/plugins/platforms/virtual/egl_gbm_backend.h --- a/plugins/platforms/virtual/egl_gbm_backend.h +++ b/plugins/platforms/virtual/egl_gbm_backend.h @@ -20,7 +20,6 @@ #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 @@ EglGbmBackend(VirtualBackend *b); virtual ~EglGbmBackend(); void screenGeometryChanged(const QSize &size) override; - SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) override; + SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; QRegion prepareRenderingFrame() override; void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; bool usesOverlayWindow() const override; @@ -68,7 +67,7 @@ private: friend class EglGbmBackend; - EglGbmTexture(SceneOpenGL::Texture *texture, EglGbmBackend *backend); + EglGbmTexture(SceneOpenGLTexture *texture, EglGbmBackend *backend); }; } // namespace diff --git a/plugins/platforms/virtual/egl_gbm_backend.cpp b/plugins/platforms/virtual/egl_gbm_backend.cpp --- a/plugins/platforms/virtual/egl_gbm_backend.cpp +++ b/plugins/platforms/virtual/egl_gbm_backend.cpp @@ -29,6 +29,7 @@ #include // kwin libs #include +#include // Qt #include // system @@ -214,7 +215,7 @@ // TODO, create new buffer? } -SceneOpenGL::TexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglGbmBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new EglGbmTexture(texture, this); } @@ -282,7 +283,7 @@ * EglTexture ************************************************/ -EglGbmTexture::EglGbmTexture(KWin::SceneOpenGL::Texture *texture, EglGbmBackend *backend) +EglGbmTexture::EglGbmTexture(KWin::SceneOpenGLTexture *texture, EglGbmBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/virtual/virtual_backend.cpp b/plugins/platforms/virtual/virtual_backend.cpp --- a/plugins/platforms/virtual/virtual_backend.cpp +++ b/plugins/platforms/virtual/virtual_backend.cpp @@ -29,6 +29,7 @@ // system #include #include +#include #if HAVE_GBM #include #endif diff --git a/plugins/platforms/wayland/CMakeLists.txt b/plugins/platforms/wayland/CMakeLists.txt --- a/plugins/platforms/wayland/CMakeLists.txt +++ b/plugins/platforms/wayland/CMakeLists.txt @@ -8,11 +8,12 @@ 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 SceneQPainterBackend) if(HAVE_WAYLAND_EGL) - target_link_libraries(KWinWaylandWaylandBackend Wayland::Egl) + target_link_libraries(KWinWaylandWaylandBackend SceneOpenGLBackend Wayland::Egl) endif() install( diff --git a/plugins/platforms/wayland/egl_wayland_backend.h b/plugins/platforms/wayland/egl_wayland_backend.h --- a/plugins/platforms/wayland/egl_wayland_backend.h +++ b/plugins/platforms/wayland/egl_wayland_backend.h @@ -20,7 +20,6 @@ #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 @@ EglWaylandBackend(Wayland::WaylandBackend *b); virtual ~EglWaylandBackend(); virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture); + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion); virtual bool usesOverlayWindow() const override; @@ -88,7 +87,7 @@ private: friend class EglWaylandBackend; - EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend); + EglWaylandTexture(SceneOpenGLTexture *texture, EglWaylandBackend *backend); }; } // namespace diff --git a/plugins/platforms/wayland/egl_wayland_backend.cpp b/plugins/platforms/wayland/egl_wayland_backend.cpp --- a/plugins/platforms/wayland/egl_wayland_backend.cpp +++ b/plugins/platforms/wayland/egl_wayland_backend.cpp @@ -213,7 +213,7 @@ m_bufferAge = 0; } -SceneOpenGL::TexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglWaylandBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new EglWaylandTexture(texture, this); } @@ -280,7 +280,7 @@ * EglTexture ************************************************/ -EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglWaylandBackend *backend) +EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGLTexture *texture, KWin::EglWaylandBackend *backend) : AbstractEglTexture(texture, backend) { } diff --git a/plugins/platforms/x11/common/CMakeLists.txt b/plugins/platforms/x11/common/CMakeLists.txt --- a/plugins/platforms/x11/common/CMakeLists.txt +++ b/plugins/platforms/x11/common/CMakeLists.txt @@ -4,5 +4,6 @@ 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.h b/plugins/platforms/x11/common/eglonxbackend.h --- a/plugins/platforms/x11/common/eglonxbackend.h +++ b/plugins/platforms/x11/common/eglonxbackend.h @@ -20,7 +20,9 @@ #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 @@ 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(SceneOpenGLTexture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion); virtual OverlayWindow* overlayWindow() override; @@ -80,6 +82,7 @@ xcb_window_t m_renderingWindow = XCB_WINDOW_NONE; bool m_havePlatformBase = false; bool m_x11TextureFromPixmapSupported = true; + SwapProfiler m_swapProfiler; friend class EglTexture; }; @@ -96,7 +99,7 @@ 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/common/eglonxbackend.cpp b/plugins/platforms/x11/common/eglonxbackend.cpp --- a/plugins/platforms/x11/common/eglonxbackend.cpp +++ b/plugins/platforms/x11/common/eglonxbackend.cpp @@ -23,11 +23,15 @@ #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 @@ m_bufferAge = 0; } -SceneOpenGL::TexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *EglOnXBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new EglTexture(texture, this); } @@ -473,7 +477,7 @@ * EglTexture ************************************************/ -EglTexture::EglTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglOnXBackend *backend) +EglTexture::EglTexture(KWin::SceneOpenGLTexture *texture, KWin::EglOnXBackend *backend) : AbstractEglTexture(texture, backend) , m_backend(backend) { diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/platforms/x11/standalone/CMakeLists.txt --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -20,8 +20,10 @@ set(X11PLATFORM_SOURCES ${X11PLATFORM_SOURCES} glxbackend.cpp glx_context_attribute_builder.cpp) endif() +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) + add_library(KWinX11Platform MODULE ${X11PLATFORM_SOURCES}) -target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils Qt5::X11Extras XCB::CURSOR) +target_link_libraries(KWinX11Platform eglx11common kwin kwinxrenderutils 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.h b/plugins/platforms/x11/standalone/glxbackend.h --- a/plugins/platforms/x11/standalone/glxbackend.h +++ b/plugins/platforms/x11/standalone/glxbackend.h @@ -19,11 +19,14 @@ *********************************************************************/ #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 @@ GlxBackend(Display *display); virtual ~GlxBackend(); virtual void screenGeometryChanged(const QSize &size); - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture); + virtual SceneOpenGLTexturePrivate *createBackendTexture(SceneOpenGLTexture *texture) override; virtual QRegion prepareRenderingFrame(); virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion); virtual bool makeCurrent() override; @@ -116,13 +119,14 @@ bool haveSwapInterval = false; bool haveWaitSync = 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 @@ 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 visual); 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/standalone/glxbackend.cpp b/plugins/platforms/x11/standalone/glxbackend.cpp --- a/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/plugins/platforms/x11/standalone/glxbackend.cpp @@ -31,10 +31,13 @@ #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 @@ #if HAVE_DL_LIBRARY #include #endif +#include #ifndef XCB_GLX_BUFFER_SWAP_COMPLETE #define XCB_GLX_BUFFER_SWAP_COMPLETE 1 @@ -722,7 +726,7 @@ } } else { // Copy Pixels (horribly slow on Mesa) glDrawBuffer(GL_FRONT); - SceneOpenGL::copyPixels(lastDamage()); + copyPixels(lastDamage()); glDrawBuffer(GL_BACK); } @@ -748,7 +752,7 @@ m_bufferAge = 0; } -SceneOpenGL::TexturePrivate *GlxBackend::createBackendTexture(SceneOpenGL::Texture *texture) +SceneOpenGLTexturePrivate *GlxBackend::createBackendTexture(SceneOpenGLTexture *texture) { return new GlxTexture(texture, this); } @@ -844,8 +848,8 @@ /******************************************************** * 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/windowed/CMakeLists.txt b/plugins/platforms/x11/windowed/CMakeLists.txt --- a/plugins/platforms/x11/windowed/CMakeLists.txt +++ b/plugins/platforms/x11/windowed/CMakeLists.txt @@ -5,8 +5,9 @@ x11windowed_backend.cpp ) +include_directories(${CMAKE_SOURCE_DIR}/platformsupport/scenes/opengl) add_library(KWinWaylandX11Backend MODULE ${X11BACKEND_SOURCES}) -target_link_libraries(KWinWaylandX11Backend eglx11common kwin kwinxrenderutils X11::XCB SceneQPainterBackend) +target_link_libraries(KWinWaylandX11Backend eglx11common kwin kwinxrenderutils X11::XCB SceneQPainterBackend SceneOpenGLBackend) install( TARGETS diff --git a/plugins/platforms/x11/windowed/x11windowed_backend.cpp b/plugins/platforms/x11/windowed/x11windowed_backend.cpp --- a/plugins/platforms/x11/windowed/x11windowed_backend.cpp +++ b/plugins/platforms/x11/windowed/x11windowed_backend.cpp @@ -27,8 +27,10 @@ #include // KDE #include +#include #include #include +#include #include // kwayland #include diff --git a/plugins/scenes/CMakeLists.txt b/plugins/scenes/CMakeLists.txt --- 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/CMakeLists.txt new file mode 100644 --- /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/opengl.json new file mode 100644 --- /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/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h new file mode 100644 --- /dev/null +++ b/plugins/scenes/opengl/scene_opengl.h @@ -0,0 +1,354 @@ +/******************************************************************** + 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äßlin + +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::DecoratedClientImpl *impl) override; + virtual void triggerFence() override; + virtual QMatrix4x4 projectionMatrix() const = 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 = 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) = 0; + virtual void updateProjectionMatrix() = 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 = nullptr); + virtual ~SceneOpenGL2(); + virtual CompositingType compositingType() const { + return OpenGL2Compositing; + } + + static bool supported(OpenGLBackend *backend); + + QMatrix4x4 projectionMatrix() const override { return m_projectionMatrix; } + QMatrix4x4 screenProjectionMatrix() const override { return m_screenProjectionMatrix; } + +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 region, WindowPaintData& data); + virtual void updateProjectionMatrix() override; + void paintCursor() override; + +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, WindowPaintData &data); + virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0; + void endRenderWindow(); + bool bindTexture(); + void setScene(SceneOpenGL *scene) { + m_scene = 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 = 0, DecorationLeaf, ContentLeaf, PreviousContentLeaf, 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, const WindowPaintData &data); + virtual void performPaint(int mask, QRegion region, WindowPaintData data); + +private: + /** + * Whether prepareStates enabled blending and restore states should disable 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 frameOpacity); + + 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 texture +}; + +/** + * @short OpenGL implementation of Shadow. + * + * This class extends Shadow by the Elements required for OpenGL rendering. + * @author Martin Gräßlin + **/ +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 = nullptr); + ~OpenGLFactory() override; + + Scene *create(QObject *parent = nullptr) const override; +}; + +} // namespace + +#endif diff --git a/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp rename from scene_opengl.cpp rename to plugins/scenes/opengl/scene_opengl.cpp --- a/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -30,6 +30,7 @@ #include "platform.h" #include "wayland_server.h" +#include "platformsupport/scenes/opengl/texture.h" #include @@ -44,6 +45,7 @@ #include "screens.h" #include "cursor.h" #include "decorations/decoratedclient.h" +#include #include #include @@ -180,18 +182,18 @@ glGetSynciv(m_sync, GL_SYNC_STATUS, 1, nullptr, &value); if (value != 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 = 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 @@ // ----------------------------------------------------------------------- - - -//**************************************** -// 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: " << reason; - m_failed = 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 <= m_damageHistory.count()) { - for (int i = 0; i < bufferAge - 1; i++) - region |= m_damageHistory[i]; - } else { - const QSize &s = screens()->size(); - region = 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 @@ GLPlatform *glPlatform = 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_ARB_texture_rectangle missing"; + qCCritical(KWIN_OPENGL) << "GL_ARB_texture_non_power_of_two and GL_ARB_texture_rectangle missing"; init_ok = false; return; // error } if (glPlatform->isMesaDriver() && glPlatform->mesaVersion() < kVersionNumber(10, 0)) { - qCCritical(KWIN_CORE) << "KWin requires at least Mesa 10.0 for OpenGL compositing."; + qCCritical(KWIN_OPENGL) << "KWin requires at least Mesa 10.0 for OpenGL compositing."; init_ok = false; return; } @@ -432,10 +355,10 @@ const QByteArray useExplicitSync = qgetenv("KWIN_EXPLICIT_SYNC"); if (useExplicitSync != "0") { - qCDebug(KWIN_CORE) << "Initializing fences for synchronization with the X command stream"; + qCDebug(KWIN_OPENGL) << "Initializing fences for synchronization with the X command stream"; m_syncManager = new SyncManager; } else { - qCDebug(KWIN_CORE) << "Explicit synchronization with the X command stream disabled by environment variable"; + qCDebug(KWIN_OPENGL) << "Explicit synchronization with the X command stream disabled by environment variable"; } } } @@ -514,7 +437,7 @@ 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 @@ 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 @@ } if (!scene) { if (GLPlatform::instance()->recommendedCompositor() == XRenderCompositing) { - qCCritical(KWIN_CORE) << "OpenGL driver recommends XRender based compositing. Falling back to XRender."; - qCCritical(KWIN_CORE) << "To overwrite the detection use the environment variable KWIN_COMPOSE"; - qCCritical(KWIN_CORE) << "For more information see http://community.kde.org/KWin/Environment_Variables#KWIN_COMPOSE"; + qCCritical(KWIN_OPENGL) << "OpenGL driver recommends XRender based 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://community.kde.org/KWin/Environment_Variables#KWIN_COMPOSE"; QTimer::singleShot(0, Compositor::self(), SLOT(fallbackToXRenderCompositing())); } delete backend; @@ -621,32 +544,19 @@ return !init_ok; } -void SceneOpenGL::copyPixels(const QRegion ®ion) -{ - const int height = screens()->size().height(); - foreach (const QRect &r, region.rects()) { - const int x0 = r.x(); - const int y0 = height - r.y() - r.height(); - const int x1 = r.x() + r.width(); - const int y1 = 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 current GL context occurred."; + qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the current GL context occurred."; break; case GL_INNOCENT_CONTEXT_RESET: - qCDebug(KWIN_CORE) << "A graphics reset not attributable to the current 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 occurred."; + qCDebug(KWIN_OPENGL) << "A graphics reset of an unknown cause occurred."; break; default: @@ -660,7 +570,7 @@ while (timer.elapsed() < 10000 && glGetGraphicsResetStatus() != GL_NO_ERROR) usleep(50); - qCDebug(KWIN_CORE) << "Attempting to reset compositing."; + qCDebug(KWIN_OPENGL) << "Attempting to reset compositing."; QMetaObject::invokeMethod(this, "resetCompositing", Qt::QueuedConnection); KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); @@ -800,7 +710,7 @@ options->glPreferBufferSwap() == Options::CopyFrontBuffer && validRegion != displayRegion) { glReadBuffer(GL_FRONT); - copyPixels(displayRegion - validRegion); + m_backend->copyPixels(displayRegion - validRegion); glReadBuffer(GL_BACK); validRegion = displayRegion; } @@ -815,8 +725,8 @@ 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 unsynchronized."; + qCDebug(KWIN_OPENGL) << "Aborting explicit synchronization with the X command stream."; + qCDebug(KWIN_OPENGL) << "Future frames will be rendered unsynchronized."; delete m_syncManager; m_syncManager = nullptr; } @@ -902,9 +812,9 @@ } } -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 @@ const QByteArray forceEnv = qgetenv("KWIN_COMPOSE"); if (!forceEnv.isEmpty()) { if (qstrcmp(forceEnv, "O2") == 0 || qstrcmp(forceEnv, "O2ES") == 0) { - qCDebug(KWIN_CORE) << "OpenGL 2 compositing enforced by environment variable"; + qCDebug(KWIN_OPENGL) << "OpenGL 2 compositing enforced by environment variable"; return true; } else { // OpenGL 2 disabled by environment variable @@ -1045,7 +955,7 @@ return false; } if (GLPlatform::instance()->recommendedCompositor() < OpenGL2Compositing) { - qCDebug(KWIN_CORE) << "Driver does not recommend OpenGL 2 compositing"; + qCDebug(KWIN_OPENGL) << "Driver does not recommend OpenGL 2 compositing"; return false; } return true; @@ -1062,7 +972,7 @@ // 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 = false; return; } @@ -1074,7 +984,7 @@ // 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 = false; return; // error } @@ -1086,12 +996,12 @@ } if (!ShaderManager::instance()->selfTest()) { - qCCritical(KWIN_CORE) << "ShaderManager self test failed"; + qCCritical(KWIN_OPENGL) << "ShaderManager self test failed"; init_ok = false; return; } - qCDebug(KWIN_CORE) << "OpenGL 2 compositing successfully initialized"; + qCDebug(KWIN_OPENGL) << "OpenGL 2 compositing successfully initialized"; init_ok = true; } @@ -1198,65 +1108,6 @@ w->sceneWindow()->performPaint(mask, region, data); } -//**************************************** -// SceneOpenGL::Texture -//**************************************** - -SceneOpenGL::Texture::Texture(OpenGLBackend *backend) - : GLTexture(*backend->createBackendTexture(this)) -{ -} - -SceneOpenGL::Texture::~Texture() -{ -} - -SceneOpenGL::Texture& SceneOpenGL::Texture::operator = (const SceneOpenGL::Texture& tex) -{ - d_ptr = tex.d_ptr; - return *this; -} - -void SceneOpenGL::Texture::discard() -{ - d_ptr = 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 = d_func()->backend()->createBackendTexture(this); //new TexturePrivate(); - - 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 //**************************************** @@ -1271,7 +1122,7 @@ { } -static SceneOpenGL::Texture *s_frameTexture = NULL; +static SceneOpenGLTexture *s_frameTexture = NULL; // Bind the window pixmap to an OpenGL texture. bool SceneOpenGL::Window::bindTexture() { @@ -1748,7 +1599,7 @@ toplevel()->resetDamage(); } } else - qCDebug(KWIN_CORE) << "Failed to bind window"; + qCDebug(KWIN_OPENGL) << "Failed to bind window"; return success; } @@ -2473,36 +2324,6 @@ return true; } -SwapProfiler::SwapProfiler() -{ - init(); -} - -void SwapProfiler::init() -{ - m_time = 2 * 1000*1000; // we start with a long time mean of 2ms ... - m_counter = 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 = (10*m_time + m_timer.nsecsElapsed())/11; - if (++m_counter > 500) { - const bool blocks = m_time > 1000 * 1000; // 1ms, i get ~250µs and ~7ms w/o triple buffering... - qCDebug(KWIN_CORE) << "Triple buffering detection:" << QString(blocks ? QStringLiteral("NOT available") : QStringLiteral("Available")) << - " - Mean block time:" << m_time/(1000.0*1000.0) << "ms"; - return blocks ? 'd' : 't'; - } - return 0; -} - SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client) : Renderer(client) , m_texture() @@ -2610,4 +2431,31 @@ Renderer::reparent(deleted); } + +OpenGLFactory::OpenGLFactory(QObject *parent) + : SceneFactory(parent) +{ +} + +OpenGLFactory::~OpenGLFactory() = 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 library is unsafe to use"; + return nullptr; + } + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreInit); + auto s = SceneOpenGL::createScene(parent); + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); + if (s && s->initFailed()) { + delete s; + return nullptr; + } + return s; +} + } // namespace diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -186,6 +186,7 @@ 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 --- a/scene_opengl.h +++ /dev/null @@ -1,694 +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äßlin - -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::DecoratedClientImpl *impl) override; - virtual void triggerFence() override; - virtual QMatrix4x4 projectionMatrix() const = 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 buffer - */ - static void copyPixels(const QRegion ®ion); - - static SceneOpenGL *createScene(QObject *parent); - -protected: - SceneOpenGL(OpenGLBackend *backend, QObject *parent = 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) = 0; - virtual void updateProjectionMatrix() = 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 = nullptr); - virtual ~SceneOpenGL2(); - virtual CompositingType compositingType() const { - return OpenGL2Compositing; - } - - static bool supported(OpenGLBackend *backend); - - QMatrix4x4 projectionMatrix() const override { return m_projectionMatrix; } - QMatrix4x4 screenProjectionMatrix() const override { return m_screenProjectionMatrix; } - -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 region, WindowPaintData& data); - virtual void updateProjectionMatrix() override; - void paintCursor() override; - -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) = 0; - virtual void updateTexture(WindowPixmap *pixmap); - virtual OpenGLBackend *backend() = 0; - -protected: - TexturePrivate(); - -private: - Q_DISABLE_COPY(TexturePrivate) -}; - -class SceneOpenGL::Texture - : public GLTexture -{ -public: - Texture(OpenGLBackend *backend); - virtual ~Texture(); - - Texture & operator = (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, WindowPaintData &data); - virtual void performPaint(int mask, QRegion region, WindowPaintData data) = 0; - void endRenderWindow(); - bool bindTexture(); - void setScene(SceneOpenGL *scene) { - m_scene = 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 = 0, DecorationLeaf, ContentLeaf, PreviousContentLeaf, 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, const WindowPaintData &data); - virtual void performPaint(int mask, QRegion region, WindowPaintData data); - -private: - /** - * Whether prepareStates enabled blending and restore states should disable 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 frameOpacity); - - 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 texture -}; - -/** - * @short OpenGL implementation of Shadow. - * - * This class extends Shadow by the Elements required for OpenGL rendering. - * @author Martin Gräßlin - **/ -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 non-blocking) buffering and - * 0 (NOT '0') otherwise, so you can act on "if (char result = SwapProfiler::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 responsible 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äßlin - **/ -class KWIN_EXPORT OpenGLBackend -{ -public: - OpenGLBackend(); - virtual ~OpenGLBackend(); - - virtual void init() = 0; - /** - * @return Time passes since start of rendering current frame. - * @see startRenderTimer - **/ - qint64 renderTime() { - return m_renderTimer.nsecsElapsed(); - } - virtual void screenGeometryChanged(const QSize &size) = 0; - virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture) = 0; - - /** - * @brief Backend specific code to prepare the rendering of a frame including flushing the - * previously rendered frame to the screen if the backend works this way. - * - * @return A region that if not empty will be repainted in addition to the damaged region - **/ - virtual QRegion prepareRenderingFrame() = 0; - - /** - * @brief Backend specific code to handle the end of rendering a frame. - * - * @param renderedRegion The possibly larger region that has been rendered - * @param damagedRegion The damaged region that should be posted - **/ - virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion) = 0; - virtual void endRenderingFrameForScreen(int screenId, const QRegion &damage, const QRegion &damagedRegion); - virtual bool makeCurrent() = 0; - virtual void doneCurrent() = 0; - virtual bool usesOverlayWindow() const = 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 paints. - **/ - 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 correctly. If this method - * returns @c true, the SceneOpenGL should not try to start the rendering. - * - * @return bool @c true if the creation of the Backend failed, @c false 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 otherwise - **/ - bool syncsToVBlank() const { - return m_syncsToVBlank; - } - /** - * @brief Whether VSync blocks execution until the screen is in the retrace - * - * 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 indirect - **/ - 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 extension. - **/ - bool hasExtension(const QByteArray &extension) const { - return m_extensions.contains(extension); - } - -protected: - /** - * @brief Backend specific flushing of frame to screen. - **/ - virtual void present() = 0; - /** - * @brief Sets the backend initialization to failed. - * - * This method should be called by the concrete subclass in case the initialization 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 whether 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 otherwise. - **/ - void setSyncsToVBlank(bool enabled) { - m_syncsToVBlank = 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 = enabled; - } - /** - * @brief Sets whether the OpenGL context is direct. - * - * Should be called by the concrete subclass once it is determined whether 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 = direct; - } - - void setSupportsBufferAge(bool value) { - m_haveBufferAge = value; - } - - /** - * @return const QRegion& Damage of previously rendered frame - **/ - const QRegion &lastDamage() const { - return m_lastDamage; - } - void setLastDamage(const QRegion &damage) { - m_lastDamage = 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 = set; - } - - /** - * Sets the platform-specific @p extensions. - * - * These are the EGL/GLX extensions, not the OpenGL extensions - **/ - void setExtensions(const QList &extensions) { - m_extensions = 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 vertical 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_buffer_age. - */ - bool m_haveBufferAge; - /** - * @brief Whether the initialization failed, of course default to @c false. - **/ - 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 = 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