Direct2D QPA: Optimize Clipping
Use axis aligned clips when possible instead of layer-clipping. This can be much faster when a lot of clipping operations take place. Change-Id: I6865d69fc917a7da858033b4c362b307724d9006 Reviewed-by: Risto Avila <risto.avila@digia.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Andrew Knight <andrew.knight@digia.com>
This commit is contained in:
parent
42bc626e4e
commit
5611b66c90
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
@ -235,21 +235,6 @@ static const QRectF boundingRect(const QPointF *points, int pointCount)
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T> static inline bool isRect(const T *pts, int elementCount) {
|
||||
return (elementCount == 5 // 5-point polygon, check for closed rect
|
||||
&& pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
|
||||
&& pts[0] == pts[6] && pts[2] == pts[4] // x values equal
|
||||
&& pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
|
||||
&& pts[0] < pts[4] && pts[1] < pts[5]
|
||||
) ||
|
||||
(elementCount == 4 // 4-point polygon, check for unclosed rect
|
||||
&& pts[0] == pts[6] && pts[2] == pts[4] // x values equal
|
||||
&& pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
|
||||
&& pts[0] < pts[4] && pts[1] < pts[5]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static void qt_ft_outline_move_to(qfixed x, qfixed y, void *data)
|
||||
{
|
||||
((QOutlineMapper *) data)->moveTo(QPointF(qt_fixed_to_real(x), qt_fixed_to_real(y)));
|
||||
@ -1193,22 +1178,14 @@ void QRasterPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
|
||||
Q_D(QRasterPaintEngine);
|
||||
QRasterPaintEngineState *s = state();
|
||||
|
||||
const qreal *points = path.points();
|
||||
const QPainterPath::ElementType *types = path.elements();
|
||||
|
||||
// There are some cases that are not supported by clip(QRect)
|
||||
if (op != Qt::IntersectClip || !s->clip || s->clip->hasRectClip || s->clip->hasRegionClip) {
|
||||
if (s->matrix.type() <= QTransform::TxScale
|
||||
&& ((path.shape() == QVectorPath::RectangleHint)
|
||||
|| (isRect(points, path.elementCount())
|
||||
&& (!types || (types[0] == QPainterPath::MoveToElement
|
||||
&& types[1] == QPainterPath::LineToElement
|
||||
&& types[2] == QPainterPath::LineToElement
|
||||
&& types[3] == QPainterPath::LineToElement))))) {
|
||||
&& path.isRect()) {
|
||||
#ifdef QT_DEBUG_DRAW
|
||||
qDebug() << " --- optimizing vector clip to rect clip...";
|
||||
#endif
|
||||
|
||||
const qreal *points = path.points();
|
||||
QRectF r(points[0], points[1], points[4]-points[0], points[5]-points[1]);
|
||||
if (setClipRectInDeviceCoords(s->matrix.mapRect(r).toRect(), op))
|
||||
return;
|
||||
@ -1939,7 +1916,7 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
|
||||
#endif
|
||||
Q_ASSERT(pointCount >= 2);
|
||||
|
||||
if (mode != PolylineMode && isRect((qreal *) points, pointCount)) {
|
||||
if (mode != PolylineMode && QVectorPath::isRect((qreal *) points, pointCount)) {
|
||||
QRectF r(points[0], points[2]);
|
||||
drawRects(&r, 1);
|
||||
return;
|
||||
@ -1980,7 +1957,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
|
||||
qDebug() << " - " << points[i];
|
||||
#endif
|
||||
Q_ASSERT(pointCount >= 2);
|
||||
if (mode != PolylineMode && isRect((int *) points, pointCount)) {
|
||||
if (mode != PolylineMode && QVectorPath::isRect((int *) points, pointCount)) {
|
||||
QRect r(points[0].x(),
|
||||
points[0].y(),
|
||||
points[2].x() - points[0].x(),
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
@ -167,6 +167,32 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T> static inline bool isRect(const T *pts, int elementCount) {
|
||||
return (elementCount == 5 // 5-point polygon, check for closed rect
|
||||
&& pts[0] == pts[8] && pts[1] == pts[9] // last point == first point
|
||||
&& pts[0] == pts[6] && pts[2] == pts[4] // x values equal
|
||||
&& pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
|
||||
&& pts[0] < pts[4] && pts[1] < pts[5]
|
||||
) ||
|
||||
(elementCount == 4 // 4-point polygon, check for unclosed rect
|
||||
&& pts[0] == pts[6] && pts[2] == pts[4] // x values equal
|
||||
&& pts[1] == pts[3] && pts[5] == pts[7] // y values equal...
|
||||
&& pts[0] < pts[4] && pts[1] < pts[5]
|
||||
);
|
||||
}
|
||||
|
||||
inline bool isRect() const
|
||||
{
|
||||
const QPainterPath::ElementType * const types = elements();
|
||||
|
||||
return (shape() == QVectorPath::RectangleHint)
|
||||
|| (isRect(points(), elementCount())
|
||||
&& (!types || (types[0] == QPainterPath::MoveToElement
|
||||
&& types[1] == QPainterPath::LineToElement
|
||||
&& types[2] == QPainterPath::LineToElement
|
||||
&& types[3] == QPainterPath::LineToElement)));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(QVectorPath)
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "qwindowsfontdatabase.h"
|
||||
#include "qwindowsintegration.h"
|
||||
|
||||
#include <QtCore/QStack>
|
||||
#include <QtGui/private/qpaintengine_p.h>
|
||||
#include <QtGui/private/qtextengine_p.h>
|
||||
#include <QtGui/private/qfontengine_p.h>
|
||||
@ -80,9 +81,14 @@ enum {
|
||||
|
||||
//Clipping flags
|
||||
enum {
|
||||
UserClip = 0x1,
|
||||
SimpleSystemClip = 0x2
|
||||
SimpleSystemClip = 0x1
|
||||
};
|
||||
|
||||
enum ClipType {
|
||||
AxisAlignedClip,
|
||||
LayerClip
|
||||
};
|
||||
|
||||
#define D2D_TAG(tag) d->dc()->SetTags(tag, tag)
|
||||
|
||||
Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert);
|
||||
@ -320,8 +326,8 @@ public:
|
||||
|
||||
QWindowsDirect2DBitmap *bitmap;
|
||||
|
||||
QPainterPath clipPath;
|
||||
unsigned int clipFlags;
|
||||
QStack<ClipType> pushedClips;
|
||||
|
||||
QPointF currentBrushOrigin;
|
||||
|
||||
@ -389,30 +395,55 @@ public:
|
||||
pen.brush->SetOpacity(opacity);
|
||||
}
|
||||
|
||||
void pushClip()
|
||||
void pushClip(const QVectorPath &path)
|
||||
{
|
||||
popClip();
|
||||
Q_Q(QWindowsDirect2DPaintEngine);
|
||||
|
||||
ComPtr<ID2D1PathGeometry1> geometry = painterPathToID2D1PathGeometry(clipPath, antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
if (!geometry)
|
||||
return;
|
||||
if (path.isEmpty()) {
|
||||
D2D_RECT_F rect = {0, 0, 0, 0};
|
||||
dc()->PushAxisAlignedClip(rect, antialiasMode());
|
||||
pushedClips.push(AxisAlignedClip);
|
||||
} else if (path.isRect() && (q->state()->matrix.type() <= QTransform::TxScale)) {
|
||||
const qreal * const points = path.points();
|
||||
D2D_RECT_F rect = {
|
||||
points[0], // left
|
||||
points[1], // top
|
||||
points[2], // right,
|
||||
points[5] // bottom
|
||||
};
|
||||
|
||||
dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(),
|
||||
geometry.Get(),
|
||||
antialiasMode(),
|
||||
D2D1::IdentityMatrix(),
|
||||
1.0,
|
||||
NULL,
|
||||
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
|
||||
NULL);
|
||||
clipFlags |= UserClip;
|
||||
dc()->PushAxisAlignedClip(rect, antialiasMode());
|
||||
pushedClips.push(AxisAlignedClip);
|
||||
} else {
|
||||
ComPtr<ID2D1PathGeometry1> geometry = vectorPathToID2D1PathGeometry(path, antialiasMode() == D2D1_ANTIALIAS_MODE_ALIASED);
|
||||
if (!geometry) {
|
||||
qWarning("%s: Could not convert vector path to painter path!", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
dc()->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(),
|
||||
geometry.Get(),
|
||||
antialiasMode(),
|
||||
D2D1::IdentityMatrix(),
|
||||
1.0,
|
||||
NULL,
|
||||
D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND),
|
||||
NULL);
|
||||
pushedClips.push(LayerClip);
|
||||
}
|
||||
}
|
||||
|
||||
void popClip()
|
||||
void clearClips()
|
||||
{
|
||||
if (clipFlags & UserClip) {
|
||||
dc()->PopLayer();
|
||||
clipFlags &= ~UserClip;
|
||||
while (!pushedClips.isEmpty()) {
|
||||
switch (pushedClips.pop()) {
|
||||
case AxisAlignedClip:
|
||||
dc()->PopAxisAlignedClip();
|
||||
break;
|
||||
case LayerClip:
|
||||
dc()->PopLayer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,24 +451,23 @@ public:
|
||||
{
|
||||
Q_Q(const QWindowsDirect2DPaintEngine);
|
||||
if (!q->state()->clipEnabled)
|
||||
popClip();
|
||||
else if (!(clipFlags & UserClip))
|
||||
pushClip();
|
||||
clearClips();
|
||||
else if (pushedClips.isEmpty())
|
||||
replayClipOperations();
|
||||
}
|
||||
|
||||
void updateClipPath(const QPainterPath &path, Qt::ClipOperation operation)
|
||||
void clip(const QVectorPath &path, Qt::ClipOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case Qt::NoClip:
|
||||
popClip();
|
||||
clearClips();
|
||||
break;
|
||||
case Qt::ReplaceClip:
|
||||
clipPath = path;
|
||||
pushClip();
|
||||
clearClips();
|
||||
pushClip(path);
|
||||
break;
|
||||
case Qt::IntersectClip:
|
||||
clipPath &= path;
|
||||
pushClip();
|
||||
pushClip(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -863,7 +893,7 @@ bool QWindowsDirect2DPaintEngine::end()
|
||||
{
|
||||
Q_D(QWindowsDirect2DPaintEngine);
|
||||
// First pop any user-applied clipping
|
||||
d->popClip();
|
||||
d->clearClips();
|
||||
// Now the system clip from begin() above
|
||||
if (d->clipFlags & SimpleSystemClip) {
|
||||
d->dc()->PopAxisAlignedClip();
|
||||
@ -915,7 +945,7 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br
|
||||
if (!d->brush.brush)
|
||||
return;
|
||||
|
||||
if (path.hints() & QVectorPath::RectangleShapeMask) {
|
||||
if (path.isRect()) {
|
||||
const qreal * const points = path.points();
|
||||
D2D_RECT_F rect = {
|
||||
points[0], // left
|
||||
@ -936,34 +966,10 @@ void QWindowsDirect2DPaintEngine::fill(const QVectorPath &path, const QBrush &br
|
||||
}
|
||||
}
|
||||
|
||||
// For clipping we convert everything to painter paths since it allows
|
||||
// calculating intersections easily. It might be faster to convert to
|
||||
// ID2D1Geometry and use its operations, although that needs to measured.
|
||||
// The implementation would be more complex in any case.
|
||||
|
||||
void QWindowsDirect2DPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op)
|
||||
{
|
||||
clip(path.convertToPainterPath(), op);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
|
||||
{
|
||||
QPainterPath p;
|
||||
p.addRect(rect);
|
||||
clip(p, op);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op)
|
||||
{
|
||||
QPainterPath p;
|
||||
p.addRegion(region);
|
||||
clip(p, op);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op)
|
||||
{
|
||||
Q_D(QWindowsDirect2DPaintEngine);
|
||||
d->updateClipPath(path, op);
|
||||
d->clip(path, op);
|
||||
}
|
||||
|
||||
void QWindowsDirect2DPaintEngine::clipEnabledChanged()
|
||||
|
@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
|
||||
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||
** Contact: http://www.qt-project.org/legal
|
||||
**
|
||||
** This file is part of the plugins of the Qt Toolkit.
|
||||
@ -66,11 +66,7 @@ public:
|
||||
Type type() const Q_DECL_OVERRIDE;
|
||||
|
||||
void fill(const QVectorPath &path, const QBrush &brush) Q_DECL_OVERRIDE;
|
||||
|
||||
void clip(const QVectorPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE;
|
||||
void clip(const QRect &rect, Qt::ClipOperation op) Q_DECL_OVERRIDE;
|
||||
void clip(const QRegion ®ion, Qt::ClipOperation op) Q_DECL_OVERRIDE;
|
||||
void clip(const QPainterPath &path, Qt::ClipOperation op) Q_DECL_OVERRIDE;
|
||||
|
||||
void clipEnabledChanged() Q_DECL_OVERRIDE;
|
||||
void penChanged() Q_DECL_OVERRIDE;
|
||||
|
Loading…
Reference in New Issue
Block a user