From 0e906ec182875f47afa54a3b2ab4485237fe23b9 Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 17 Jan 2023 20:22:28 +0200 Subject: [PATCH] scene: Decouple scene bits from Shadow class Currently the Shadow class is scene specific, which adds coupling between Window and scene bits. This change introduces ShadowTextureProvider that contains scene specific stuff so the Shadow acts like a data source and is not coupled to concrete scene. --- src/scene/itemrenderer_opengl.cpp | 4 +- src/scene/shadowitem.cpp | 26 ++++++++ src/scene/shadowitem.h | 18 +++++ src/scene/workspacescene.h | 12 +--- src/scene/workspacescene_opengl.cpp | 94 +++++++++++++-------------- src/scene/workspacescene_opengl.h | 14 ++-- src/scene/workspacescene_qpainter.cpp | 21 +++--- src/scene/workspacescene_qpainter.h | 12 ++-- src/shadow.cpp | 23 ++----- src/shadow.h | 17 ++--- 10 files changed, 122 insertions(+), 119 deletions(-) diff --git a/src/scene/itemrenderer_opengl.cpp b/src/scene/itemrenderer_opengl.cpp index 3f8463efa1..7d48824dd9 100644 --- a/src/scene/itemrenderer_opengl.cpp +++ b/src/scene/itemrenderer_opengl.cpp @@ -159,9 +159,9 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) if (auto shadowItem = qobject_cast(item)) { if (!geometry.isEmpty()) { - SceneOpenGLShadow *shadow = static_cast(shadowItem->shadow()); + OpenGLShadowTextureProvider *textureProvider = static_cast(shadowItem->textureProvider()); context->renderNodes.append(RenderNode{ - .texture = shadow->shadowTexture(), + .texture = textureProvider->shadowTexture(), .geometry = geometry, .transformMatrix = context->transformStack.top(), .opacity = context->opacityStack.top(), diff --git a/src/scene/shadowitem.cpp b/src/scene/shadowitem.cpp index 28dbf213df..8e25d8c0c1 100644 --- a/src/scene/shadowitem.cpp +++ b/src/scene/shadowitem.cpp @@ -5,16 +5,28 @@ */ #include "scene/shadowitem.h" +#include "composite.h" #include "deleted.h" +#include "scene/workspacescene.h" #include "shadow.h" namespace KWin { +ShadowTextureProvider::ShadowTextureProvider(Shadow *shadow) + : m_shadow(shadow) +{ +} + +ShadowTextureProvider::~ShadowTextureProvider() +{ +} + ShadowItem::ShadowItem(Shadow *shadow, Window *window, Scene *scene, Item *parent) : Item(scene, parent) , m_window(window) , m_shadow(shadow) + , m_textureProvider(Compositor::self()->scene()->createShadowTextureProvider(shadow)) { connect(window, &Window::windowClosed, this, &ShadowItem::handleWindowClosed); @@ -35,6 +47,11 @@ Shadow *ShadowItem::shadow() const return m_shadow; } +ShadowTextureProvider *ShadowItem::textureProvider() const +{ + return m_textureProvider.get(); +} + void ShadowItem::updateGeometry() { const QRectF rect = m_shadow->rect() + m_shadow->offset(); @@ -48,6 +65,7 @@ void ShadowItem::handleTextureChanged() { scheduleRepaint(rect()); discardQuads(); + m_textureDirty = true; } void ShadowItem::handleWindowClosed(Window *original, Deleted *deleted) @@ -287,4 +305,12 @@ WindowQuadList ShadowItem::buildQuads() const return quads; } +void ShadowItem::preprocess() +{ + if (m_textureDirty) { + m_textureDirty = false; + m_textureProvider->update(); + } +} + } // namespace KWin diff --git a/src/scene/shadowitem.h b/src/scene/shadowitem.h index 45eca20d99..575cfc7f3a 100644 --- a/src/scene/shadowitem.h +++ b/src/scene/shadowitem.h @@ -15,6 +15,20 @@ class Deleted; class Shadow; class Window; +class KWIN_EXPORT ShadowTextureProvider +{ +public: + explicit ShadowTextureProvider(Shadow *shadow); + virtual ~ShadowTextureProvider(); + + Shadow *shadow() const { return m_shadow; } + + virtual void update() = 0; + +protected: + Shadow *m_shadow; +}; + /** * The ShadowItem class represents a nine-tile patch server-side drop-shadow. */ @@ -27,9 +41,11 @@ public: ~ShadowItem() override; Shadow *shadow() const; + ShadowTextureProvider *textureProvider() const; protected: WindowQuadList buildQuads() const override; + void preprocess() override; private Q_SLOTS: void handleTextureChanged(); @@ -39,6 +55,8 @@ private Q_SLOTS: private: Window *m_window; Shadow *m_shadow = nullptr; + std::unique_ptr m_textureProvider; + bool m_textureDirty = true; }; } // namespace KWin diff --git a/src/scene/workspacescene.h b/src/scene/workspacescene.h index 9c8d9a24f9..89d99668c8 100644 --- a/src/scene/workspacescene.h +++ b/src/scene/workspacescene.h @@ -38,6 +38,7 @@ class RenderLoop; class WorkspaceScene; class Shadow; class ShadowItem; +class ShadowTextureProvider; class SurfaceItem; class WindowItem; @@ -57,21 +58,12 @@ public: void postPaint() override; void paint(RenderTarget *renderTarget, const QRegion ®ion) override; - /** - * @brief Creates the Scene specific Shadow subclass. - * - * An implementing class has to create a proper instance. It is not allowed to - * return @c null. - * - * @param window The Window for which the Shadow needs to be created. - */ - virtual std::unique_ptr createShadow(Window *window) = 0; - virtual bool makeOpenGLContextCurrent(); virtual void doneOpenGLContextCurrent(); virtual bool supportsNativeFence() const; virtual DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0; + virtual std::unique_ptr createShadowTextureProvider(Shadow *shadow) = 0; /** * Whether the Scene is able to drive animations. diff --git a/src/scene/workspacescene_opengl.cpp b/src/scene/workspacescene_opengl.cpp index ed45b6939b..3e0930bae4 100644 --- a/src/scene/workspacescene_opengl.cpp +++ b/src/scene/workspacescene_opengl.cpp @@ -19,6 +19,7 @@ #include "core/output.h" #include "decorations/decoratedclient.h" #include "scene/itemrenderer_opengl.h" +#include "shadow.h" #include "window.h" #include @@ -69,16 +70,16 @@ bool WorkspaceSceneOpenGL::supportsNativeFence() const return m_backend->supportsNativeFence(); } -std::unique_ptr WorkspaceSceneOpenGL::createShadow(Window *window) -{ - return std::make_unique(window); -} - DecorationRenderer *WorkspaceSceneOpenGL::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) { return new SceneOpenGLDecorationRenderer(impl); } +std::unique_ptr WorkspaceSceneOpenGL::createShadowTextureProvider(Shadow *shadow) +{ + return std::make_unique(shadow); +} + bool WorkspaceSceneOpenGL::animationsSupported() const { return !GLPlatform::instance()->isSoftwareEmulation(); @@ -99,15 +100,15 @@ public: DecorationShadowTextureCache(const DecorationShadowTextureCache &) = delete; static DecorationShadowTextureCache &instance(); - void unregister(SceneOpenGLShadow *shadow); - std::shared_ptr getTexture(SceneOpenGLShadow *shadow); + void unregister(ShadowTextureProvider *provider); + std::shared_ptr getTexture(ShadowTextureProvider *provider); private: DecorationShadowTextureCache() = default; struct Data { std::shared_ptr texture; - QVector shadows; + QVector providers; }; QHash m_cache; }; @@ -123,22 +124,22 @@ DecorationShadowTextureCache::~DecorationShadowTextureCache() Q_ASSERT(m_cache.isEmpty()); } -void DecorationShadowTextureCache::unregister(SceneOpenGLShadow *shadow) +void DecorationShadowTextureCache::unregister(ShadowTextureProvider *provider) { auto it = m_cache.begin(); while (it != m_cache.end()) { auto &d = it.value(); // check whether the Vector of Shadows contains our shadow and remove all of them - auto glIt = d.shadows.begin(); - while (glIt != d.shadows.end()) { - if (*glIt == shadow) { - glIt = d.shadows.erase(glIt); + auto glIt = d.providers.begin(); + while (glIt != d.providers.end()) { + if (*glIt == provider) { + glIt = d.providers.erase(glIt); } else { glIt++; } } // if there are no shadows any more we can erase the cache entry - if (d.shadows.isEmpty()) { + if (d.providers.isEmpty()) { it = m_cache.erase(it); } else { it++; @@ -146,31 +147,32 @@ void DecorationShadowTextureCache::unregister(SceneOpenGLShadow *shadow) } } -std::shared_ptr DecorationShadowTextureCache::getTexture(SceneOpenGLShadow *shadow) +std::shared_ptr DecorationShadowTextureCache::getTexture(ShadowTextureProvider *provider) { + Shadow *shadow = provider->shadow(); Q_ASSERT(shadow->hasDecorationShadow()); - unregister(shadow); + unregister(provider); const auto &decoShadow = shadow->decorationShadow().toStrongRef(); Q_ASSERT(!decoShadow.isNull()); auto it = m_cache.find(decoShadow.data()); if (it != m_cache.end()) { - Q_ASSERT(!it.value().shadows.contains(shadow)); - it.value().shadows << shadow; + Q_ASSERT(!it.value().providers.contains(provider)); + it.value().providers << provider; return it.value().texture; } Data d; - d.shadows << shadow; + d.providers << provider; d.texture = std::make_shared(shadow->decorationShadowImage()); m_cache.insert(decoShadow.data(), d); return d.texture; } -SceneOpenGLShadow::SceneOpenGLShadow(Window *window) - : Shadow(window) +OpenGLShadowTextureProvider::OpenGLShadowTextureProvider(Shadow *shadow) + : ShadowTextureProvider(shadow) { } -SceneOpenGLShadow::~SceneOpenGLShadow() +OpenGLShadowTextureProvider::~OpenGLShadowTextureProvider() { WorkspaceScene *scene = Compositor::self()->scene(); if (scene) { @@ -180,30 +182,28 @@ SceneOpenGLShadow::~SceneOpenGLShadow() } } -bool SceneOpenGLShadow::prepareBackend() +void OpenGLShadowTextureProvider::update() { - if (hasDecorationShadow()) { + if (m_shadow->hasDecorationShadow()) { // simplifies a lot by going directly to - WorkspaceScene *scene = Compositor::self()->scene(); - scene->makeOpenGLContextCurrent(); m_texture = DecorationShadowTextureCache::instance().getTexture(this); - - return true; + return; } - const QSize top(shadowElement(ShadowElementTop).size()); - const QSize topRight(shadowElement(ShadowElementTopRight).size()); - const QSize right(shadowElement(ShadowElementRight).size()); - const QSize bottom(shadowElement(ShadowElementBottom).size()); - const QSize bottomLeft(shadowElement(ShadowElementBottomLeft).size()); - const QSize left(shadowElement(ShadowElementLeft).size()); - const QSize topLeft(shadowElement(ShadowElementTopLeft).size()); - const QSize bottomRight(shadowElement(ShadowElementBottomRight).size()); + + const QSize top(m_shadow->shadowElement(Shadow::ShadowElementTop).size()); + const QSize topRight(m_shadow->shadowElement(Shadow::ShadowElementTopRight).size()); + const QSize right(m_shadow->shadowElement(Shadow::ShadowElementRight).size()); + const QSize bottom(m_shadow->shadowElement(Shadow::ShadowElementBottom).size()); + const QSize bottomLeft(m_shadow->shadowElement(Shadow::ShadowElementBottomLeft).size()); + const QSize left(m_shadow->shadowElement(Shadow::ShadowElementLeft).size()); + const QSize topLeft(m_shadow->shadowElement(Shadow::ShadowElementTopLeft).size()); + const QSize bottomRight(m_shadow->shadowElement(Shadow::ShadowElementBottomRight).size()); const int width = std::max({topLeft.width(), left.width(), bottomLeft.width()}) + std::max(top.width(), bottom.width()) + std::max({topRight.width(), right.width(), bottomRight.width()}); const int height = std::max({topLeft.height(), top.height(), topRight.height()}) + std::max(left.height(), right.height()) + std::max({bottomLeft.height(), bottom.height(), bottomRight.height()}); if (width == 0 || height == 0) { - return false; + return; } QImage image(width, height, QImage::Format_ARGB32); @@ -215,16 +215,16 @@ bool SceneOpenGLShadow::prepareBackend() QPainter p; p.begin(&image); - p.drawImage(QRectF(0, 0, topLeft.width(), topLeft.height()), shadowElement(ShadowElementTopLeft)); - p.drawImage(QRectF(innerRectLeft, 0, top.width(), top.height()), shadowElement(ShadowElementTop)); - p.drawImage(QRectF(width - topRight.width(), 0, topRight.width(), topRight.height()), shadowElement(ShadowElementTopRight)); + p.drawImage(QRectF(0, 0, topLeft.width(), topLeft.height()), m_shadow->shadowElement(Shadow::ShadowElementTopLeft)); + p.drawImage(QRectF(innerRectLeft, 0, top.width(), top.height()), m_shadow->shadowElement(Shadow::ShadowElementTop)); + p.drawImage(QRectF(width - topRight.width(), 0, topRight.width(), topRight.height()), m_shadow->shadowElement(Shadow::ShadowElementTopRight)); - p.drawImage(QRectF(0, innerRectTop, left.width(), left.height()), shadowElement(ShadowElementLeft)); - p.drawImage(QRectF(width - right.width(), innerRectTop, right.width(), right.height()), shadowElement(ShadowElementRight)); + p.drawImage(QRectF(0, innerRectTop, left.width(), left.height()), m_shadow->shadowElement(Shadow::ShadowElementLeft)); + p.drawImage(QRectF(width - right.width(), innerRectTop, right.width(), right.height()), m_shadow->shadowElement(Shadow::ShadowElementRight)); - p.drawImage(QRectF(0, height - bottomLeft.height(), bottomLeft.width(), bottomLeft.height()), shadowElement(ShadowElementBottomLeft)); - p.drawImage(QRectF(innerRectLeft, height - bottom.height(), bottom.width(), bottom.height()), shadowElement(ShadowElementBottom)); - p.drawImage(QRectF(width - bottomRight.width(), height - bottomRight.height(), bottomRight.width(), bottomRight.height()), shadowElement(ShadowElementBottomRight)); + p.drawImage(QRectF(0, height - bottomLeft.height(), bottomLeft.width(), bottomLeft.height()), m_shadow->shadowElement(Shadow::ShadowElementBottomLeft)); + p.drawImage(QRectF(innerRectLeft, height - bottom.height(), bottom.width(), bottom.height()), m_shadow->shadowElement(Shadow::ShadowElementBottom)); + p.drawImage(QRectF(width - bottomRight.width(), height - bottomRight.height(), bottomRight.width(), bottomRight.height()), m_shadow->shadowElement(Shadow::ShadowElementBottomRight)); p.end(); @@ -251,8 +251,6 @@ bool SceneOpenGLShadow::prepareBackend() } } - WorkspaceScene *scene = Compositor::self()->scene(); - scene->makeOpenGLContextCurrent(); m_texture = std::make_shared(image); if (m_texture->internalFormat() == GL_R8) { @@ -260,8 +258,6 @@ bool SceneOpenGLShadow::prepareBackend() m_texture->bind(); m_texture->setSwizzle(GL_ZERO, GL_ZERO, GL_ZERO, GL_RED); } - - return true; } SceneOpenGLDecorationRenderer::SceneOpenGLDecorationRenderer(Decoration::DecoratedClientImpl *client) diff --git a/src/scene/workspacescene_opengl.h b/src/scene/workspacescene_opengl.h index f7a20094ab..a47ed2cb29 100644 --- a/src/scene/workspacescene_opengl.h +++ b/src/scene/workspacescene_opengl.h @@ -13,8 +13,8 @@ #include "openglbackend.h" #include "scene/decorationitem.h" +#include "scene/shadowitem.h" #include "scene/workspacescene.h" -#include "shadow.h" #include "kwinglutils.h" @@ -30,11 +30,11 @@ public: explicit WorkspaceSceneOpenGL(OpenGLBackend *backend); ~WorkspaceSceneOpenGL() override; - std::unique_ptr createShadow(Window *window) override; bool makeOpenGLContextCurrent() override; void doneOpenGLContextCurrent() override; bool supportsNativeFence() const override; DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; + std::unique_ptr createShadowTextureProvider(Shadow *shadow) override; bool animationsSupported() const override; OpenGLBackend *backend() const @@ -55,20 +55,18 @@ private: * This class extends Shadow by the Elements required for OpenGL rendering. * @author Martin Gräßlin */ -class SceneOpenGLShadow - : public Shadow +class OpenGLShadowTextureProvider : public ShadowTextureProvider { public: - explicit SceneOpenGLShadow(Window *window); - ~SceneOpenGLShadow() override; + explicit OpenGLShadowTextureProvider(Shadow *shadow); + ~OpenGLShadowTextureProvider() override; GLTexture *shadowTexture() { return m_texture.get(); } -protected: - bool prepareBackend() override; + void update() override; private: std::shared_ptr m_texture; diff --git a/src/scene/workspacescene_qpainter.cpp b/src/scene/workspacescene_qpainter.cpp index 840d9e7f91..0df85f2d94 100644 --- a/src/scene/workspacescene_qpainter.cpp +++ b/src/scene/workspacescene_qpainter.cpp @@ -36,33 +36,28 @@ WorkspaceSceneQPainter::~WorkspaceSceneQPainter() { } -std::unique_ptr WorkspaceSceneQPainter::createShadow(Window *window) -{ - return std::make_unique(window); -} - DecorationRenderer *WorkspaceSceneQPainter::createDecorationRenderer(Decoration::DecoratedClientImpl *impl) { return new SceneQPainterDecorationRenderer(impl); } +std::unique_ptr WorkspaceSceneQPainter::createShadowTextureProvider(Shadow *shadow) +{ + return std::make_unique(shadow); +} + //**************************************** // QPainterShadow //**************************************** -SceneQPainterShadow::SceneQPainterShadow(Window *window) - : Shadow(window) +QPainterShadowTextureProvider::QPainterShadowTextureProvider(Shadow *shadow) + : ShadowTextureProvider(shadow) { } -SceneQPainterShadow::~SceneQPainterShadow() +void QPainterShadowTextureProvider::update() { } -bool SceneQPainterShadow::prepareBackend() -{ - return true; -} - //**************************************** // QPainterDecorationRenderer //**************************************** diff --git a/src/scene/workspacescene_qpainter.h b/src/scene/workspacescene_qpainter.h index 7bc30e2780..ed4c806baa 100644 --- a/src/scene/workspacescene_qpainter.h +++ b/src/scene/workspacescene_qpainter.h @@ -11,8 +11,8 @@ #include "qpainterbackend.h" #include "scene/decorationitem.h" +#include "scene/shadowitem.h" #include "scene/workspacescene.h" -#include "shadow.h" namespace KWin { @@ -25,8 +25,8 @@ public: explicit WorkspaceSceneQPainter(QPainterBackend *backend); ~WorkspaceSceneQPainter() override; - std::unique_ptr createShadow(Window *window) override; DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *impl) override; + std::unique_ptr createShadowTextureProvider(Shadow *shadow) override; bool animationsSupported() const override { @@ -42,14 +42,12 @@ private: QPainterBackend *m_backend; }; -class SceneQPainterShadow : public Shadow +class QPainterShadowTextureProvider : public ShadowTextureProvider { public: - SceneQPainterShadow(Window *window); - ~SceneQPainterShadow() override; + explicit QPainterShadowTextureProvider(Shadow *shadow); -protected: - bool prepareBackend() override; + void update() override; }; class SceneQPainterDecorationRenderer : public DecorationRenderer diff --git a/src/shadow.cpp b/src/shadow.cpp index 1811c4c9fa..abd6fd5a68 100644 --- a/src/shadow.cpp +++ b/src/shadow.cpp @@ -10,9 +10,7 @@ #include "shadow.h" // kwin #include "atoms.h" -#include "composite.h" #include "internalwindow.h" -#include "scene/workspacescene.h" #include "wayland/shadow_interface.h" #include "wayland/shmclientbuffer.h" #include "wayland/surface_interface.h" @@ -60,7 +58,7 @@ std::unique_ptr Shadow::createShadowFromX11(Window *window) { auto data = Shadow::readX11ShadowProperty(window->window()); if (!data.isEmpty()) { - auto shadow = Compositor::self()->scene()->createShadow(window); + auto shadow = std::make_unique(window); if (!shadow->init(data)) { return nullptr; } @@ -75,7 +73,7 @@ std::unique_ptr Shadow::createShadowFromDecoration(Window *window) if (!window->decoration()) { return nullptr; } - auto shadow = Compositor::self()->scene()->createShadow(window); + auto shadow = std::make_unique(window); if (!shadow->init(window->decoration())) { return nullptr; } @@ -92,7 +90,7 @@ std::unique_ptr Shadow::createShadowFromWayland(Window *window) if (!s) { return nullptr; } - auto shadow = Compositor::self()->scene()->createShadow(window); + auto shadow = std::make_unique(window); if (!shadow->init(s)) { return nullptr; } @@ -109,7 +107,7 @@ std::unique_ptr Shadow::createShadowFromInternalWindow(Window *window) if (!handle) { return nullptr; } - auto shadow = Compositor::self()->scene()->createShadow(window); + auto shadow = std::make_unique(window); if (!shadow->init(handle)) { return nullptr; } @@ -170,9 +168,6 @@ bool Shadow::init(const QVector &data) data[ShadowElementsCount + 1], data[ShadowElementsCount + 2]); Q_EMIT offsetChanged(); - if (!prepareBackend()) { - return false; - } Q_EMIT textureChanged(); return true; } @@ -196,9 +191,6 @@ bool Shadow::init(KDecoration2::Decoration *decoration) m_offset = m_decorationShadow->padding(); Q_EMIT offsetChanged(); - if (!prepareBackend()) { - return false; - } Q_EMIT textureChanged(); return true; } @@ -229,9 +221,6 @@ bool Shadow::init(const QPointer &shadow) m_offset = shadow->offset().toMargins(); Q_EMIT offsetChanged(); - if (!prepareBackend()) { - return false; - } Q_EMIT textureChanged(); return true; } @@ -263,10 +252,6 @@ bool Shadow::init(const QWindow *window) m_offset = window->property("kwin_shadow_padding").value(); Q_EMIT offsetChanged(); - - if (!prepareBackend()) { - return false; - } Q_EMIT textureChanged(); return true; } diff --git a/src/shadow.h b/src/shadow.h index 2e8ce87d70..d3db3043a7 100644 --- a/src/shadow.h +++ b/src/shadow.h @@ -47,6 +47,7 @@ class KWIN_EXPORT Shadow : public QObject { Q_OBJECT public: + explicit Shadow(Window *window); ~Shadow() override; /** @@ -58,7 +59,7 @@ public: * delete the Shadow. * @returns @c true when the shadow has been updated, @c false if the property is not set anymore. */ - virtual bool updateShadow(); + bool updateShadow(); /** * Factory Method to create the shadow from the property. @@ -112,6 +113,10 @@ public: { return m_offset; } + inline const QImage &shadowElement(ShadowElements element) const + { + return m_shadowElements[element]; + } Q_SIGNALS: void offsetChanged(); @@ -121,16 +126,6 @@ Q_SIGNALS: public Q_SLOTS: void geometryChanged(); -protected: - Shadow(Window *window); - - inline const QImage &shadowElement(ShadowElements element) const - { - return m_shadowElements[element]; - }; - - virtual bool prepareBackend() = 0; - private: static std::unique_ptr createShadowFromX11(Window *window); static std::unique_ptr createShadowFromDecoration(Window *window);