contrast: Improve performance

glCopyTexSubImage2D is super slow on Intel GPUs on wayland.

We have an existing method to read from the framebuffer that is used in
the blur and other effects.

Rather than creating a scratch framebuffer every frame we keep a cache
per window for the lifespan of the effect.

BUG: 469151
This commit is contained in:
David Edmundson 2023-06-23 14:15:06 +02:00
parent 2d53204738
commit b22e58846a
2 changed files with 32 additions and 23 deletions

View file

@ -160,12 +160,14 @@ void ContrastEffect::updateContrastRegion(EffectWindow *w)
}
if (valid) {
m_windowData[w] = {
.colorMatrix = matrix,
.contrastRegion = region,
};
Data &data = m_windowData[w];
data.colorMatrix = matrix;
data.contrastRegion = region;
} else {
m_windowData.remove(w);
if (auto it = m_windowData.find(w); it != m_windowData.end()) {
effects->makeOpenGLContextCurrent();
m_windowData.erase(it);
}
}
}
@ -208,7 +210,10 @@ void ContrastEffect::slotWindowDeleted(EffectWindow *w)
disconnect(m_contrastChangedConnections[w]);
m_contrastChangedConnections.remove(w);
}
m_windowData.remove(w);
if (auto it = m_windowData.find(w); it != m_windowData.end()) {
effects->makeOpenGLContextCurrent();
m_windowData.erase(it);
}
}
void ContrastEffect::slotPropertyNotify(EffectWindow *w, long atom)
@ -297,7 +302,7 @@ QRegion ContrastEffect::contrastRegion(const EffectWindow *w) const
{
QRegion region;
if (const auto it = m_windowData.find(w); it != m_windowData.end()) {
const QRegion &appRegion = it->contrastRegion;
const QRegion &appRegion = it->second.contrastRegion;
if (!appRegion.isEmpty()) {
region |= appRegion.translated(w->contentsRect().topLeft().toPoint()) & w->decorationInnerRect().toRect();
} else {
@ -434,23 +439,26 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi
}
vbo->bindArrays();
// Create a scratch texture and copy the area in the back buffer that we're
// going to blur into it
const auto scratch = GLTexture::allocate(GL_RGBA8, r.size().toSize());
if (!scratch) {
return;
Q_ASSERT(m_windowData.contains(w));
auto &windowData = m_windowData[w];
if (!windowData.texture || windowData.texture->size() != r.size()) {
windowData.texture = GLTexture::allocate(GL_RGBA8, r.size().toSize());
if (!windowData.texture) {
return;
}
windowData.fbo = std::make_unique<GLFramebuffer>(windowData.texture.get());
windowData.texture->setFilter(GL_LINEAR);
windowData.texture->setWrapMode(GL_CLAMP_TO_EDGE);
}
scratch->setFilter(GL_LINEAR);
scratch->setWrapMode(GL_CLAMP_TO_EDGE);
scratch->bind();
GLTexture *contrastTexture = windowData.texture.get();
contrastTexture->bind();
const QRectF sg = viewport.mapToRenderTarget(viewport.renderRect());
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (r.x() - sg.x()), (sg.height() - (r.y() - sg.y() + r.height())),
scratch->width(), scratch->height());
const QRect logicalSourceRect = actualShape.boundingRect();
windowData.fbo->blitFromRenderTarget(renderTarget, viewport, logicalSourceRect, QRect(0, 0, contrastTexture->width(), contrastTexture->height()));
// Draw the texture on the offscreen framebuffer object, while blurring it horizontally
m_shader->setColorMatrix(m_windowData.value(w).colorMatrix);
m_shader->setColorMatrix(m_windowData[w].colorMatrix);
m_shader->bind();
m_shader->setOpacity(opacity);
@ -463,8 +471,6 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi
textureMatrix *= renderTarget.transformation();
textureMatrix.translate(-0.5, -0.5);
// scaled logical to texture coordinates
textureMatrix.scale(1, -1);
textureMatrix.translate(0, -1);
textureMatrix.scale(1.0 / boundingRect.width(), 1.0 / boundingRect.height(), 1);
textureMatrix.translate(-boundingRect.x(), -boundingRect.y(), 0);
textureMatrix.scale(1.0 / viewport.scale(), 1.0 / viewport.scale());
@ -474,7 +480,7 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi
vbo->draw(GL_TRIANGLES, 0, actualShape.rectCount() * 6);
scratch->unbind();
contrastTexture->unbind();
vbo->unbindArrays();

View file

@ -13,6 +13,7 @@
#include <QVector2D>
#include <QVector>
#include <unordered_map>
namespace KWaylandServer
{
@ -71,8 +72,10 @@ private:
{
QMatrix4x4 colorMatrix;
QRegion contrastRegion;
std::unique_ptr<GLTexture> texture;
std::unique_ptr<GLFramebuffer> fbo;
};
QHash<const EffectWindow *, Data> m_windowData;
std::unordered_map<const EffectWindow *, Data> m_windowData;
static KWaylandServer::ContrastManagerInterface *s_contrastManager;
static QTimer *s_contrastManagerRemoveTimer;
};