Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: src/core/SkCanvas.cpp

Issue 2225393002: Optimized implementation of quickReject() (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Adding test and Debug asserts Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkPostConfig.h ('k') | tests/QuickRejectTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2008 The Android Open Source Project 2 * Copyright 2008 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBitmapDevice.h" 8 #include "SkBitmapDevice.h"
9 #include "SkCanvas.h" 9 #include "SkCanvas.h"
10 #include "SkCanvasPriv.h" 10 #include "SkCanvasPriv.h"
11 #include "SkClipStack.h" 11 #include "SkClipStack.h"
12 #include "SkColorFilter.h" 12 #include "SkColorFilter.h"
13 #include "SkDraw.h" 13 #include "SkDraw.h"
14 #include "SkDrawable.h" 14 #include "SkDrawable.h"
15 #include "SkDrawFilter.h" 15 #include "SkDrawFilter.h"
16 #include "SkDrawLooper.h" 16 #include "SkDrawLooper.h"
17 #include "SkErrorInternals.h" 17 #include "SkErrorInternals.h"
18 #include "SkImage.h" 18 #include "SkImage.h"
19 #include "SkImage_Base.h" 19 #include "SkImage_Base.h"
20 #include "SkImageFilter.h" 20 #include "SkImageFilter.h"
21 #include "SkImageFilterCache.h" 21 #include "SkImageFilterCache.h"
22 #include "SkLatticeIter.h" 22 #include "SkLatticeIter.h"
23 #include "SkMatrixUtils.h" 23 #include "SkMatrixUtils.h"
24 #include "SkMetaData.h" 24 #include "SkMetaData.h"
25 #include "SkNx.h"
25 #include "SkPaintPriv.h" 26 #include "SkPaintPriv.h"
26 #include "SkPatchUtils.h" 27 #include "SkPatchUtils.h"
27 #include "SkPicture.h" 28 #include "SkPicture.h"
28 #include "SkRasterClip.h" 29 #include "SkRasterClip.h"
29 #include "SkReadPixelsRec.h" 30 #include "SkReadPixelsRec.h"
30 #include "SkRRect.h" 31 #include "SkRRect.h"
31 #include "SkSmallAllocator.h" 32 #include "SkSmallAllocator.h"
32 #include "SkSpecialImage.h" 33 #include "SkSpecialImage.h"
33 #include "SkSurface_Base.h" 34 #include "SkSurface_Base.h"
34 #include "SkTextBlob.h" 35 #include "SkTextBlob.h"
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after
623 #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \ 624 #define LOOPER_BEGIN_CHECK_COMPLETE_OVERWRITE(paint, type, bounds, auxOpaque) \
624 this->predrawNotify(bounds, &paint, auxOpaque); \ 625 this->predrawNotify(bounds, &paint, auxOpaque); \
625 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ 626 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
626 while (looper.next(type)) { \ 627 while (looper.next(type)) { \
627 SkDrawIter iter(this); 628 SkDrawIter iter(this);
628 629
629 #define LOOPER_END } 630 #define LOOPER_END }
630 631
631 //////////////////////////////////////////////////////////////////////////// 632 ////////////////////////////////////////////////////////////////////////////
632 633
634 static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
635 // Expand bounds out by 1 in case we are anti-aliasing. We store the
636 // bounds as floats to enable a faster quick reject implementation.
637 SkRect dst;
638 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLe ft);
639 return dst;
640 }
641
633 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { 642 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
634 this->restoreToCount(1); 643 this->restoreToCount(1);
635 fCachedLocalClipBounds.setEmpty();
636 fCachedLocalClipBoundsDirty = true;
637 fClipStack->reset(); 644 fClipStack->reset();
638 fMCRec->reset(bounds); 645 fMCRec->reset(bounds);
639 646
640 // We're peering through a lot of structs here. Only at this scope do we 647 // We're peering through a lot of structs here. Only at this scope do we
641 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi ce). 648 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi ce).
642 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e()); 649 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e());
650 fDeviceClipBounds = qr_clip_bounds(bounds);
651 fConservativeIsScaleTranslate = true;
643 } 652 }
644 653
645 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { 654 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
646 if (device && device->forceConservativeRasterClip()) { 655 if (device && device->forceConservativeRasterClip()) {
647 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); 656 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
648 } 657 }
649 // Since init() is only called once by our constructors, it is safe to perfo rm this 658 // Since init() is only called once by our constructors, it is safe to perfo rm this
650 // const-cast. 659 // const-cast.
651 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag); 660 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag);
652 661
653 fCachedLocalClipBounds.setEmpty();
654 fCachedLocalClipBoundsDirty = true;
655 fAllowSoftClip = true; 662 fAllowSoftClip = true;
656 fAllowSimplifyClip = false; 663 fAllowSimplifyClip = false;
657 fDeviceCMDirty = true; 664 fDeviceCMDirty = true;
658 fSaveCount = 1; 665 fSaveCount = 1;
659 fMetaData = nullptr; 666 fMetaData = nullptr;
660 #ifdef SK_EXPERIMENTAL_SHADOWING 667 #ifdef SK_EXPERIMENTAL_SHADOWING
661 fLights = nullptr; 668 fLights = nullptr;
662 #endif 669 #endif
663 670
664 fClipStack.reset(new SkClipStack); 671 fClipStack.reset(new SkClipStack);
665 672
666 fMCRec = (MCRec*)fMCStack.push_back(); 673 fMCRec = (MCRec*)fMCStack.push_back();
667 new (fMCRec) MCRec(fConservativeRasterClip); 674 new (fMCRec) MCRec(fConservativeRasterClip);
668 675
669 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); 676 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
670 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; 677 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
671 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip, 678 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip,
672 fMCRec->fMatrix); 679 fMCRec->fMatrix);
673 680
674 fMCRec->fTopLayer = fMCRec->fLayer; 681 fMCRec->fTopLayer = fMCRec->fLayer;
675 682
676 fSurfaceBase = nullptr; 683 fSurfaceBase = nullptr;
677 684
678 if (device) { 685 if (device) {
679 // The root device and the canvas should always have the same pixel geom etry 686 // The root device and the canvas should always have the same pixel geom etry
680 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( )); 687 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( ));
681 fMCRec->fLayer->fDevice = SkRef(device); 688 fMCRec->fLayer->fDevice = SkRef(device);
682 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); 689 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
690 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
691 fConservativeIsScaleTranslate = true;
683 } 692 }
693
684 return device; 694 return device;
685 } 695 }
686 696
687 SkCanvas::SkCanvas() 697 SkCanvas::SkCanvas()
688 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 698 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
689 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) 699 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
690 , fConservativeRasterClip(false) 700 , fConservativeRasterClip(false)
691 { 701 {
692 inc_canvas(); 702 inc_canvas();
693 703
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 } 1098 }
1089 SkIRect ir; 1099 SkIRect ir;
1090 if (bounds) { 1100 if (bounds) {
1091 SkRect r; 1101 SkRect r;
1092 1102
1093 ctm.mapRect(&r, *bounds); 1103 ctm.mapRect(&r, *bounds);
1094 r.roundOut(&ir); 1104 r.roundOut(&ir);
1095 // early exit if the layer's bounds are clipped out 1105 // early exit if the layer's bounds are clipped out
1096 if (!ir.intersect(clipBounds)) { 1106 if (!ir.intersect(clipBounds)) {
1097 if (BoundsAffectsClip(saveLayerFlags)) { 1107 if (BoundsAffectsClip(saveLayerFlags)) {
1098 fCachedLocalClipBoundsDirty = true;
1099 fMCRec->fRasterClip.setEmpty(); 1108 fMCRec->fRasterClip.setEmpty();
1109 fDeviceClipBounds.setEmpty();
1100 } 1110 }
1101 return false; 1111 return false;
1102 } 1112 }
1103 } else { // no user bounds, so just use the clip 1113 } else { // no user bounds, so just use the clip
1104 ir = clipBounds; 1114 ir = clipBounds;
1105 } 1115 }
1106 SkASSERT(!ir.isEmpty()); 1116 SkASSERT(!ir.isEmpty());
1107 1117
1108 if (BoundsAffectsClip(saveLayerFlags)) { 1118 if (BoundsAffectsClip(saveLayerFlags)) {
1109 // Simplify the current clips since they will be applied properly during restore() 1119 // Simplify the current clips since they will be applied properly during restore()
1110 fCachedLocalClipBoundsDirty = true;
1111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); 1120 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
1112 fMCRec->fRasterClip.setRect(ir); 1121 fMCRec->fRasterClip.setRect(ir);
1122 fDeviceClipBounds = qr_clip_bounds(ir);
1113 } 1123 }
1114 1124
1115 if (intersection) { 1125 if (intersection) {
1116 *intersection = ir; 1126 *intersection = ir;
1117 } 1127 }
1118 return true; 1128 return true;
1119 } 1129 }
1120 1130
1121 1131
1122 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 1132 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1294 SkPaint tmpPaint; 1304 SkPaint tmpPaint;
1295 tmpPaint.setAlpha(alpha); 1305 tmpPaint.setAlpha(alpha);
1296 return this->saveLayer(bounds, &tmpPaint); 1306 return this->saveLayer(bounds, &tmpPaint);
1297 } 1307 }
1298 } 1308 }
1299 1309
1300 void SkCanvas::internalRestore() { 1310 void SkCanvas::internalRestore() {
1301 SkASSERT(fMCStack.count() != 0); 1311 SkASSERT(fMCStack.count() != 0);
1302 1312
1303 fDeviceCMDirty = true; 1313 fDeviceCMDirty = true;
1304 fCachedLocalClipBoundsDirty = true;
1305 1314
1306 fClipStack->restore(); 1315 fClipStack->restore();
1307 1316
1308 // reserve our layer (if any) 1317 // reserve our layer (if any)
1309 DeviceCM* layer = fMCRec->fLayer; // may be null 1318 DeviceCM* layer = fMCRec->fLayer; // may be null
1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1319 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1311 fMCRec->fLayer = nullptr; 1320 fMCRec->fLayer = nullptr;
1312 1321
1313 // now do the normal restore() 1322 // now do the normal restore()
1314 fMCRec->~MCRec(); // balanced in save() 1323 fMCRec->~MCRec(); // balanced in save()
(...skipping 13 matching lines...) Expand all
1328 // reset this, since internalDrawDevice will have set it to true 1337 // reset this, since internalDrawDevice will have set it to true
1329 fDeviceCMDirty = true; 1338 fDeviceCMDirty = true;
1330 delete layer; 1339 delete layer;
1331 } else { 1340 } else {
1332 // we're at the root 1341 // we're at the root
1333 SkASSERT(layer == (void*)fDeviceCMStorage); 1342 SkASSERT(layer == (void*)fDeviceCMStorage);
1334 layer->~DeviceCM(); 1343 layer->~DeviceCM();
1335 // no need to update fMCRec, 'cause we're killing the canvas 1344 // no need to update fMCRec, 'cause we're killing the canvas
1336 } 1345 }
1337 } 1346 }
1347
1348 if (fMCRec) {
1349 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1350 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1351 }
1338 } 1352 }
1339 1353
1340 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) { 1354 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) {
1341 if (nullptr == props) { 1355 if (nullptr == props) {
1342 props = &fProps; 1356 props = &fProps;
1343 } 1357 }
1344 return this->onNewSurface(info, *props); 1358 return this->onNewSurface(info, *props);
1345 } 1359 }
1346 1360
1347 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface Props& props) { 1361 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface Props& props) {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
1482 this->concat(m); 1496 this->concat(m);
1483 } 1497 }
1484 1498
1485 void SkCanvas::concat(const SkMatrix& matrix) { 1499 void SkCanvas::concat(const SkMatrix& matrix) {
1486 if (matrix.isIdentity()) { 1500 if (matrix.isIdentity()) {
1487 return; 1501 return;
1488 } 1502 }
1489 1503
1490 this->checkForDeferredSave(); 1504 this->checkForDeferredSave();
1491 fDeviceCMDirty = true; 1505 fDeviceCMDirty = true;
1492 fCachedLocalClipBoundsDirty = true;
1493 fMCRec->fMatrix.preConcat(matrix); 1506 fMCRec->fMatrix.preConcat(matrix);
1494 1507
1508 // We may miss some rare cases here. Ex: rotate 45 then -45. But being dat a
1509 // independ of preConcat() may allow us to go faster.
mtklein 2016/08/11 20:19:12 independ -> independent Did this actually help?
msarett 2016/08/11 21:11:57 Added a bench for concat and dropped this optimiza
1510 fConservativeIsScaleTranslate = fConservativeIsScaleTranslate && matrix.isSc aleTranslate();
1495 this->didConcat(matrix); 1511 this->didConcat(matrix);
1496 } 1512 }
1497 1513
1498 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { 1514 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1499 fDeviceCMDirty = true; 1515 fDeviceCMDirty = true;
1500 fCachedLocalClipBoundsDirty = true;
1501 fMCRec->fMatrix = matrix; 1516 fMCRec->fMatrix = matrix;
1502 } 1517 }
1503 1518
1504 void SkCanvas::setMatrix(const SkMatrix& matrix) { 1519 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1505 this->checkForDeferredSave(); 1520 this->checkForDeferredSave();
1506 this->internalSetMatrix(matrix); 1521 this->internalSetMatrix(matrix);
1522 fConservativeIsScaleTranslate = matrix.isScaleTranslate();
1507 this->didSetMatrix(matrix); 1523 this->didSetMatrix(matrix);
1508 } 1524 }
1509 1525
1510 void SkCanvas::resetMatrix() { 1526 void SkCanvas::resetMatrix() {
1511 this->setMatrix(SkMatrix::I()); 1527 this->setMatrix(SkMatrix::I());
1512 } 1528 }
1513 1529
1514 #ifdef SK_EXPERIMENTAL_SHADOWING 1530 #ifdef SK_EXPERIMENTAL_SHADOWING
1515 void SkCanvas::translateZ(SkScalar z) { 1531 void SkCanvas::translateZ(SkScalar z) {
1516 this->checkForDeferredSave(); 1532 this->checkForDeferredSave();
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
1597 rect.left(), rect.top(), rect.right(), rect.bottom()); 1613 rect.left(), rect.top(), rect.right(), rect.bottom());
1598 #endif 1614 #endif
1599 return; 1615 return;
1600 } 1616 }
1601 } 1617 }
1602 #endif 1618 #endif
1603 1619
1604 AutoValidateClip avc(this); 1620 AutoValidateClip avc(this);
1605 1621
1606 fDeviceCMDirty = true; 1622 fDeviceCMDirty = true;
1607 fCachedLocalClipBoundsDirty = true;
1608 1623
1609 if (isScaleTrans) { 1624 if (isScaleTrans) {
1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1625 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1611 fClipStack->clipDevRect(devR, op, isAA); 1626 fClipStack->clipDevRect(devR, op, isAA);
1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); 1627 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
1613 } else { 1628 } else {
1614 // since we're rotated or some such thing, we convert the rect to a path 1629 // since we're rotated or some such thing, we convert the rect to a path
1615 // and clip against that, since it can handle any matrix. However, to 1630 // and clip against that, since it can handle any matrix. However, to
1616 // avoid recursion in the case where we are subclassed (e.g. Pictures) 1631 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1617 // we explicitly call "our" version of clipPath. 1632 // we explicitly call "our" version of clipPath.
1618 SkPath path; 1633 SkPath path;
1619 1634
1620 path.addRect(rect); 1635 path.addRect(rect);
1621 this->SkCanvas::onClipPath(path, op, edgeStyle); 1636 this->SkCanvas::onClipPath(path, op, edgeStyle);
1622 } 1637 }
1638
1639 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1623 } 1640 }
1624 1641
1625 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1642 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1626 this->checkForDeferredSave(); 1643 this->checkForDeferredSave();
1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1644 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1628 if (rrect.isRect()) { 1645 if (rrect.isRect()) {
1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1646 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1630 } else { 1647 } else {
1631 this->onClipRRect(rrect, op, edgeStyle); 1648 this->onClipRRect(rrect, op, edgeStyle);
1632 } 1649 }
1633 } 1650 }
1634 1651
1635 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1652 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1636 SkRRect transformedRRect; 1653 SkRRect transformedRRect;
1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { 1654 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1638 AutoValidateClip avc(this); 1655 AutoValidateClip avc(this);
1639 1656
1640 fDeviceCMDirty = true; 1657 fDeviceCMDirty = true;
1641 fCachedLocalClipBoundsDirty = true;
1642 if (!fAllowSoftClip) { 1658 if (!fAllowSoftClip) {
1643 edgeStyle = kHard_ClipEdgeStyle; 1659 edgeStyle = kHard_ClipEdgeStyle;
1644 } 1660 }
1645 1661
1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle); 1662 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle);
1647 1663
1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, 1664 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
1649 kSoft_ClipEdgeStyle == edgeStyle); 1665 kSoft_ClipEdgeStyle == edgeStyle);
1666 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1650 return; 1667 return;
1651 } 1668 }
1652 1669
1653 SkPath path; 1670 SkPath path;
1654 path.addRRect(rrect); 1671 path.addRRect(rrect);
1655 // call the non-virtual version 1672 // call the non-virtual version
1656 this->SkCanvas::onClipPath(path, op, edgeStyle); 1673 this->SkCanvas::onClipPath(path, op, edgeStyle);
1657 } 1674 }
1658 1675
1659 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1676 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1695 fClipStack->clipEmpty(); 1712 fClipStack->clipEmpty();
1696 (void)fMCRec->fRasterClip.setEmpty(); 1713 (void)fMCRec->fRasterClip.setEmpty();
1697 return; 1714 return;
1698 } 1715 }
1699 } 1716 }
1700 #endif 1717 #endif
1701 1718
1702 AutoValidateClip avc(this); 1719 AutoValidateClip avc(this);
1703 1720
1704 fDeviceCMDirty = true; 1721 fDeviceCMDirty = true;
1705 fCachedLocalClipBoundsDirty = true;
1706 if (!fAllowSoftClip) { 1722 if (!fAllowSoftClip) {
1707 edgeStyle = kHard_ClipEdgeStyle; 1723 edgeStyle = kHard_ClipEdgeStyle;
1708 } 1724 }
1709 1725
1710 SkPath devPath; 1726 SkPath devPath;
1711 path.transform(fMCRec->fMatrix, &devPath); 1727 path.transform(fMCRec->fMatrix, &devPath);
1712 1728
1713 // Check if the transfomation, or the original path itself 1729 // Check if the transfomation, or the original path itself
1714 // made us empty. Note this can also happen if we contained NaN 1730 // made us empty. Note this can also happen if we contained NaN
1715 // values. computing the bounds detects this, and will set our 1731 // values. computing the bounds detects this, and will set our
(...skipping 10 matching lines...) Expand all
1726 if (fAllowSimplifyClip) { 1742 if (fAllowSimplifyClip) {
1727 bool clipIsAA = getClipStack()->asPath(&devPath); 1743 bool clipIsAA = getClipStack()->asPath(&devPath);
1728 if (clipIsAA) { 1744 if (clipIsAA) {
1729 edgeStyle = kSoft_ClipEdgeStyle; 1745 edgeStyle = kSoft_ClipEdgeStyle;
1730 } 1746 }
1731 1747
1732 op = SkRegion::kReplace_Op; 1748 op = SkRegion::kReplace_Op;
1733 } 1749 }
1734 1750
1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); 1751 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
1752 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1736 } 1753 }
1737 1754
1738 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1755 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1739 this->checkForDeferredSave(); 1756 this->checkForDeferredSave();
1740 this->onClipRegion(rgn, op); 1757 this->onClipRegion(rgn, op);
1741 } 1758 }
1742 1759
1743 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1760 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1744 AutoValidateClip avc(this); 1761 AutoValidateClip avc(this);
1745 1762
1746 fDeviceCMDirty = true; 1763 fDeviceCMDirty = true;
1747 fCachedLocalClipBoundsDirty = true;
1748 1764
1749 // todo: signal fClipStack that we have a region, and therefore (I guess) 1765 // todo: signal fClipStack that we have a region, and therefore (I guess)
1750 // we have to ignore it, and use the region directly? 1766 // we have to ignore it, and use the region directly?
1751 fClipStack->clipDevRect(rgn.getBounds(), op); 1767 fClipStack->clipDevRect(rgn.getBounds(), op);
1752 1768
1753 fMCRec->fRasterClip.op(rgn, op); 1769 fMCRec->fRasterClip.op(rgn, op);
1770 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1754 } 1771 }
1755 1772
1756 #ifdef SK_DEBUG 1773 #ifdef SK_DEBUG
1757 void SkCanvas::validateClip() const { 1774 void SkCanvas::validateClip() const {
1758 // construct clipRgn from the clipstack 1775 // construct clipRgn from the clipstack
1759 const SkBaseDevice* device = this->getDevice(); 1776 const SkBaseDevice* device = this->getDevice();
1760 if (!device) { 1777 if (!device) {
1761 SkASSERT(this->isClipEmpty()); 1778 SkASSERT(this->isClipEmpty());
1762 return; 1779 return;
1763 } 1780 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1800 /////////////////////////////////////////////////////////////////////////////// 1817 ///////////////////////////////////////////////////////////////////////////////
1801 1818
1802 bool SkCanvas::isClipEmpty() const { 1819 bool SkCanvas::isClipEmpty() const {
1803 return fMCRec->fRasterClip.isEmpty(); 1820 return fMCRec->fRasterClip.isEmpty();
1804 } 1821 }
1805 1822
1806 bool SkCanvas::isClipRect() const { 1823 bool SkCanvas::isClipRect() const {
1807 return fMCRec->fRasterClip.isRect(); 1824 return fMCRec->fRasterClip.isRect();
1808 } 1825 }
1809 1826
1810 bool SkCanvas::quickReject(const SkRect& rect) const { 1827 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1811 if (!rect.isFinite()) 1828 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1812 return true; 1829 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1830 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1831 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1832 return 0xF != _mm_movemask_ps(mask);
1833 #elif defined(SK_ARM_HAS_NEON)
1834 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1835 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1836 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1837 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1838 #else
1839 SkRect devRectAsRect;
1840 SkRect devClipAsRect;
1841 devRect.store(&devRectAsRect.fLeft);
1842 devClip.store(&devClipAsRect.fLeft);
1843 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1844 #endif
1845 }
1813 1846
1814 if (fMCRec->fRasterClip.isEmpty()) { 1847 // It's important for this function to not be inlined. Otherwise the compiler w ill share code
1815 return true; 1848 // between the fast path and the slow path, resulting in two slow paths.
1849 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRe ct& deviceClip,
1850 const SkMatrix& matrix) {
1851 SkRect deviceRect;
1852 matrix.mapRect(&deviceRect, src);
1853 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1854 }
1855
1856 bool SkCanvas::quickReject(const SkRect& src) const {
1857 #ifdef SK_DEBUG
1858 // Verify that fDeviceClipBounds are set properly.
1859 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1860 SkASSERT(tmp == fDeviceClipBounds);
1861
1862 // Verify that fConservativeIsScaleTranslate is set properly.
1863 SkASSERT(!fConservativeIsScaleTranslate || fMCRec->fMatrix.isScaleTranslate( ));
1864 #endif
1865
1866 if (!fConservativeIsScaleTranslate) {
1867 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1816 } 1868 }
1817 1869
1818 if (fMCRec->fMatrix.hasPerspective()) { 1870 // We inline the implementation of mapScaleTranslate() for the fast path.
1819 SkRect dst; 1871 float sx = fMCRec->fMatrix.getScaleX();
1820 fMCRec->fMatrix.mapRect(&dst, rect); 1872 float sy = fMCRec->fMatrix.getScaleY();
1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBound s()); 1873 float tx = fMCRec->fMatrix.getTranslateX();
1822 } else { 1874 float ty = fMCRec->fMatrix.getTranslateY();
1823 const SkRect& clipR = this->getLocalClipBounds(); 1875 Sk4f scale(sx, sy, sx, sy);
1876 Sk4f trans(tx, ty, tx, ty);
1824 1877
1825 // for speed, do the most likely reject compares first 1878 // Apply matrix.
1826 // TODO: should we use | instead, or compare all 4 at once? 1879 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1880
1828 return true; 1881 // Make sure left < right, top < bottom.
1829 } 1882 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1883 Sk4f min = Sk4f::Min(ltrb, rblt);
1831 return true; 1884 Sk4f max = Sk4f::Max(ltrb, rblt);
1832 } 1885 // We can extract either pair [0,1] or [2,3] from min and max and be correct , but on
1833 return false; 1886 // ARM this sequence generates the fastest (a single instruction).
1834 } 1887 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1888
1889 // Check if the device rect is NaN or outside the clip.
1890 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1835 } 1891 }
1836 1892
1837 bool SkCanvas::quickReject(const SkPath& path) const { 1893 bool SkCanvas::quickReject(const SkPath& path) const {
1838 return path.isEmpty() || this->quickReject(path.getBounds()); 1894 return path.isEmpty() || this->quickReject(path.getBounds());
1839 } 1895 }
1840 1896
1841 bool SkCanvas::getClipBounds(SkRect* bounds) const { 1897 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1842 SkIRect ibounds; 1898 SkIRect ibounds;
1843 if (!this->getClipDeviceBounds(&ibounds)) { 1899 if (!this->getClipDeviceBounds(&ibounds)) {
1844 return false; 1900 return false;
(...skipping 1323 matching lines...) Expand 10 before | Expand all | Expand 10 after
3168 3224
3169 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 3225 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3170 fCanvas->restoreToCount(fSaveCount); 3226 fCanvas->restoreToCount(fSaveCount);
3171 } 3227 }
3172 3228
3173 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API 3229 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3174 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) { 3230 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) {
3175 return this->makeSurface(info, props).release(); 3231 return this->makeSurface(info, props).release();
3176 } 3232 }
3177 #endif 3233 #endif
OLDNEW
« no previous file with comments | « include/core/SkPostConfig.h ('k') | tests/QuickRejectTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698