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.
icc-effect-5.14.5
Martin Gräßlin 2013-02-06 08:03:14 +01:00
parent 368de6842a
commit a1ac6df20e
4 changed files with 105 additions and 66 deletions

View File

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

View File

@ -39,10 +39,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
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
*/

View File

@ -37,6 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <kxerrorhandler.h>
#include <QtGui/QPainter>
#include <QtCore/qmath.h>
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<xcb_render_pointfix_t> 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;

View File

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