diff --git a/src/plugins/blur/blur.cpp b/src/plugins/blur/blur.cpp index 89e066b548..d16c4135ad 100644 --- a/src/plugins/blur/blur.cpp +++ b/src/plugins/blur/blur.cpp @@ -10,6 +10,7 @@ // KConfigSkeleton #include "blurconfig.h" +#include "core/pixelgrid.h" #include "core/rendertarget.h" #include "core/renderviewport.h" #include "effect/effecthandler.h" @@ -559,8 +560,29 @@ void BlurEffect::blur(const RenderTarget &renderTarget, const RenderViewport &vi blurShape = translated; } + const QRect backgroundRect = blurShape.boundingRect(); + const QRect deviceBackgroundRect = snapToPixelGrid(scaledRect(backgroundRect, viewport.scale())); + const auto opacity = w->opacity() * data.opacity(); + // Get the effective shape that will be actually blurred. It's possible that all of it will be clipped. - const QRegion effectiveShape = blurShape & region; + QList effectiveShape; + effectiveShape.reserve(blurShape.rectCount()); + if (region != infiniteRegion()) { + for (const QRect &clipRect : region) { + const QRectF deviceClipRect = snapToPixelGridF(scaledRect(clipRect, viewport.scale())) + .translated(-deviceBackgroundRect.topLeft()); + for (const QRect &shapeRect : blurShape) { + const QRectF deviceShapeRect = snapToPixelGridF(scaledRect(shapeRect.translated(-backgroundRect.topLeft()), viewport.scale())); + if (const QRectF intersected = deviceClipRect.intersected(deviceShapeRect); !intersected.isEmpty()) { + effectiveShape.append(intersected); + } + } + } + } else { + for (const QRect &rect : blurShape) { + effectiveShape.append(snapToPixelGridF(scaledRect(rect.translated(-backgroundRect.topLeft()), viewport.scale()))); + } + } if (effectiveShape.isEmpty()) { return; } @@ -572,10 +594,6 @@ void BlurEffect::blur(const RenderTarget &renderTarget, const RenderViewport &vi textureFormat = renderTarget.texture()->internalFormat(); } - const QRect backgroundRect = blurShape.boundingRect(); - const QRect deviceBackgroundRect = scaledRect(backgroundRect, viewport.scale()).toRect(); - const auto opacity = w->opacity() * data.opacity(); - if (renderInfo.framebuffers.size() != (m_iterationCount + 1) || renderInfo.textures[0]->size() != backgroundRect.size() || renderInfo.textures[0]->internalFormat() != textureFormat) { renderInfo.framebuffers.clear(); renderInfo.textures.clear(); @@ -611,7 +629,7 @@ void BlurEffect::blur(const RenderTarget &renderTarget, const RenderViewport &vi vbo->reset(); vbo->setAttribLayout(std::span(GLVertexBuffer::GLVertex2DLayout), sizeof(GLVertex2D)); - const int vertexCount = effectiveShape.rectCount() * 6; + const int vertexCount = effectiveShape.size() * 6; if (auto result = vbo->map(6 + vertexCount)) { auto map = *result; @@ -661,13 +679,11 @@ void BlurEffect::blur(const RenderTarget &renderTarget, const RenderViewport &vi } // The geometry that will be painted on screen, in device pixels. - for (const QRect &rect : effectiveShape) { - const QRectF localRect = scaledRect(rect, viewport.scale()).translated(-deviceBackgroundRect.topLeft()); - - const float x0 = std::round(localRect.left()); - const float y0 = std::round(localRect.top()); - const float x1 = std::round(localRect.right()); - const float y1 = std::round(localRect.bottom()); + for (const QRectF &rect : effectiveShape) { + const float x0 = rect.left(); + const float y0 = rect.top(); + const float x1 = rect.right(); + const float y1 = rect.bottom(); const float u0 = x0 / deviceBackgroundRect.width(); const float v0 = 1.0f - y0 / deviceBackgroundRect.height();