From 05a8777edfb3b71a2ae9c64d304ac00b80f79904 Mon Sep 17 00:00:00 2001 From: Philipp Knechtges Date: Sun, 12 Feb 2012 16:42:09 +0100 Subject: [PATCH] kwin: adding proper clipping for transformed windows This patch kind of reintroduces the old PaintClipper functionality. REVIEW: 104397 --- libkwineffects/kwingltexture.cpp | 4 +-- libkwineffects/kwingltexture.h | 2 +- libkwineffects/kwinglutils.cpp | 52 +++++++++++++++++++--------- libkwineffects/kwinglutils.h | 5 +-- scene_opengl.cpp | 59 ++++++++++++++++---------------- scene_opengl.h | 6 ++-- 6 files changed, 74 insertions(+), 54 deletions(-) diff --git a/libkwineffects/kwingltexture.cpp b/libkwineffects/kwingltexture.cpp index 50a081025c..410c35da9e 100644 --- a/libkwineffects/kwingltexture.cpp +++ b/libkwineffects/kwingltexture.cpp @@ -297,7 +297,7 @@ void GLTexture::unbind() d->unbind(); } -void GLTexture::render(QRegion region, const QRect& rect) +void GLTexture::render(QRegion region, const QRect& rect, bool hardwareClipping) { Q_D(GLTexture); if (rect.size() != d->m_cachedSize) { @@ -338,7 +338,7 @@ void GLTexture::render(QRegion region, const QRect& rect) } else { pushMatrix(translation); } - d->m_vbo->render(region, GL_TRIANGLE_STRIP); + d->m_vbo->render(region, GL_TRIANGLE_STRIP, hardwareClipping); if (ShaderManager::instance()->isShaderBound()) { GLShader *shader = ShaderManager::instance()->getBoundShader(); shader->setUniform(GLShader::WindowTransformation, QMatrix4x4()); diff --git a/libkwineffects/kwingltexture.h b/libkwineffects/kwingltexture.h index ed24349af5..a18dc94317 100644 --- a/libkwineffects/kwingltexture.h +++ b/libkwineffects/kwingltexture.h @@ -72,7 +72,7 @@ public: virtual void discard(); void bind(); void unbind(); - void render(QRegion region, const QRect& rect); + void render(QRegion region, const QRect& rect, bool hardwareClipping = false); GLuint texture() const; GLenum target() const; diff --git a/libkwineffects/kwinglutils.cpp b/libkwineffects/kwinglutils.cpp index 016603bc7f..0b125ef185 100644 --- a/libkwineffects/kwinglutils.cpp +++ b/libkwineffects/kwinglutils.cpp @@ -1145,18 +1145,17 @@ public: QColor color; //! VBO is not supported - void legacyPainting(QRegion region, GLenum primitiveMode); + void legacyPainting(QRegion region, GLenum primitiveMode, bool hardwareClipping); //! VBO and shaders are both supported - void corePainting(const QRegion& region, GLenum primitiveMode); + void corePainting(const QRegion& region, GLenum primitiveMode, bool hardwareClipping); //! VBO is supported, but shaders are not supported - void fallbackPainting(const QRegion& region, GLenum primitiveMode); + void fallbackPainting(const QRegion& region, GLenum primitiveMode, bool hardwareClipping); }; bool GLVertexBufferPrivate::supported = false; GLVertexBuffer *GLVertexBufferPrivate::streamingBuffer = NULL; -void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode) +void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode, bool hardwareClipping) { - Q_UNUSED(region) #ifdef KWIN_HAVE_OPENGLES Q_UNUSED(primitiveMode) #else @@ -1172,7 +1171,14 @@ void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode) glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); } - glDrawArrays(primitiveMode, 0, numberVertices); + if (!hardwareClipping) { + glDrawArrays(primitiveMode, 0, numberVertices); + } else { + foreach (const QRect& r, region.rects()) { + glScissor(r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height()); + glDrawArrays(primitiveMode, 0, numberVertices); + } + } glDisableClientState(GL_VERTEX_ARRAY); if (!legacyTexCoords.isEmpty()) { @@ -1181,9 +1187,8 @@ void GLVertexBufferPrivate::legacyPainting(QRegion region, GLenum primitiveMode) #endif } -void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitiveMode) +void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitiveMode, bool hardwareClipping) { - Q_UNUSED(region) GLShader *shader = ShaderManager::instance()->getBoundShader(); GLint vertexAttrib = shader->attributeLocation("vertex"); GLint texAttrib = shader->attributeLocation("texCoord"); @@ -1205,7 +1210,14 @@ void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitive glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0); } - glDrawArrays(primitiveMode, 0, numberVertices); + if (!hardwareClipping) { + glDrawArrays(primitiveMode, 0, numberVertices); + } else { + foreach (const QRect& r, region.rects()) { + glScissor(r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height()); + glDrawArrays(primitiveMode, 0, numberVertices); + } + } glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -1215,9 +1227,8 @@ void GLVertexBufferPrivate::corePainting(const QRegion& region, GLenum primitive glDisableVertexAttribArray(vertexAttrib); } -void GLVertexBufferPrivate::fallbackPainting(const QRegion& region, GLenum primitiveMode) +void GLVertexBufferPrivate::fallbackPainting(const QRegion& region, GLenum primitiveMode, bool hardwareClipping) { - Q_UNUSED(region) #ifdef KWIN_HAVE_OPENGLES Q_UNUSED(primitiveMode) #else @@ -1234,7 +1245,14 @@ void GLVertexBufferPrivate::fallbackPainting(const QRegion& region, GLenum primi } // Clip using scissoring - glDrawArrays(primitiveMode, 0, numberVertices); + if (!hardwareClipping) { + glDrawArrays(primitiveMode, 0, numberVertices); + } else { + foreach (const QRect& r, region.rects()) { + glScissor(r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height()); + glDrawArrays(primitiveMode, 0, numberVertices); + } + } glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -1306,17 +1324,17 @@ void GLVertexBuffer::setData(int numberVertices, int dim, const float* vertices, void GLVertexBuffer::render(GLenum primitiveMode) { - render(infiniteRegion(), primitiveMode); + render(infiniteRegion(), primitiveMode, false); } -void GLVertexBuffer::render(const QRegion& region, GLenum primitiveMode) +void GLVertexBuffer::render(const QRegion& region, GLenum primitiveMode, bool hardwareClipping) { if (!GLVertexBufferPrivate::supported) { - d->legacyPainting(region, primitiveMode); + d->legacyPainting(region, primitiveMode, hardwareClipping); } else if (ShaderManager::instance()->isShaderBound()) { - d->corePainting(region, primitiveMode); + d->corePainting(region, primitiveMode, hardwareClipping); } else { - d->fallbackPainting(region, primitiveMode); + d->fallbackPainting(region, primitiveMode, hardwareClipping); } } diff --git a/libkwineffects/kwinglutils.h b/libkwineffects/kwinglutils.h index c39f2dc361..7a7c3c96ee 100644 --- a/libkwineffects/kwinglutils.h +++ b/libkwineffects/kwinglutils.h @@ -510,9 +510,10 @@ public: */ void render(GLenum primitiveMode); /** - * Same as above restricting painting to @a region. + * Same as above restricting painting to @a region if @a hardwareClipping is true. + * It's within the caller's responsibility to enable GL_SCISSOR_TEST. */ - void render(const QRegion& region, GLenum primitiveMode); + void render(const QRegion& region, GLenum primitiveMode, bool hardwareClipping = false); /** * Sets the color the geometry will be rendered with. * For legacy rendering glColor is used before rendering the geometry. diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 43d30ad55a..2ff293847f 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -445,22 +445,11 @@ QMatrix4x4 SceneOpenGL::Window::transformation(int mask, const WindowPaintData & // paint the window void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData data) { - // check if there is something to paint (e.g. don't paint if the window - // is only opaque and only PAINT_WINDOW_TRANSLUCENT is requested) - /* HACK: It seems this causes painting glitches, disable temporarily - bool opaque = isOpaque() && data.opacity == 1.0; - if (( mask & PAINT_WINDOW_OPAQUE ) ^ ( mask & PAINT_WINDOW_TRANSLUCENT )) - { // We are only painting either opaque OR translucent windows, not both - if ( mask & PAINT_WINDOW_OPAQUE && !opaque ) - return; // Only painting opaque and window is translucent - if ( mask & PAINT_WINDOW_TRANSLUCENT && opaque ) - return; // Only painting translucent and window is opaque - }*/ - if (region.isEmpty()) return; - if (region != infiniteRegion() && !(mask & PAINT_WINDOW_TRANSFORMED)) { + bool hardwareClipping = region != infiniteRegion() && (mask & PAINT_WINDOW_TRANSFORMED); + if (region != infiniteRegion() && !hardwareClipping) { WindowQuadList quads; const QRegion filterRegion = region.translated(-x(), -y()); // split all quads in bounding rect with the actual rects in the region @@ -483,8 +472,13 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData data.quads = quads; } - if (!bindTexture()) + if (!bindTexture()) { return; + } + + if (hardwareClipping) { + glEnable(GL_SCISSOR_TEST); + } // Update the texture filter if (options->glSmoothScale() != 0 && @@ -523,7 +517,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData // shadow if (m_shadow) { - paintShadow(region, data); + paintShadow(region, data, hardwareClipping); } // decorations Client *client = dynamic_cast(toplevel); @@ -578,10 +572,10 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData } } - paintDecoration(top, DecorationTop, region, topRect, data, topList, updateDeco); - paintDecoration(left, DecorationLeft, region, leftRect, data, leftList, updateDeco); - paintDecoration(right, DecorationRight, region, rightRect, data, rightList, updateDeco); - paintDecoration(bottom, DecorationBottom, region, bottomRect, data, bottomList, updateDeco); + paintDecoration(top, DecorationTop, region, topRect, data, topList, updateDeco, hardwareClipping); + paintDecoration(left, DecorationLeft, region, leftRect, data, leftList, updateDeco, hardwareClipping); + paintDecoration(right, DecorationRight, region, rightRect, data, rightList, updateDeco, hardwareClipping); + paintDecoration(bottom, DecorationBottom, region, bottomRect, data, bottomList, updateDeco, hardwareClipping); } } @@ -590,18 +584,22 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData if (!contentQuads.empty()) { texture.bind(); prepareStates(Content, data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader); - renderQuads(mask, region, contentQuads, &texture); + renderQuads(mask, region, contentQuads, &texture, false, hardwareClipping); restoreStates(Content, data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader); texture.unbind(); #ifndef KWIN_HAVE_OPENGLES if (static_cast(scene)->debug) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - renderQuads(mask, region, contentQuads, &texture); + renderQuads(mask, region, contentQuads, &texture, false, hardwareClipping); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif } + if (hardwareClipping) { + glDisable(GL_SCISSOR_TEST); + } + if (sceneShader) { ShaderManager::instance()->popShader(); data.shader = NULL; @@ -610,7 +608,9 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData } } -void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco) +void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType decorationType, + const QRegion& region, const QRect& rect, const WindowPaintData& data, + const WindowQuadList& quads, bool updateDeco, bool hardwareClipping) { SceneOpenGL::Texture* decorationTexture; switch(decorationType) { @@ -658,19 +658,19 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType prepareStates(decorationType, data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader); makeDecorationArrays(quads, rect, decorationTexture); - GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES); + GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping); restoreStates(decorationType, data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader); decorationTexture->unbind(); #ifndef KWIN_HAVE_OPENGLES if (static_cast(scene)->debug) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES); + GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif } -void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintData &data) +void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintData &data, bool hardwareClipping) { WindowQuadList quads = data.quads.select(WindowQuadShadowTopLeft); quads.append(data.quads.select(WindowQuadShadowTop)); @@ -694,13 +694,13 @@ void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintDa texture->setWrapMode(GL_CLAMP_TO_EDGE); texture->bind(); prepareStates(Shadow, data.opacity, data.brightness, data.saturation, data.shader, texture); - renderQuads(0, region, quads, texture, true); + renderQuads(0, region, quads, texture, true, hardwareClipping); restoreStates(Shadow, data.opacity, data.brightness, data.saturation, data.shader, texture); texture->unbind(); #ifndef KWIN_HAVE_OPENGLES if (static_cast(scene)->debug) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - renderQuads(0, region, quads, texture); + renderQuads(0, region, quads, texture, true, hardwareClipping); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } #endif @@ -765,7 +765,8 @@ void SceneOpenGL::Window::makeDecorationArrays(const WindowQuadList& quads, cons GLVertexBuffer::streamingBuffer()->setData(quads.count() * 6, 2, vertices.data(), texcoords.data()); } -void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture *tex, bool normalized) +void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQuadList& quads, + GLTexture *tex, bool normalized, bool hardwareClipping) { if (quads.isEmpty()) return; @@ -785,7 +786,7 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu #endif quads.makeArrays(&vertices, &texcoords, size, tex->isYInverted()); GLVertexBuffer::streamingBuffer()->setData(quads.count() * 6, 2, vertices, texcoords); - GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES); + GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping); delete[] vertices; delete[] texcoords; } diff --git a/scene_opengl.h b/scene_opengl.h index 98d4dd41ad..7cf3b6c8fb 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -175,10 +175,10 @@ protected: }; QMatrix4x4 transformation(int mask, const WindowPaintData &data) const; - void paintDecoration(const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco); - void paintShadow(const QRegion ®ion, const WindowPaintData &data); + void paintDecoration(const QPixmap* decoration, TextureType decorationType, const QRegion& region, const QRect& rect, const WindowPaintData& data, const WindowQuadList& quads, bool updateDeco, bool hardwareClipping); + void paintShadow(const QRegion ®ion, const WindowPaintData &data, bool hardwareClipping); void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const; - void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized = false); + void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized, bool hardwareClipping); void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture); void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex);