From a1ac6df20e56ceb68b6e73441b9fa8100a727cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 6 Feb 2013 08:03:14 +0100 Subject: [PATCH] Move XRender based rendering of unstyled EffectFrame into scene_xrender This follows how it is done for OpenGL where the renderRoundBox() got dropped some time ago. New implementation implements the box with round corners using xrender directly instead of using a QPainter on a QPixmap. --- libkwineffects/kwinxrenderutils.cpp | 58 --------------- libkwineffects/kwinxrenderutils.h | 4 -- scene_xrender.cpp | 106 ++++++++++++++++++++++++++-- scene_xrender.h | 3 + 4 files changed, 105 insertions(+), 66 deletions(-) diff --git a/libkwineffects/kwinxrenderutils.cpp b/libkwineffects/kwinxrenderutils.cpp index 2ea6b9dc1d..41a864163b 100644 --- a/libkwineffects/kwinxrenderutils.cpp +++ b/libkwineffects/kwinxrenderutils.cpp @@ -73,64 +73,6 @@ XRenderPicture xRenderBlendPicture(double opacity) return _blendPicture; } - -static XRenderPicture *_circle[4] = {NULL, NULL, NULL, NULL}; - -#define DUMP_CNR(_SECT_, _W_, _H_, _XOFF_, _YOFF_)\ - dump = QPixmap(_W_, _H_);\ - dump.fill(Qt::transparent);\ - p.begin(&dump);\ - p.drawPixmap( 0, 0, tmp, _XOFF_, _YOFF_, _W_, _H_ );\ - p.end();\ - _circle[_SECT_] = new XRenderPicture(dump); - -#define CS 8 - -static XRenderPicture *circle(int i) -{ - if (!_circle[0]) { - QPixmap tmp(2 * CS, 2 * CS); - tmp.fill(Qt::transparent); - QPainter p(&tmp); - p.setRenderHint(QPainter::Antialiasing); - p.setPen(Qt::NoPen); p.setBrush(Qt::black); - p.drawEllipse(tmp.rect()); - p.end(); - QPixmap dump; - DUMP_CNR(0, CS, CS, 0, 0); - DUMP_CNR(1, CS, CS, CS, 0); - DUMP_CNR(2, CS, CS, CS, CS); - DUMP_CNR(3, CS, CS, 0, CS); - } - return _circle[i]; -} - -void xRenderRoundBox(Picture pict, const QRect &rect, int , const QColor &c) -{ - XRenderPicture fill = xRenderFill(c); - int op = c.alpha() == 255 ? PictOpSrc : PictOpOver; - // TODO: implement second paramenter "roundness" - // so rather use ?? XRenderCompositeTriFan (dpy, op, src, dst, maskFormat, xSrc, ySrc, - //XPointFixed *points, npoint); - // this will require "points on a circle" calculation, however... - - int s = qMin(CS, qMin(rect.height() / 2, rect.width() / 2)); - int x, y, b, r; - rect.getCoords(&x, &y, &r, &b); - r -= (s - 1); - b -= (s - 1); - XRenderComposite(display(), PictOpOver, fill, *circle(0), pict, 0, 0, 0, 0, x, y, CS, CS); - XRenderComposite(display(), PictOpOver, fill, *circle(1), pict, 0, 0, CS - s, 0, r, y, s, s); - XRenderComposite(display(), PictOpOver, fill, *circle(2), pict, 0, 0, CS - s, CS - s, r, b, s, s); - XRenderComposite(display(), PictOpOver, fill, *circle(3), pict, 0, 0, 0, CS - s, x, b, s, s); - XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x + s, y, rect.width() - 2 * s, s); - XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x, y + s, rect.width(), rect.height() - 2 * s); - XRenderComposite(display(), op, fill, 0, pict, 0, 0, 0, 0, x + s, b, rect.width() - 2 * s, s); -} - -#undef CS -#undef DUMP_CNR - // XRenderFind(Standard)Format() is a roundtrip, so cache the results static XRenderPictFormat* renderformats[ 33 ]; diff --git a/libkwineffects/kwinxrenderutils.h b/libkwineffects/kwinxrenderutils.h index 4218f8ba81..7069e8201f 100644 --- a/libkwineffects/kwinxrenderutils.h +++ b/libkwineffects/kwinxrenderutils.h @@ -39,10 +39,6 @@ along with this program. If not, see . namespace KWin { -/** - * draws a round box on the renderscene - */ -KWIN_EXPORT void xRenderRoundBox(Picture pict, const QRect &rect, int round, const QColor &c); /** * dumps a QColor into a XRenderColor */ diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 140470a168..dc40f66137 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -37,6 +37,7 @@ along with this program. If not, see . #include #include +#include namespace KWin { @@ -93,6 +94,7 @@ SceneXrender::~SceneXrender() m_overlayWindow->destroy(); return; } + SceneXrender::EffectFrame::cleanup(); XRenderFreePicture(display(), front); XRenderFreePicture(display(), buffer); buffer = None; @@ -727,6 +729,8 @@ void SceneXrender::screenGeometryChanged(const QSize &size) // SceneXrender::EffectFrame //**************************************** +XRenderPicture *SceneXrender::EffectFrame::s_effectFrameCircle = NULL; + SceneXrender::EffectFrame::EffectFrame(EffectFrameImpl* frame) : Scene::EffectFrame(frame) { @@ -744,6 +748,12 @@ SceneXrender::EffectFrame::~EffectFrame() delete m_selectionPicture; } +void SceneXrender::EffectFrame::cleanup() +{ + delete s_effectFrameCircle; + s_effectFrameCircle = NULL; +} + void SceneXrender::EffectFrame::free() { delete m_picture; @@ -792,10 +802,9 @@ void SceneXrender::EffectFrame::render(QRegion region, double opacity, double fr } // Render the actual frame - if (m_effectFrame->style() == EffectFrameUnstyled) - xRenderRoundBox(effects->xrenderBufferPicture(), m_effectFrame->geometry().adjusted(-5, -5, 5, 5), - 5, QColor(0, 0, 0, int(opacity * frameOpacity * 255))); - else if (m_effectFrame->style() == EffectFrameStyled) { + if (m_effectFrame->style() == EffectFrameUnstyled) { + renderUnstyled(effects->xrenderBufferPicture(), m_effectFrame->geometry(), opacity * frameOpacity); + } else if (m_effectFrame->style() == EffectFrameStyled) { if (!m_picture) { // Lazy creation updatePicture(); } @@ -844,6 +853,95 @@ void SceneXrender::EffectFrame::render(QRegion region, double opacity, double fr } } +void SceneXrender::EffectFrame::renderUnstyled(xcb_render_picture_t pict, const QRect &rect, qreal opacity) +{ + const int roundness = 5; + const QRect area = rect.adjusted(-roundness, -roundness, roundness, roundness); + xcb_rectangle_t rects[3]; + // center + rects[0].x = area.left(); + rects[0].y = area.top() + roundness; + rects[0].width = area.width(); + rects[0].height = area.height() - roundness * 2; + // top + rects[1].x = area.left() + roundness; + rects[1].y = area.top(); + rects[1].width = area.width() - roundness * 2; + rects[1].height = roundness; + // bottom + rects[2].x = area.left() + roundness; + rects[2].y = area.top() + area.height() - roundness; + rects[2].width = area.width() - roundness * 2; + rects[2].height = roundness; + xcb_render_color_t color = {0, 0, 0, uint16_t(opacity * 0xffff)}; + xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_OVER, pict, color, 3, rects); + + if (!s_effectFrameCircle) { + // create the circle + const int diameter = roundness * 2; + xcb_pixmap_t pix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 32, pix, rootWindow(), diameter, diameter); + s_effectFrameCircle = new XRenderPicture(pix, 32); + xcb_free_pixmap(connection(), pix); + + // clear it with transparent + xcb_rectangle_t xrect = {0, 0, diameter, diameter}; + xcb_render_color_t tranparent = {0, 0, 0, 0}; + xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, *s_effectFrameCircle, tranparent, 1, &xrect); + + static int num_segments = 80; + static qreal theta = 2 * M_PI / qreal(num_segments); + static qreal c = qCos(theta); //precalculate the sine and cosine + static qreal s = qSin(theta); + qreal t; + + qreal x = roundness;//we start at angle = 0 + qreal y = 0; + #define DOUBLE_TO_FIXED(d) ((xcb_render_fixed_t) ((d) * 65536)) + QVector points; + xcb_render_pointfix_t point; + point.x = DOUBLE_TO_FIXED(roundness); + point.y = DOUBLE_TO_FIXED(roundness); + points << point; + for (int ii = 0; ii <= num_segments; ++ii) { + point.x = DOUBLE_TO_FIXED(x + roundness); + point.y = DOUBLE_TO_FIXED(y + roundness); + points << point; + //apply the rotation matrix + t = x; + x = c * x - s * y; + y = s * t + c * y; + } + XRenderPicture fill = xRenderFill(Qt::black); + xcb_render_tri_fan(connection(), XCB_RENDER_PICT_OP_OVER, fill, *s_effectFrameCircle, + 0, 0, 0, points.count(), points.constData()); + #undef DOUBLE_TO_FIXED + } + // TODO: merge alpha mask with SceneXrender::Window::alphaMask + // alpha mask + xcb_pixmap_t pix = xcb_generate_id(connection()); + xcb_create_pixmap(connection(), 8, pix, rootWindow(), 1, 1); + XRenderPicture alphaMask(pix, 8); + xcb_free_pixmap(connection(), pix); + const uint32_t values[] = {true}; + xcb_render_change_picture(connection(), alphaMask, XCB_RENDER_CP_REPEAT, values); + color.alpha = int(opacity * 0xffff); + xcb_rectangle_t xrect = {0, 0, 1, 1}; + xcb_render_fill_rectangles(connection(), XCB_RENDER_PICT_OP_SRC, alphaMask, color, 1, &xrect); + + // TODO: replace by lambda +#define RENDER_CIRCLE(srcX, srcY, destX, destY) \ +xcb_render_composite(connection(), XCB_RENDER_PICT_OP_OVER, *s_effectFrameCircle, alphaMask, \ + pict, srcX, srcY, 0, 0, destX, destY, roundness, roundness) + + RENDER_CIRCLE(0, 0, area.left(), area.top()); + RENDER_CIRCLE(0, roundness, area.left(), area.top() + area.height() - roundness); + RENDER_CIRCLE(roundness, 0, area.left() + area.width() - roundness, area.top()); + RENDER_CIRCLE(roundness, roundness, + area.left() + area.width() - roundness, area.top() + area.height() - roundness); +#undef RENDER_CIRCLE +} + void SceneXrender::EffectFrame::updatePicture() { delete m_picture; diff --git a/scene_xrender.h b/scene_xrender.h index cfcb81416c..9f55ebd834 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -113,15 +113,18 @@ public: virtual void crossFadeIcon(); virtual void crossFadeText(); virtual void render(QRegion region, double opacity, double frameOpacity); + static void cleanup(); private: void updatePicture(); void updateTextPicture(); + void renderUnstyled(xcb_render_picture_t pict, const QRect &rect, qreal opacity); XRenderPicture* m_picture; XRenderPicture* m_textPicture; XRenderPicture* m_iconPicture; XRenderPicture* m_selectionPicture; + static XRenderPicture* s_effectFrameCircle; }; inline