kwin: adding proper clipping for transformed windows

This patch kind of reintroduces the old PaintClipper functionality.

REVIEW: 104397
This commit is contained in:
Philipp Knechtges 2012-02-12 16:42:09 +01:00
parent ba573c60ed
commit 05a8777edf
6 changed files with 74 additions and 54 deletions

View file

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

View file

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

View file

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

View file

@ -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.

View file

@ -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<Client*>(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<SceneOpenGL*>(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<SceneOpenGL*>(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 &region, const WindowPaintData &data)
void SceneOpenGL::Window::paintShadow(const QRegion &region, 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 &region, 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<SceneOpenGL*>(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;
}

View file

@ -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 &region, 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 &region, 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);