diff --git a/libkwineffects/kwinglutils.cpp b/libkwineffects/kwinglutils.cpp index 15597d48dd..9875d52f81 100644 --- a/libkwineffects/kwinglutils.cpp +++ b/libkwineffects/kwinglutils.cpp @@ -695,6 +695,11 @@ QImage GLTexture::convertToGLFormat(const QImage& img) const return res; } +bool GLTexture::isYInverted() const +{ + return y_inverted; +} + //**************************************** // GLShader //**************************************** diff --git a/libkwineffects/kwinglutils.h b/libkwineffects/kwinglutils.h index 2773fd0f2b..34ba33d0c6 100644 --- a/libkwineffects/kwinglutils.h +++ b/libkwineffects/kwinglutils.h @@ -150,6 +150,10 @@ public: int height() const { return mSize.height(); /// @since 4.5 } + /** + * @since 4.7 + **/ + bool isYInverted() const; virtual bool load(const QImage& image, GLenum target = GL_TEXTURE_2D); virtual bool load(const QPixmap& pixmap, GLenum target = GL_TEXTURE_2D); diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 2d472f3504..07e0c45398 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -513,14 +513,7 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData // shadow if (m_shadow) { - paintShadow(WindowQuadShadowTop, region, data); - paintShadow(WindowQuadShadowTopRight, region, data); - paintShadow(WindowQuadShadowRight, region, data); - paintShadow(WindowQuadShadowBottomRight, region, data); - paintShadow(WindowQuadShadowBottom, region, data); - paintShadow(WindowQuadShadowBottomLeft, region, data); - paintShadow(WindowQuadShadowLeft, region, data); - paintShadow(WindowQuadShadowTopLeft, region, data); + paintShadow(region, data); } // decorations Client *client = dynamic_cast(toplevel); @@ -659,10 +652,17 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType #endif } -void SceneOpenGL::Window::paintShadow(WindowQuadType type, const QRegion ®ion, const WindowPaintData &data) +void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintData &data) { - WindowQuadList quads = data.quads.select(type); - Texture *texture = static_cast(m_shadow)->textureForQuadType(type); + WindowQuadList quads = data.quads.select(WindowQuadShadowTopLeft); + quads.append(data.quads.select(WindowQuadShadowTop)); + quads.append(data.quads.select(WindowQuadShadowTopRight)); + quads.append(data.quads.select(WindowQuadShadowRight)); + quads.append(data.quads.select(WindowQuadShadowBottomRight)); + quads.append(data.quads.select(WindowQuadShadowBottom)); + quads.append(data.quads.select(WindowQuadShadowBottomLeft)); + quads.append(data.quads.select(WindowQuadShadowLeft)); + GLTexture *texture = static_cast(m_shadow)->shadowTexture(); if (!texture) { return; } @@ -744,7 +744,7 @@ 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, Texture *tex, bool normalized) +void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture *tex, bool normalized) { if (quads.isEmpty()) return; @@ -762,7 +762,7 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu size.setHeight(1.0); } #endif - quads.makeArrays(&vertices, &texcoords, size, tex->getYInverted()); + quads.makeArrays(&vertices, &texcoords, size, tex->isYInverted()); GLVertexBuffer::streamingBuffer()->setData(quads.count() * 6, 2, vertices, texcoords); GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES); delete[] vertices; @@ -798,7 +798,7 @@ void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double } } -void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture) +void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture) { if (shader) { prepareShaderRenderStates(type, opacity, brightness, saturation, shader); @@ -835,7 +835,7 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa shader->setUniform(GLShader::AlphaToOne, opaque ? 1 : 0); } -void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex) +void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex) { #ifdef KWIN_HAVE_OPENGLES Q_UNUSED(type) @@ -1000,7 +1000,7 @@ void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double } } -void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture) +void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture) { if (shader) { restoreShaderRenderStates(type, opacity, brightness, saturation, shader); @@ -1026,7 +1026,7 @@ void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opa #endif } -void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex) +void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex) { Q_UNUSED(type) #ifdef KWIN_HAVE_OPENGLES @@ -1535,71 +1535,169 @@ void SceneOpenGL::EffectFrame::cleanup() //**************************************** SceneOpenGLShadow::SceneOpenGLShadow(Toplevel *toplevel) : Shadow(toplevel) + , m_texture(NULL) { } SceneOpenGLShadow::~SceneOpenGLShadow() { - for (int i=0; i topLevel()->width()) || + (rightRect.width() - rightOffset() > topLevel()->width()) || + (topRect.height() - topOffset() > topLevel()->height()) || + (bottomRect.height() - bottomOffset() > topLevel()->height())) { + // if our shadow is bigger than the window, we don't render the shadow + setShadowRegion(QRegion()); + return; } - if (texture) { - if (texture->texture() != None) { - glBindTexture(texture->target(), texture->texture()); - } else if (!pixmap.isNull()) { - const bool success = texture->load(pixmap); - if (!success) { - kDebug(1212) << "Failed to bind shadow pixmap"; - return NULL; - } - } else { - return NULL; - } + // calculate the width + const qreal cornerWidth = topLeftRect.width() + topRightRect.width() + bottomLeftRect.width() + bottomRightRect.width(); + const qreal leftRightWidth = leftRect.width() + rightRect.width(); + const qreal topBottomWidth = topRect.width() + bottomRect.width(); + // calculate the height + const qreal cornerHeight = qMax(topLeftRect.height(), qMax(topRightRect.height(), qMax(bottomLeftRect.height(), bottomRightRect.height()))); + const qreal leftRightHeight = qMax(leftRect.height(), rightRect.height()); + const qreal width = m_texture->width(); + const qreal height = m_texture->height(); + qreal tx1, tx2, ty1, ty2; + tx1 = tx2 = ty1 = ty2 = 0.0; + tx2 = topLeftRect.width()/width; + ty2 = topLeftRect.height()/height; + WindowQuad topLeftQuad(WindowQuadShadowTopLeft); + topLeftQuad[ 0 ] = WindowVertex(-leftOffset(), -topOffset(), tx1, ty1); + topLeftQuad[ 1 ] = WindowVertex(-leftOffset() + topLeftRect.width(), -topOffset(), tx2, ty1); + topLeftQuad[ 2 ] = WindowVertex(-leftOffset() + topLeftRect.width(), -topOffset() + topLeftRect.height(), tx2, ty2); + topLeftQuad[ 3 ] = WindowVertex(-leftOffset(), -topOffset() + topLeftRect.height(), tx1, ty2); + quads.append(topLeftQuad); + tx2 = topRect.width()/width; + ty1 = (cornerHeight + leftRightHeight)/height; + ty2 = (cornerHeight + leftRightHeight + topRect.height())/height; + WindowQuad topQuad(WindowQuadShadowTop); + topQuad[ 0 ] = WindowVertex(-leftOffset() + topLeftRect.width(), -topOffset(), tx1, ty1); + topQuad[ 1 ] = WindowVertex(topLevel()->width() + rightOffset() - topRightRect.width(), -topOffset(), tx2, ty1); + topQuad[ 2 ] = WindowVertex(topLevel()->width() + rightOffset() - topRightRect.width(), -topOffset() + topRect.height(),tx2, ty2); + topQuad[ 3 ] = WindowVertex(-leftOffset() + topLeftRect.width(), -topOffset() + topRect.height(), tx1, ty2); + quads.append(topQuad); + tx1 = topLeftRect.width()/width; + tx2 = (topLeftRect.width() + topRightRect.width())/width; + ty1 = 0.0; + ty2 = topRightRect.height()/height; + WindowQuad topRightQuad(WindowQuadShadowTopRight); + topRightQuad[ 0 ] = WindowVertex(topLevel()->width() + rightOffset() - topRightRect.width(), -topOffset(), tx1, ty1); + topRightQuad[ 1 ] = WindowVertex(topLevel()->width() + rightOffset(), -topOffset(), tx2, ty1); + topRightQuad[ 2 ] = WindowVertex(topLevel()->width() + rightOffset(), -topOffset() + topRightRect.height(), tx2, ty2); + topRightQuad[ 3 ] = WindowVertex(topLevel()->width() + rightOffset() - topRightRect.width(), -topOffset() + topRightRect.height(), tx1, ty2); + quads.append(topRightQuad); + tx1 = leftRect.width()/width; + tx2 = leftRightWidth/width; + ty1 = cornerHeight/height; + ty2 = (cornerHeight+rightRect.height())/height; + WindowQuad rightQuad(WindowQuadShadowRight); + rightQuad[ 0 ] = WindowVertex(topLevel()->width() + rightOffset() - rightRect.width(), -topOffset() + topRightRect.height(), tx1, ty1); + rightQuad[ 1 ] = WindowVertex(topLevel()->width() + rightOffset(), -topOffset() + topRightRect.height(), tx2, ty1); + rightQuad[ 2 ] = WindowVertex(topLevel()->width() + rightOffset(), topLevel()->height() + bottomOffset() - bottomRightRect.height(), tx2, ty2); + rightQuad[ 3 ] = WindowVertex(topLevel()->width() + rightOffset() - rightRect.width(), topLevel()->height() + bottomOffset() - bottomRightRect.height(), tx1, ty2); + quads.append(rightQuad); + tx1 = (topLeftRect.width() + topRightRect.width() + bottomLeftRect.width())/width; + tx2 = cornerWidth/width; + ty1 = 0.0; + ty2 = bottomRightRect.height()/height; + WindowQuad bottomRightQuad(WindowQuadShadowBottomRight); + bottomRightQuad[ 0 ] = WindowVertex(topLevel()->width() + rightOffset() - bottomRightRect.width(), topLevel()->height() + bottomOffset() - bottomRightRect.height(), tx1, ty1); + bottomRightQuad[ 1 ] = WindowVertex(topLevel()->width() + rightOffset(), topLevel()->height() + bottomOffset() - bottomRightRect.height(), tx2, ty1); + bottomRightQuad[ 2 ] = WindowVertex(topLevel()->width() + rightOffset(), topLevel()->height() + bottomOffset(), tx2, ty2); + bottomRightQuad[ 3 ] = WindowVertex(topLevel()->width() + rightOffset() - bottomRightRect.width(), topLevel()->height() + bottomOffset(), tx1, ty2); + quads.append(bottomRightQuad); + tx1 = topRect.width()/width; + tx2 = topBottomWidth/width; + ty1 = (cornerHeight + leftRightHeight)/height; + ty2 = (cornerHeight + leftRightHeight + bottomRect.height())/height; + WindowQuad bottomQuad(WindowQuadShadowBottom); + bottomQuad[ 0 ] = WindowVertex(-leftOffset() + bottomLeftRect.width(), topLevel()->height() + bottomOffset() - bottomRect.height(), tx1, ty1); + bottomQuad[ 1 ] = WindowVertex(topLevel()->width() + rightOffset() - bottomRightRect.width(), topLevel()->height() + bottomOffset() - bottomRect.height(), tx2, ty1); + bottomQuad[ 2 ] = WindowVertex(topLevel()->width() + rightOffset() - bottomRightRect.width(), topLevel()->height() + bottomOffset(), tx2, ty2); + bottomQuad[ 3 ] = WindowVertex(-leftOffset() + bottomLeftRect.width(), topLevel()->height() + bottomOffset(), tx1, ty2); + quads.append(bottomQuad); + tx1 = (topLeftRect.width() + topRightRect.width())/width; + tx2 = (topLeftRect.width() + topRightRect.width() + bottomLeftRect.width())/width; + ty1 = 0.0; + ty2 = bottomLeftRect.height()/height; + WindowQuad bottomLeftQuad(WindowQuadShadowBottomLeft); + bottomLeftQuad[ 0 ] = WindowVertex(-leftOffset(), topLevel()->height() + bottomOffset() - bottomLeftRect.height(), tx1, ty1); + bottomLeftQuad[ 1 ] = WindowVertex(-leftOffset() + bottomLeftRect.width(), topLevel()->height() + bottomOffset() - bottomLeftRect.height(), tx2, ty1); + bottomLeftQuad[ 2 ] = WindowVertex(-leftOffset() + bottomLeftRect.width(), topLevel()->height() + bottomOffset(), tx2, ty2); + bottomLeftQuad[ 3 ] = WindowVertex(-leftOffset(), topLevel()->height() + bottomOffset(), tx1, ty2); + quads.append(bottomLeftQuad); + tx1 = 0.0; + tx2 = leftRect.width()/width; + ty1 = cornerHeight/height; + ty2 = (cornerHeight+leftRect.height())/height; + WindowQuad leftQuad(WindowQuadShadowLeft); + leftQuad[ 0 ] = WindowVertex(-leftOffset(), -topOffset() + topLeftRect.height(), tx1, ty1); + leftQuad[ 1 ] = WindowVertex(-leftOffset() + leftRect.width(), -topOffset() + topLeftRect.height(), tx2, ty1); + leftQuad[ 2 ] = WindowVertex(-leftOffset() + leftRect.width(), topLevel()->height() + bottomOffset() - bottomLeftRect.height(), tx2, ty2); + leftQuad[ 3 ] = WindowVertex(-leftOffset(), topLevel()->height() + bottomOffset() - bottomLeftRect.height(), tx1, ty2); + quads.append(leftQuad); + m_shadowQuads = quads; +} + +bool SceneOpenGLShadow::prepareBackend() +{ + const QRect topRect(QPoint(0, 0), shadowPixmap(ShadowElementTop).size()); + const QRect topRightRect(QPoint(0, 0), shadowPixmap(ShadowElementTopRight).size()); + const QRect rightRect(QPoint(0, 0), shadowPixmap(ShadowElementRight).size()); + const QRect bottomRightRect(QPoint(0, 0), shadowPixmap(ShadowElementBottomRight).size()); + const QRect bottomRect(QPoint(0, 0), shadowPixmap(ShadowElementBottom).size()); + const QRect bottomLeftRect(QPoint(0, 0), shadowPixmap(ShadowElementBottomLeft).size()); + const QRect leftRect(QPoint(0, 0), shadowPixmap(ShadowElementLeft).size()); + const QRect topLeftRect(QPoint(0, 0), shadowPixmap(ShadowElementTopLeft).size()); + // calculate the width + const int cornerWidth = topLeftRect.width() + topRightRect.width() + bottomLeftRect.width() + bottomRightRect.width(); + const int leftRightWidth = leftRect.width() + rightRect.width(); + const int topBottomWidth = topRect.width() + bottomRect.width(); + const int width = qMax(cornerWidth, qMax(leftRightWidth, topBottomWidth)); + // calculate the height + const int cornerHeight = qMax(topLeftRect.height(), qMax(topRightRect.height(), qMax(bottomLeftRect.height(), bottomRightRect.height()))); + const int leftRightHeight = qMax(leftRect.height(), rightRect.height()); + const int topBottomHeight = qMax(topRect.height(), bottomRect.height()); + const int height = cornerHeight + leftRightHeight + topBottomHeight; + + QImage image(width, height, QImage::Format_ARGB32); + image.fill(Qt::transparent); + QPainter p; + p.begin(&image); + p.drawPixmap(0, 0, shadowPixmap(ShadowElementTopLeft)); + p.drawPixmap(topLeftRect.width(), 0, shadowPixmap(ShadowElementTopRight)); + p.drawPixmap(topLeftRect.width() + topRightRect.width(), 0, shadowPixmap(ShadowElementBottomLeft)); + p.drawPixmap(topLeftRect.width() + topRightRect.width() + bottomLeftRect.width(), 0, shadowPixmap(ShadowElementBottomRight)); + p.drawPixmap(0, cornerHeight, shadowPixmap(ShadowElementLeft)); + p.drawPixmap(leftRect.width(), cornerHeight, shadowPixmap(ShadowElementRight)); + p.drawPixmap(0, cornerHeight + leftRightHeight, shadowPixmap(ShadowElementTop)); + p.drawPixmap(topRect.width(), cornerHeight + leftRightHeight, shadowPixmap(ShadowElementBottom)); + p.end(); + + if (m_texture) { + delete m_texture; + m_texture = NULL; } - return texture; + + m_texture = new GLTexture(image); + return true; } } // namespace diff --git a/scene_opengl.h b/scene_opengl.h index 0de22ce23e..fdff2f0340 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -167,16 +167,16 @@ 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(WindowQuadType type, const QRegion ®ion, const WindowPaintData &data); + void paintShadow(const QRegion ®ion, const WindowPaintData &data); void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const; - void renderQuads(int, const QRegion& region, const WindowQuadList& quads, Texture* tex, bool normalized = false); + void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized = false); void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); - void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture); - void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex); + 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); void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); - void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, Texture *texture); - void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, Texture *tex); + void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture); + void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex); void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader); private: @@ -237,16 +237,14 @@ public: SceneOpenGLShadow(Toplevel *toplevel); virtual ~SceneOpenGLShadow(); - /** - * Returns the Texture for a specific ShadowQuad. The method takes care of performing - * the Texture from Pixmap operation. The calling method can use the returned Texture - * directly. - * In error case the method returns @c NULL. - * @return OpenGL Texture for the Shadow Quad. May be @c NULL. - **/ - SceneOpenGL::Texture *textureForQuadType(WindowQuadType type); + GLTexture *shadowTexture() { + return m_texture; + } +protected: + virtual void buildQuads(); + virtual bool prepareBackend(); private: - SceneOpenGL::Texture m_shadowTextures[ShadowElementsCount]; + GLTexture *m_texture; }; } // namespace diff --git a/scene_xrender.h b/scene_xrender.h index 0600550386..b00a454897 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -165,6 +165,9 @@ public: protected: virtual void buildQuads(); + virtual bool prepareBackend() { + return true; + }; private: QPixmap m_resizedElements[ShadowElementsCount]; diff --git a/shadow.cpp b/shadow.cpp index d51a0259dc..c47b5e9ed7 100644 --- a/shadow.cpp +++ b/shadow.cpp @@ -110,6 +110,9 @@ bool Shadow::init(const QVector< long > &data) m_bottomOffset = data[ShadowElementsCount+2]; m_leftOffset = data[ShadowElementsCount+3]; updateShadowRegion(); + if (!prepareBackend()) { + return false; + } buildQuads(); return true; } diff --git a/shadow.h b/shadow.h index 7127db95ae..43108184b5 100644 --- a/shadow.h +++ b/shadow.h @@ -23,6 +23,7 @@ along with this program. If not, see . #include #include #include +#include namespace KWin { @@ -58,7 +59,10 @@ public: /** * @return Cached Shadow Quads **/ - const WindowQuadList &shadowQuads() { + const WindowQuadList &shadowQuads() const { + return m_shadowQuads; + }; + WindowQuadList &shadowQuads() { return m_shadowQuads; }; @@ -125,6 +129,14 @@ protected: }; virtual void buildQuads(); void updateShadowRegion(); + Toplevel *topLevel() { + return m_topLevel; + }; + void setShadowRegion(const QRegion ®ion) { + m_shadowRegion = region; + }; + virtual bool prepareBackend() = 0; + WindowQuadList m_shadowQuads; private: static QVector readX11ShadowProperty(WId id); @@ -139,7 +151,6 @@ private: int m_leftOffset; // caches QRegion m_shadowRegion; - WindowQuadList m_shadowQuads; QSize m_cachedSize; };