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

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: Fix NX_NOSIMD and Chrome assert 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 if (bounds.isEmpty()) {
636 return SkRect::MakeEmpty();
637 }
638
639 // Expand bounds out by 1 in case we are anti-aliasing. We store the
640 // bounds as floats to enable a faster quick reject implementation.
641 SkRect dst;
642 SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLe ft);
643 return dst;
644 }
645
633 void SkCanvas::resetForNextPicture(const SkIRect& bounds) { 646 void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
634 this->restoreToCount(1); 647 this->restoreToCount(1);
635 fCachedLocalClipBounds.setEmpty();
636 fCachedLocalClipBoundsDirty = true;
637 fClipStack->reset(); 648 fClipStack->reset();
638 fMCRec->reset(bounds); 649 fMCRec->reset(bounds);
639 650
640 // We're peering through a lot of structs here. Only at this scope do we 651 // 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). 652 // know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevi ce).
642 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e()); 653 static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.siz e());
654 fDeviceClipBounds = qr_clip_bounds(bounds);
655 fConservativeIsScaleTranslate = true;
643 } 656 }
644 657
645 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) { 658 SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
646 if (device && device->forceConservativeRasterClip()) { 659 if (device && device->forceConservativeRasterClip()) {
647 flags = InitFlags(flags | kConservativeRasterClip_InitFlag); 660 flags = InitFlags(flags | kConservativeRasterClip_InitFlag);
648 } 661 }
649 // Since init() is only called once by our constructors, it is safe to perfo rm this 662 // Since init() is only called once by our constructors, it is safe to perfo rm this
650 // const-cast. 663 // const-cast.
651 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag); 664 *const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativ eRasterClip_InitFlag);
652 665
653 fCachedLocalClipBounds.setEmpty();
654 fCachedLocalClipBoundsDirty = true;
655 fAllowSoftClip = true; 666 fAllowSoftClip = true;
656 fAllowSimplifyClip = false; 667 fAllowSimplifyClip = false;
657 fDeviceCMDirty = true; 668 fDeviceCMDirty = true;
658 fSaveCount = 1; 669 fSaveCount = 1;
659 fMetaData = nullptr; 670 fMetaData = nullptr;
660 #ifdef SK_EXPERIMENTAL_SHADOWING 671 #ifdef SK_EXPERIMENTAL_SHADOWING
661 fLights = nullptr; 672 fLights = nullptr;
662 #endif 673 #endif
663 674
664 fClipStack.reset(new SkClipStack); 675 fClipStack.reset(new SkClipStack);
665 676
666 fMCRec = (MCRec*)fMCStack.push_back(); 677 fMCRec = (MCRec*)fMCStack.push_back();
667 new (fMCRec) MCRec(fConservativeRasterClip); 678 new (fMCRec) MCRec(fConservativeRasterClip);
668 679
669 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); 680 SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage));
670 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; 681 fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage;
671 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip, 682 new (fDeviceCMStorage) DeviceCM(nullptr, nullptr, nullptr, fConservativeRast erClip,
672 fMCRec->fMatrix); 683 fMCRec->fMatrix);
673 684
674 fMCRec->fTopLayer = fMCRec->fLayer; 685 fMCRec->fTopLayer = fMCRec->fLayer;
675 686
676 fSurfaceBase = nullptr; 687 fSurfaceBase = nullptr;
677 688
678 if (device) { 689 if (device) {
679 // The root device and the canvas should always have the same pixel geom etry 690 // The root device and the canvas should always have the same pixel geom etry
680 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( )); 691 SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry( ));
681 fMCRec->fLayer->fDevice = SkRef(device); 692 fMCRec->fLayer->fDevice = SkRef(device);
682 fMCRec->fRasterClip.setRect(device->getGlobalBounds()); 693 fMCRec->fRasterClip.setRect(device->getGlobalBounds());
694 fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
695 fConservativeIsScaleTranslate = true;
683 } 696 }
697
684 return device; 698 return device;
685 } 699 }
686 700
687 SkCanvas::SkCanvas() 701 SkCanvas::SkCanvas()
688 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) 702 : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
689 , fProps(SkSurfaceProps::kLegacyFontHost_InitType) 703 , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
690 , fConservativeRasterClip(false) 704 , fConservativeRasterClip(false)
691 { 705 {
692 inc_canvas(); 706 inc_canvas();
693 707
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 } 1102 }
1089 SkIRect ir; 1103 SkIRect ir;
1090 if (bounds) { 1104 if (bounds) {
1091 SkRect r; 1105 SkRect r;
1092 1106
1093 ctm.mapRect(&r, *bounds); 1107 ctm.mapRect(&r, *bounds);
1094 r.roundOut(&ir); 1108 r.roundOut(&ir);
1095 // early exit if the layer's bounds are clipped out 1109 // early exit if the layer's bounds are clipped out
1096 if (!ir.intersect(clipBounds)) { 1110 if (!ir.intersect(clipBounds)) {
1097 if (BoundsAffectsClip(saveLayerFlags)) { 1111 if (BoundsAffectsClip(saveLayerFlags)) {
1098 fCachedLocalClipBoundsDirty = true;
1099 fMCRec->fRasterClip.setEmpty(); 1112 fMCRec->fRasterClip.setEmpty();
1113 fDeviceClipBounds.setEmpty();
1100 } 1114 }
1101 return false; 1115 return false;
1102 } 1116 }
1103 } else { // no user bounds, so just use the clip 1117 } else { // no user bounds, so just use the clip
1104 ir = clipBounds; 1118 ir = clipBounds;
1105 } 1119 }
1106 SkASSERT(!ir.isEmpty()); 1120 SkASSERT(!ir.isEmpty());
1107 1121
1108 if (BoundsAffectsClip(saveLayerFlags)) { 1122 if (BoundsAffectsClip(saveLayerFlags)) {
1109 // Simplify the current clips since they will be applied properly during restore() 1123 // Simplify the current clips since they will be applied properly during restore()
1110 fCachedLocalClipBoundsDirty = true;
1111 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op); 1124 fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
1112 fMCRec->fRasterClip.setRect(ir); 1125 fMCRec->fRasterClip.setRect(ir);
1126 fDeviceClipBounds = qr_clip_bounds(ir);
1113 } 1127 }
1114 1128
1115 if (intersection) { 1129 if (intersection) {
1116 *intersection = ir; 1130 *intersection = ir;
1117 } 1131 }
1118 return true; 1132 return true;
1119 } 1133 }
1120 1134
1121 1135
1122 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) { 1136 int SkCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint) {
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
1294 SkPaint tmpPaint; 1308 SkPaint tmpPaint;
1295 tmpPaint.setAlpha(alpha); 1309 tmpPaint.setAlpha(alpha);
1296 return this->saveLayer(bounds, &tmpPaint); 1310 return this->saveLayer(bounds, &tmpPaint);
1297 } 1311 }
1298 } 1312 }
1299 1313
1300 void SkCanvas::internalRestore() { 1314 void SkCanvas::internalRestore() {
1301 SkASSERT(fMCStack.count() != 0); 1315 SkASSERT(fMCStack.count() != 0);
1302 1316
1303 fDeviceCMDirty = true; 1317 fDeviceCMDirty = true;
1304 fCachedLocalClipBoundsDirty = true;
1305 1318
1306 fClipStack->restore(); 1319 fClipStack->restore();
1307 1320
1308 // reserve our layer (if any) 1321 // reserve our layer (if any)
1309 DeviceCM* layer = fMCRec->fLayer; // may be null 1322 DeviceCM* layer = fMCRec->fLayer; // may be null
1310 // now detach it from fMCRec so we can pop(). Gets freed after its drawn 1323 // now detach it from fMCRec so we can pop(). Gets freed after its drawn
1311 fMCRec->fLayer = nullptr; 1324 fMCRec->fLayer = nullptr;
1312 1325
1313 // now do the normal restore() 1326 // now do the normal restore()
1314 fMCRec->~MCRec(); // balanced in save() 1327 fMCRec->~MCRec(); // balanced in save()
(...skipping 13 matching lines...) Expand all
1328 // reset this, since internalDrawDevice will have set it to true 1341 // reset this, since internalDrawDevice will have set it to true
1329 fDeviceCMDirty = true; 1342 fDeviceCMDirty = true;
1330 delete layer; 1343 delete layer;
1331 } else { 1344 } else {
1332 // we're at the root 1345 // we're at the root
1333 SkASSERT(layer == (void*)fDeviceCMStorage); 1346 SkASSERT(layer == (void*)fDeviceCMStorage);
1334 layer->~DeviceCM(); 1347 layer->~DeviceCM();
1335 // no need to update fMCRec, 'cause we're killing the canvas 1348 // no need to update fMCRec, 'cause we're killing the canvas
1336 } 1349 }
1337 } 1350 }
1351
1352 if (fMCRec) {
1353 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1354 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1355 }
1338 } 1356 }
1339 1357
1340 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) { 1358 sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceP rops* props) {
1341 if (nullptr == props) { 1359 if (nullptr == props) {
1342 props = &fProps; 1360 props = &fProps;
1343 } 1361 }
1344 return this->onNewSurface(info, *props); 1362 return this->onNewSurface(info, *props);
1345 } 1363 }
1346 1364
1347 sk_sp<SkSurface> SkCanvas::onNewSurface(const SkImageInfo& info, const SkSurface Props& props) { 1365 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); 1500 this->concat(m);
1483 } 1501 }
1484 1502
1485 void SkCanvas::concat(const SkMatrix& matrix) { 1503 void SkCanvas::concat(const SkMatrix& matrix) {
1486 if (matrix.isIdentity()) { 1504 if (matrix.isIdentity()) {
1487 return; 1505 return;
1488 } 1506 }
1489 1507
1490 this->checkForDeferredSave(); 1508 this->checkForDeferredSave();
1491 fDeviceCMDirty = true; 1509 fDeviceCMDirty = true;
1492 fCachedLocalClipBoundsDirty = true;
1493 fMCRec->fMatrix.preConcat(matrix); 1510 fMCRec->fMatrix.preConcat(matrix);
1494 1511 fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1495 this->didConcat(matrix); 1512 this->didConcat(matrix);
1496 } 1513 }
1497 1514
1498 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { 1515 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1499 fDeviceCMDirty = true; 1516 fDeviceCMDirty = true;
1500 fCachedLocalClipBoundsDirty = true;
1501 fMCRec->fMatrix = matrix; 1517 fMCRec->fMatrix = matrix;
1502 } 1518 }
1503 1519
1504 void SkCanvas::setMatrix(const SkMatrix& matrix) { 1520 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1505 this->checkForDeferredSave(); 1521 this->checkForDeferredSave();
1506 this->internalSetMatrix(matrix); 1522 this->internalSetMatrix(matrix);
1523 fConservativeIsScaleTranslate = matrix.isScaleTranslate();
1507 this->didSetMatrix(matrix); 1524 this->didSetMatrix(matrix);
1508 } 1525 }
1509 1526
1510 void SkCanvas::resetMatrix() { 1527 void SkCanvas::resetMatrix() {
1511 this->setMatrix(SkMatrix::I()); 1528 this->setMatrix(SkMatrix::I());
1512 } 1529 }
1513 1530
1514 #ifdef SK_EXPERIMENTAL_SHADOWING 1531 #ifdef SK_EXPERIMENTAL_SHADOWING
1515 void SkCanvas::translateZ(SkScalar z) { 1532 void SkCanvas::translateZ(SkScalar z) {
1516 this->checkForDeferredSave(); 1533 this->checkForDeferredSave();
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 if (fMCRec->fRasterClip.isEmpty()) { 1585 if (fMCRec->fRasterClip.isEmpty()) {
1569 return; 1586 return;
1570 } 1587 }
1571 1588
1572 if (this->quickReject(rect)) { 1589 if (this->quickReject(rect)) {
1573 fDeviceCMDirty = true; 1590 fDeviceCMDirty = true;
1574 fCachedLocalClipBoundsDirty = true; 1591 fCachedLocalClipBoundsDirty = true;
1575 1592
1576 fClipStack->clipEmpty(); 1593 fClipStack->clipEmpty();
1577 (void)fMCRec->fRasterClip.setEmpty(); 1594 (void)fMCRec->fRasterClip.setEmpty();
1595 fDeviceClipBounds.setEmpty();
1578 return; 1596 return;
1579 } 1597 }
1580 } 1598 }
1581 #endif 1599 #endif
1582 1600
1583 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate(); 1601 const bool isScaleTrans = fMCRec->fMatrix.isScaleTranslate();
1584 SkRect devR; 1602 SkRect devR;
1585 if (isScaleTrans) { 1603 if (isScaleTrans) {
1586 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect); 1604 fMCRec->fMatrix.mapRectScaleTranslate(&devR, rect);
1587 } 1605 }
1588 1606
1589 #ifndef SK_SUPPORT_PRECHECK_CLIPRECT 1607 #ifndef SK_SUPPORT_PRECHECK_CLIPRECT
1590 if (SkRegion::kIntersect_Op == op && 1608 if (SkRegion::kIntersect_Op == op &&
1591 kHard_ClipEdgeStyle == edgeStyle 1609 kHard_ClipEdgeStyle == edgeStyle
1592 && isScaleTrans) 1610 && isScaleTrans)
1593 { 1611 {
1594 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) { 1612 if (devR.round().contains(fMCRec->fRasterClip.getBounds())) {
1595 #if 0 1613 #if 0
1596 SkDebugf("------- ignored clipRect [%g %g %g %g]\n", 1614 SkDebugf("------- ignored clipRect [%g %g %g %g]\n",
1597 rect.left(), rect.top(), rect.right(), rect.bottom()); 1615 rect.left(), rect.top(), rect.right(), rect.bottom());
1598 #endif 1616 #endif
1599 return; 1617 return;
1600 } 1618 }
1601 } 1619 }
1602 #endif 1620 #endif
1603 1621
1604 AutoValidateClip avc(this); 1622 AutoValidateClip avc(this);
1605 1623
1606 fDeviceCMDirty = true; 1624 fDeviceCMDirty = true;
1607 fCachedLocalClipBoundsDirty = true;
1608 1625
1609 if (isScaleTrans) { 1626 if (isScaleTrans) {
1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1627 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1611 fClipStack->clipDevRect(devR, op, isAA); 1628 fClipStack->clipDevRect(devR, op, isAA);
1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); 1629 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
1613 } else { 1630 } else {
1614 // since we're rotated or some such thing, we convert the rect to a path 1631 // 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 1632 // 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) 1633 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1617 // we explicitly call "our" version of clipPath. 1634 // we explicitly call "our" version of clipPath.
1618 SkPath path; 1635 SkPath path;
1619 1636
1620 path.addRect(rect); 1637 path.addRect(rect);
1621 this->SkCanvas::onClipPath(path, op, edgeStyle); 1638 this->SkCanvas::onClipPath(path, op, edgeStyle);
1622 } 1639 }
1640
1641 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1623 } 1642 }
1624 1643
1625 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1644 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1626 this->checkForDeferredSave(); 1645 this->checkForDeferredSave();
1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1646 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1628 if (rrect.isRect()) { 1647 if (rrect.isRect()) {
1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1648 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1630 } else { 1649 } else {
1631 this->onClipRRect(rrect, op, edgeStyle); 1650 this->onClipRRect(rrect, op, edgeStyle);
1632 } 1651 }
1633 } 1652 }
1634 1653
1635 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1654 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1636 SkRRect transformedRRect; 1655 SkRRect transformedRRect;
1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { 1656 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1638 AutoValidateClip avc(this); 1657 AutoValidateClip avc(this);
1639 1658
1640 fDeviceCMDirty = true; 1659 fDeviceCMDirty = true;
1641 fCachedLocalClipBoundsDirty = true;
1642 if (!fAllowSoftClip) { 1660 if (!fAllowSoftClip) {
1643 edgeStyle = kHard_ClipEdgeStyle; 1661 edgeStyle = kHard_ClipEdgeStyle;
1644 } 1662 }
1645 1663
1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle); 1664 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle);
1647 1665
1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, 1666 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
1649 kSoft_ClipEdgeStyle == edgeStyle); 1667 kSoft_ClipEdgeStyle == edgeStyle);
1668 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1650 return; 1669 return;
1651 } 1670 }
1652 1671
1653 SkPath path; 1672 SkPath path;
1654 path.addRRect(rrect); 1673 path.addRRect(rrect);
1655 // call the non-virtual version 1674 // call the non-virtual version
1656 this->SkCanvas::onClipPath(path, op, edgeStyle); 1675 this->SkCanvas::onClipPath(path, op, edgeStyle);
1657 } 1676 }
1658 1677
1659 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1678 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
(...skipping 27 matching lines...) Expand all
1687 if (fMCRec->fRasterClip.isEmpty()) { 1706 if (fMCRec->fRasterClip.isEmpty()) {
1688 return; 1707 return;
1689 } 1708 }
1690 1709
1691 if (this->quickReject(path.getBounds())) { 1710 if (this->quickReject(path.getBounds())) {
1692 fDeviceCMDirty = true; 1711 fDeviceCMDirty = true;
1693 fCachedLocalClipBoundsDirty = true; 1712 fCachedLocalClipBoundsDirty = true;
1694 1713
1695 fClipStack->clipEmpty(); 1714 fClipStack->clipEmpty();
1696 (void)fMCRec->fRasterClip.setEmpty(); 1715 (void)fMCRec->fRasterClip.setEmpty();
1716 fDeviceClipBounds.setEmpty();
1697 return; 1717 return;
1698 } 1718 }
1699 } 1719 }
1700 #endif 1720 #endif
1701 1721
1702 AutoValidateClip avc(this); 1722 AutoValidateClip avc(this);
1703 1723
1704 fDeviceCMDirty = true; 1724 fDeviceCMDirty = true;
1705 fCachedLocalClipBoundsDirty = true;
1706 if (!fAllowSoftClip) { 1725 if (!fAllowSoftClip) {
1707 edgeStyle = kHard_ClipEdgeStyle; 1726 edgeStyle = kHard_ClipEdgeStyle;
1708 } 1727 }
1709 1728
1710 SkPath devPath; 1729 SkPath devPath;
1711 path.transform(fMCRec->fMatrix, &devPath); 1730 path.transform(fMCRec->fMatrix, &devPath);
1712 1731
1713 // Check if the transfomation, or the original path itself 1732 // Check if the transfomation, or the original path itself
1714 // made us empty. Note this can also happen if we contained NaN 1733 // made us empty. Note this can also happen if we contained NaN
1715 // values. computing the bounds detects this, and will set our 1734 // values. computing the bounds detects this, and will set our
(...skipping 10 matching lines...) Expand all
1726 if (fAllowSimplifyClip) { 1745 if (fAllowSimplifyClip) {
1727 bool clipIsAA = getClipStack()->asPath(&devPath); 1746 bool clipIsAA = getClipStack()->asPath(&devPath);
1728 if (clipIsAA) { 1747 if (clipIsAA) {
1729 edgeStyle = kSoft_ClipEdgeStyle; 1748 edgeStyle = kSoft_ClipEdgeStyle;
1730 } 1749 }
1731 1750
1732 op = SkRegion::kReplace_Op; 1751 op = SkRegion::kReplace_Op;
1733 } 1752 }
1734 1753
1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); 1754 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
1755 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1736 } 1756 }
1737 1757
1738 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1758 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1739 this->checkForDeferredSave(); 1759 this->checkForDeferredSave();
1740 this->onClipRegion(rgn, op); 1760 this->onClipRegion(rgn, op);
1741 } 1761 }
1742 1762
1743 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1763 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1744 AutoValidateClip avc(this); 1764 AutoValidateClip avc(this);
1745 1765
1746 fDeviceCMDirty = true; 1766 fDeviceCMDirty = true;
1747 fCachedLocalClipBoundsDirty = true;
1748 1767
1749 // todo: signal fClipStack that we have a region, and therefore (I guess) 1768 // todo: signal fClipStack that we have a region, and therefore (I guess)
1750 // we have to ignore it, and use the region directly? 1769 // we have to ignore it, and use the region directly?
1751 fClipStack->clipDevRect(rgn.getBounds(), op); 1770 fClipStack->clipDevRect(rgn.getBounds(), op);
1752 1771
1753 fMCRec->fRasterClip.op(rgn, op); 1772 fMCRec->fRasterClip.op(rgn, op);
1773 fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1754 } 1774 }
1755 1775
1756 #ifdef SK_DEBUG 1776 #ifdef SK_DEBUG
1757 void SkCanvas::validateClip() const { 1777 void SkCanvas::validateClip() const {
1758 // construct clipRgn from the clipstack 1778 // construct clipRgn from the clipstack
1759 const SkBaseDevice* device = this->getDevice(); 1779 const SkBaseDevice* device = this->getDevice();
1760 if (!device) { 1780 if (!device) {
1761 SkASSERT(this->isClipEmpty()); 1781 SkASSERT(this->isClipEmpty());
1762 return; 1782 return;
1763 } 1783 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1800 /////////////////////////////////////////////////////////////////////////////// 1820 ///////////////////////////////////////////////////////////////////////////////
1801 1821
1802 bool SkCanvas::isClipEmpty() const { 1822 bool SkCanvas::isClipEmpty() const {
1803 return fMCRec->fRasterClip.isEmpty(); 1823 return fMCRec->fRasterClip.isEmpty();
1804 } 1824 }
1805 1825
1806 bool SkCanvas::isClipRect() const { 1826 bool SkCanvas::isClipRect() const {
1807 return fMCRec->fRasterClip.isRect(); 1827 return fMCRec->fRasterClip.isRect();
1808 } 1828 }
1809 1829
1810 bool SkCanvas::quickReject(const SkRect& rect) const { 1830 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1811 if (!rect.isFinite()) 1831 #if !defined(SKNX_NO_SIMD) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1812 return true; 1832 __m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
1833 __m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1834 __m128 mask = _mm_cmplt_ps(lLtT, RrBb);
1835 return 0xF != _mm_movemask_ps(mask);
1836 #elif !defined(SKNX_NO_SIMD) && defined(SK_ARM_HAS_NEON)
1837 float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1838 float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1839 uint32x4_t mask = vcltq_f32(lLtT, RrBb);
1840 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1841 #else
1842 SkRect devRectAsRect;
1843 SkRect devClipAsRect;
1844 devRect.store(&devRectAsRect.fLeft);
1845 devClip.store(&devClipAsRect.fLeft);
1846 return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
1847 #endif
1848 }
1813 1849
1850 // It's important for this function to not be inlined. Otherwise the compiler w ill share code
1851 // between the fast path and the slow path, resulting in two slow paths.
1852 static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRe ct& deviceClip,
1853 const SkMatrix& matrix) {
1854 SkRect deviceRect;
1855 matrix.mapRect(&deviceRect, src);
1856 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1857 }
1858
1859 bool SkCanvas::quickReject(const SkRect& src) const {
1860 #ifdef SK_DEBUG
1861 // Verify that fDeviceClipBounds are set properly.
1862 SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
1814 if (fMCRec->fRasterClip.isEmpty()) { 1863 if (fMCRec->fRasterClip.isEmpty()) {
1815 return true; 1864 SkASSERT(fDeviceClipBounds.isEmpty() || tmp == fDeviceClipBounds);
1865 } else {
1866 SkASSERT(tmp == fDeviceClipBounds);
1816 } 1867 }
1817 1868
1818 if (fMCRec->fMatrix.hasPerspective()) { 1869 // Verify that fConservativeIsScaleTranslate is set properly.
1819 SkRect dst; 1870 SkASSERT(!fConservativeIsScaleTranslate || fMCRec->fMatrix.isScaleTranslate( ));
1820 fMCRec->fMatrix.mapRect(&dst, rect); 1871 #endif
1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBound s());
1822 } else {
1823 const SkRect& clipR = this->getLocalClipBounds();
1824 1872
1825 // for speed, do the most likely reject compares first 1873 if (!fConservativeIsScaleTranslate) {
1826 // TODO: should we use | instead, or compare all 4 at once? 1874 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
1828 return true;
1829 }
1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
1831 return true;
1832 }
1833 return false;
1834 } 1875 }
1876
1877 // We inline the implementation of mapScaleTranslate() for the fast path.
1878 float sx = fMCRec->fMatrix.getScaleX();
1879 float sy = fMCRec->fMatrix.getScaleY();
1880 float tx = fMCRec->fMatrix.getTranslateX();
1881 float ty = fMCRec->fMatrix.getTranslateY();
1882 Sk4f scale(sx, sy, sx, sy);
1883 Sk4f trans(tx, ty, tx, ty);
1884
1885 // Apply matrix.
1886 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1887
1888 // Make sure left < right, top < bottom.
1889 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1890 Sk4f min = Sk4f::Min(ltrb, rblt);
1891 Sk4f max = Sk4f::Max(ltrb, rblt);
1892 // We can extract either pair [0,1] or [2,3] from min and max and be correct , but on
1893 // ARM this sequence generates the fastest (a single instruction).
1894 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1895
1896 // Check if the device rect is NaN or outside the clip.
1897 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1835 } 1898 }
1836 1899
1837 bool SkCanvas::quickReject(const SkPath& path) const { 1900 bool SkCanvas::quickReject(const SkPath& path) const {
1838 return path.isEmpty() || this->quickReject(path.getBounds()); 1901 return path.isEmpty() || this->quickReject(path.getBounds());
1839 } 1902 }
1840 1903
1841 bool SkCanvas::getClipBounds(SkRect* bounds) const { 1904 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1842 SkIRect ibounds; 1905 SkIRect ibounds;
1843 if (!this->getClipDeviceBounds(&ibounds)) { 1906 if (!this->getClipDeviceBounds(&ibounds)) {
1844 return false; 1907 return false;
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after
2448 if (special) { 2511 if (special) {
2449 SkPoint pt; 2512 SkPoint pt;
2450 iter.fMatrix->mapXY(x, y, &pt); 2513 iter.fMatrix->mapXY(x, y, &pt);
2451 iter.fDevice->drawSpecial(iter, special.get(), 2514 iter.fDevice->drawSpecial(iter, special.get(),
2452 SkScalarRoundToInt(pt.fX), 2515 SkScalarRoundToInt(pt.fX),
2453 SkScalarRoundToInt(pt.fY), pnt); 2516 SkScalarRoundToInt(pt.fY), pnt);
2454 } else { 2517 } else {
2455 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint()); 2518 iter.fDevice->drawBitmap(iter, bitmap, matrix, looper.paint());
2456 } 2519 }
2457 } 2520 }
2458 2521
2459 LOOPER_END 2522 LOOPER_END
2460 } 2523 }
2461 2524
2462 // this one is non-virtual, so it can be called safely by other canvas apis 2525 // this one is non-virtual, so it can be called safely by other canvas apis
2463 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, 2526 void SkCanvas::internalDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src,
2464 const SkRect& dst, const SkPaint* paint, 2527 const SkRect& dst, const SkPaint* paint,
2465 SrcRectConstraint constraint) { 2528 SrcRectConstraint constraint) {
2466 if (bitmap.drawsNothing() || dst.isEmpty()) { 2529 if (bitmap.drawsNothing() || dst.isEmpty()) {
2467 return; 2530 return;
2468 } 2531 }
(...skipping 699 matching lines...) Expand 10 before | Expand all | Expand 10 after
3168 3231
3169 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 3232 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3170 fCanvas->restoreToCount(fSaveCount); 3233 fCanvas->restoreToCount(fSaveCount);
3171 } 3234 }
3172 3235
3173 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API 3236 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3174 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) { 3237 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) {
3175 return this->makeSurface(info, props).release(); 3238 return this->makeSurface(info, props).release();
3176 } 3239 }
3177 #endif 3240 #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