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);