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

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: Cleaning things up 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/SkCanvas.h ('k') | no next file » | 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 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 #ifdef SK_DEBUG 258 #ifdef SK_DEBUG
258 if (!fClip.isEmpty()) { 259 if (!fClip.isEmpty()) {
259 SkIRect deviceR; 260 SkIRect deviceR;
260 deviceR.set(0, 0, width, height); 261 deviceR.set(0, 0, width, height);
261 SkASSERT(deviceR.contains(fClip.getBounds())); 262 SkASSERT(deviceR.contains(fClip.getBounds()));
262 } 263 }
263 #endif 264 #endif
264 } 265 }
265 }; 266 };
266 267
268
269 static inline void set_qr_clip_bounds(SkRect* dst, const SkIRect& src) {
mtklein 2016/08/11 01:24:41 Give that this is all inline, it'll probably make
msarett 2016/08/11 16:04:01 Agreed. Went with this->setCachedClipDeviceBounds
msarett 2016/08/11 20:15:16 Changed my mind. Going with qr_clip_bounds(). It
270 // Expand bounds out by 1 in case we are anti-aliasing. We store the
271 // bounds as floats to enable a faster quick reject implementation.
272 SkNx_cast<float>(Sk4i::Load(&src.fLeft) + Sk4i(-1, -1, 1, 1)).store(&dst->fL eft);
273 }
274
267 /* This is the record we keep for each save/restore level in the stack. 275 /* This is the record we keep for each save/restore level in the stack.
268 Since a level optionally copies the matrix and/or stack, we have pointers 276 Since a level optionally copies the matrix and/or stack, we have pointers
269 for these fields. If the value is copied for this level, the copy is 277 for these fields. If the value is copied for this level, the copy is
270 stored in the ...Storage field, and the pointer points to that. If the 278 stored in the ...Storage field, and the pointer points to that. If the
271 value is not copied for this level, we ignore ...Storage, and just point 279 value is not copied for this level, we ignore ...Storage, and just point
272 at the corresponding value in the previous level in the stack. 280 at the corresponding value in the previous level in the stack.
273 */ 281 */
274 class SkCanvas::MCRec { 282 class SkCanvas::MCRec {
275 public: 283 public:
276 SkDrawFilter* fFilter; // the current filter (or null) 284 SkDrawFilter* fFilter; // the current filter (or null)
(...skipping 16 matching lines...) Expand all
293 fFilter = nullptr; 301 fFilter = nullptr;
294 fLayer = nullptr; 302 fLayer = nullptr;
295 fTopLayer = nullptr; 303 fTopLayer = nullptr;
296 fMatrix.reset(); 304 fMatrix.reset();
297 fDeferredSaveCount = 0; 305 fDeferredSaveCount = 0;
298 fCurDrawDepth = 0; 306 fCurDrawDepth = 0;
299 307
300 // don't bother initializing fNext 308 // don't bother initializing fNext
301 inc_rec(); 309 inc_rec();
302 } 310 }
303 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip), fMatrix(prev.fMatr ix), 311 MCRec(const MCRec& prev) : fRasterClip(prev.fRasterClip) , fMatrix(prev.fMat rix)
304 fCurDrawDepth(prev.fCurDrawDepth) { 312 , fCurDrawDepth(prev.fCurDrawDepth)
313 {
305 fFilter = SkSafeRef(prev.fFilter); 314 fFilter = SkSafeRef(prev.fFilter);
306 fLayer = nullptr; 315 fLayer = nullptr;
307 fTopLayer = prev.fTopLayer; 316 fTopLayer = prev.fTopLayer;
308 fDeferredSaveCount = 0; 317 fDeferredSaveCount = 0;
309 318
310 // don't bother initializing fNext 319 // don't bother initializing fNext
311 inc_rec(); 320 inc_rec();
312 } 321 }
313 ~MCRec() { 322 ~MCRec() {
314 SkSafeUnref(fFilter); 323 SkSafeUnref(fFilter);
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 AutoDrawLooper looper(this, fProps, paint, false, bounds); \ 634 AutoDrawLooper looper(this, fProps, paint, false, bounds); \
626 while (looper.next(type)) { \ 635 while (looper.next(type)) { \
627 SkDrawIter iter(this); 636 SkDrawIter iter(this);
628 637
629 #define LOOPER_END } 638 #define LOOPER_END }
630 639
631 //////////////////////////////////////////////////////////////////////////// 640 ////////////////////////////////////////////////////////////////////////////
632 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 set_qr_clip_bounds(&fDeviceClipBounds, bounds);
651 fIsScaleTranslate = 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 set_qr_clip_bounds(&fDeviceClipBounds, device->getGlobalBounds());
691 fIsScaleTranslate = true;
mtklein 2016/08/11 01:24:41 Might want to name fConservativeIsScaleTranslate,
msarett 2016/08/11 16:04:00 Done.
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 set_qr_clip_bounds(&fDeviceClipBounds, 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 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
1350 set_qr_clip_bounds(&fDeviceClipBounds, 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 fIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
mtklein 2016/08/11 01:24:41 I think we can conservatively approximate this as
mtklein 2016/08/11 01:25:43 err, meant to write not-st x not-st == st.
msarett 2016/08/11 16:04:01 Got it, I think this is a good guess.
1495 this->didConcat(matrix); 1508 this->didConcat(matrix);
1496 } 1509 }
1497 1510
1498 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) { 1511 void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
1499 fDeviceCMDirty = true; 1512 fDeviceCMDirty = true;
1500 fCachedLocalClipBoundsDirty = true;
1501 fMCRec->fMatrix = matrix; 1513 fMCRec->fMatrix = matrix;
1502 } 1514 }
1503 1515
1504 void SkCanvas::setMatrix(const SkMatrix& matrix) { 1516 void SkCanvas::setMatrix(const SkMatrix& matrix) {
1505 this->checkForDeferredSave(); 1517 this->checkForDeferredSave();
1506 this->internalSetMatrix(matrix); 1518 this->internalSetMatrix(matrix);
1519 fIsScaleTranslate = matrix.isScaleTranslate();
1507 this->didSetMatrix(matrix); 1520 this->didSetMatrix(matrix);
1508 } 1521 }
1509 1522
1510 void SkCanvas::resetMatrix() { 1523 void SkCanvas::resetMatrix() {
1511 this->setMatrix(SkMatrix::I()); 1524 this->setMatrix(SkMatrix::I());
1512 } 1525 }
1513 1526
1514 #ifdef SK_EXPERIMENTAL_SHADOWING 1527 #ifdef SK_EXPERIMENTAL_SHADOWING
1515 void SkCanvas::translateZ(SkScalar z) { 1528 void SkCanvas::translateZ(SkScalar z) {
1516 this->checkForDeferredSave(); 1529 this->checkForDeferredSave();
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
1597 rect.left(), rect.top(), rect.right(), rect.bottom()); 1610 rect.left(), rect.top(), rect.right(), rect.bottom());
1598 #endif 1611 #endif
1599 return; 1612 return;
1600 } 1613 }
1601 } 1614 }
1602 #endif 1615 #endif
1603 1616
1604 AutoValidateClip avc(this); 1617 AutoValidateClip avc(this);
1605 1618
1606 fDeviceCMDirty = true; 1619 fDeviceCMDirty = true;
1607 fCachedLocalClipBoundsDirty = true;
1608 1620
1609 if (isScaleTrans) { 1621 if (isScaleTrans) {
1610 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle; 1622 const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
1611 fClipStack->clipDevRect(devR, op, isAA); 1623 fClipStack->clipDevRect(devR, op, isAA);
1612 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA); 1624 fMCRec->fRasterClip.op(devR, this->getTopLayerBounds(), op, isAA);
1613 } else { 1625 } else {
1614 // since we're rotated or some such thing, we convert the rect to a path 1626 // 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 1627 // 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) 1628 // avoid recursion in the case where we are subclassed (e.g. Pictures)
1617 // we explicitly call "our" version of clipPath. 1629 // we explicitly call "our" version of clipPath.
1618 SkPath path; 1630 SkPath path;
1619 1631
1620 path.addRect(rect); 1632 path.addRect(rect);
1621 this->SkCanvas::onClipPath(path, op, edgeStyle); 1633 this->SkCanvas::onClipPath(path, op, edgeStyle);
1622 } 1634 }
1635
1636 set_qr_clip_bounds(&fDeviceClipBounds, fMCRec->fRasterClip.getBounds());
1623 } 1637 }
1624 1638
1625 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) { 1639 void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
1626 this->checkForDeferredSave(); 1640 this->checkForDeferredSave();
1627 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle; 1641 ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
1628 if (rrect.isRect()) { 1642 if (rrect.isRect()) {
1629 this->onClipRect(rrect.getBounds(), op, edgeStyle); 1643 this->onClipRect(rrect.getBounds(), op, edgeStyle);
1630 } else { 1644 } else {
1631 this->onClipRRect(rrect, op, edgeStyle); 1645 this->onClipRRect(rrect, op, edgeStyle);
1632 } 1646 }
1633 } 1647 }
1634 1648
1635 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 1649 void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
1636 SkRRect transformedRRect; 1650 SkRRect transformedRRect;
1637 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) { 1651 if (rrect.transform(fMCRec->fMatrix, &transformedRRect)) {
1638 AutoValidateClip avc(this); 1652 AutoValidateClip avc(this);
1639 1653
1640 fDeviceCMDirty = true; 1654 fDeviceCMDirty = true;
1641 fCachedLocalClipBoundsDirty = true;
1642 if (!fAllowSoftClip) { 1655 if (!fAllowSoftClip) {
1643 edgeStyle = kHard_ClipEdgeStyle; 1656 edgeStyle = kHard_ClipEdgeStyle;
1644 } 1657 }
1645 1658
1646 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle); 1659 fClipStack->clipDevRRect(transformedRRect, op, kSoft_ClipEdgeStyle == ed geStyle);
1647 1660
1648 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op, 1661 fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
1649 kSoft_ClipEdgeStyle == edgeStyle); 1662 kSoft_ClipEdgeStyle == edgeStyle);
1663 set_qr_clip_bounds(&fDeviceClipBounds, fMCRec->fRasterClip.getBounds());
1650 return; 1664 return;
1651 } 1665 }
1652 1666
1653 SkPath path; 1667 SkPath path;
1654 path.addRRect(rrect); 1668 path.addRRect(rrect);
1655 // call the non-virtual version 1669 // call the non-virtual version
1656 this->SkCanvas::onClipPath(path, op, edgeStyle); 1670 this->SkCanvas::onClipPath(path, op, edgeStyle);
1657 } 1671 }
1658 1672
1659 void SkCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) { 1673 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(); 1709 fClipStack->clipEmpty();
1696 (void)fMCRec->fRasterClip.setEmpty(); 1710 (void)fMCRec->fRasterClip.setEmpty();
1697 return; 1711 return;
1698 } 1712 }
1699 } 1713 }
1700 #endif 1714 #endif
1701 1715
1702 AutoValidateClip avc(this); 1716 AutoValidateClip avc(this);
1703 1717
1704 fDeviceCMDirty = true; 1718 fDeviceCMDirty = true;
1705 fCachedLocalClipBoundsDirty = true;
1706 if (!fAllowSoftClip) { 1719 if (!fAllowSoftClip) {
1707 edgeStyle = kHard_ClipEdgeStyle; 1720 edgeStyle = kHard_ClipEdgeStyle;
1708 } 1721 }
1709 1722
1710 SkPath devPath; 1723 SkPath devPath;
1711 path.transform(fMCRec->fMatrix, &devPath); 1724 path.transform(fMCRec->fMatrix, &devPath);
1712 1725
1713 // Check if the transfomation, or the original path itself 1726 // Check if the transfomation, or the original path itself
1714 // made us empty. Note this can also happen if we contained NaN 1727 // made us empty. Note this can also happen if we contained NaN
1715 // values. computing the bounds detects this, and will set our 1728 // values. computing the bounds detects this, and will set our
(...skipping 10 matching lines...) Expand all
1726 if (fAllowSimplifyClip) { 1739 if (fAllowSimplifyClip) {
1727 bool clipIsAA = getClipStack()->asPath(&devPath); 1740 bool clipIsAA = getClipStack()->asPath(&devPath);
1728 if (clipIsAA) { 1741 if (clipIsAA) {
1729 edgeStyle = kSoft_ClipEdgeStyle; 1742 edgeStyle = kSoft_ClipEdgeStyle;
1730 } 1743 }
1731 1744
1732 op = SkRegion::kReplace_Op; 1745 op = SkRegion::kReplace_Op;
1733 } 1746 }
1734 1747
1735 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle); 1748 fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
1749 set_qr_clip_bounds(&fDeviceClipBounds, fMCRec->fRasterClip.getBounds());
1736 } 1750 }
1737 1751
1738 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) { 1752 void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
1739 this->checkForDeferredSave(); 1753 this->checkForDeferredSave();
1740 this->onClipRegion(rgn, op); 1754 this->onClipRegion(rgn, op);
1741 } 1755 }
1742 1756
1743 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) { 1757 void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
1744 AutoValidateClip avc(this); 1758 AutoValidateClip avc(this);
1745 1759
1746 fDeviceCMDirty = true; 1760 fDeviceCMDirty = true;
1747 fCachedLocalClipBoundsDirty = true;
1748 1761
1749 // todo: signal fClipStack that we have a region, and therefore (I guess) 1762 // todo: signal fClipStack that we have a region, and therefore (I guess)
1750 // we have to ignore it, and use the region directly? 1763 // we have to ignore it, and use the region directly?
1751 fClipStack->clipDevRect(rgn.getBounds(), op); 1764 fClipStack->clipDevRect(rgn.getBounds(), op);
1752 1765
1753 fMCRec->fRasterClip.op(rgn, op); 1766 fMCRec->fRasterClip.op(rgn, op);
1767 set_qr_clip_bounds(&fDeviceClipBounds, fMCRec->fRasterClip.getBounds());
1754 } 1768 }
1755 1769
1756 #ifdef SK_DEBUG 1770 #ifdef SK_DEBUG
1757 void SkCanvas::validateClip() const { 1771 void SkCanvas::validateClip() const {
1758 // construct clipRgn from the clipstack 1772 // construct clipRgn from the clipstack
1759 const SkBaseDevice* device = this->getDevice(); 1773 const SkBaseDevice* device = this->getDevice();
1760 if (!device) { 1774 if (!device) {
1761 SkASSERT(this->isClipEmpty()); 1775 SkASSERT(this->isClipEmpty());
1762 return; 1776 return;
1763 } 1777 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1800 /////////////////////////////////////////////////////////////////////////////// 1814 ///////////////////////////////////////////////////////////////////////////////
1801 1815
1802 bool SkCanvas::isClipEmpty() const { 1816 bool SkCanvas::isClipEmpty() const {
1803 return fMCRec->fRasterClip.isEmpty(); 1817 return fMCRec->fRasterClip.isEmpty();
1804 } 1818 }
1805 1819
1806 bool SkCanvas::isClipRect() const { 1820 bool SkCanvas::isClipRect() const {
1807 return fMCRec->fRasterClip.isRect(); 1821 return fMCRec->fRasterClip.isRect();
1808 } 1822 }
1809 1823
1810 bool SkCanvas::quickReject(const SkRect& rect) const { 1824 static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
1811 if (!rect.isFinite()) 1825 #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
1812 return true; 1826 __m128 lltt = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
mtklein 2016/08/11 01:24:41 Might help to make one rect ltrb and the other LTR
msarett 2016/08/11 16:04:01 Agreed, done.
1827 __m128 rrbb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
1828 __m128 mask = _mm_cmplt_ps(lltt, rrbb);
1829 return 0xF != _mm_movemask_ps(mask);
1830 #elif defined(SK_ARM_HAS_NEON)
1831 float32x4_t lltt = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
1832 float32x4_t rrbb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
1833 uint32x4_t mask = vcltq_f32(lltt, rrbb);
1834 return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
1835 #else
1836 SkASSERT(false);
mtklein 2016/08/11 01:24:41 ಠ_ಠ
msarett 2016/08/11 16:04:00 Guessing this means I should implement the scalar
1837 return false;
1838 #endif
1839 }
1813 1840
1814 if (fMCRec->fRasterClip.isEmpty()) { 1841 // It's important for this function to not be inlined. Otherwise the compiler w ill share code
1815 return true; 1842 // between the fast path and the slow path, resulting in two slow paths.
1843 static __attribute__((noinline)) bool quick_reject_slow_path(const SkRect& src,
mtklein 2016/08/11 01:24:41 Let's add SK_NEVER_INLINE alongside SK_ALWAYS_INLI
msarett 2016/08/11 16:04:01 SK_NEVER_INLINE sgtm.
1844 const SkRect& devic eClip,
1845 const SkMatrix& mat rix) {
1846 SkRect deviceRect;
1847 matrix.mapRect(&deviceRect, src);
1848 return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
1849 }
1850
1851 bool SkCanvas::quickReject(const SkRect& src) const {
1852 if (!fIsScaleTranslate) {
1853 return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
mtklein 2016/08/11 01:24:41 We might follow up to see how bad things are if we
msarett 2016/08/11 16:04:00 SGTM
1816 } 1854 }
1817 1855
1818 if (fMCRec->fMatrix.hasPerspective()) { 1856 // We inline the implementation of mapScaleTranslate() for the fast path.
1819 SkRect dst; 1857 float sx = fMCRec->fMatrix.getScaleX();
1820 fMCRec->fMatrix.mapRect(&dst, rect); 1858 float sy = fMCRec->fMatrix.getScaleY();
1821 return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBound s()); 1859 float tx = fMCRec->fMatrix.getTranslateX();
1822 } else { 1860 float ty = fMCRec->fMatrix.getTranslateY();
1823 const SkRect& clipR = this->getLocalClipBounds(); 1861 Sk4f scale(sx, sy, sx, sy);
1862 Sk4f trans(tx, ty, tx, ty);
1824 1863
1825 // for speed, do the most likely reject compares first 1864 // Apply matrix.
1826 // TODO: should we use | instead, or compare all 4 at once? 1865 Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
1827 if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) { 1866
1828 return true; 1867 // Make sure left < right, top < bottom.
1829 } 1868 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1830 if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) { 1869 Sk4f min = Sk4f::Min(ltrb, rblt);
1831 return true; 1870 Sk4f max = Sk4f::Max(ltrb, rblt);
1832 } 1871 // We can extract either pair [0,1] or [2,3] from min and max and be correct , but on
1872 // ARM this sequence generates the fastest (a single instruction).
1873 Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
1874
1875 // Check if the device rect is NaN or outside the clip.
1876 return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
1877 }
1878
1879 bool SkCanvas::quickRejectY(SkScalar top, SkScalar bottom) const {
mtklein 2016/08/11 01:24:41 I think we should consider a pre-patch deleting qu
msarett 2016/08/11 16:04:00 SGTM. I wanted to delete it... Glad to know the
1880 if (!fIsScaleTranslate) {
1881 // This is only called when we draw text. Will we ever draw rotated or perspective text?
1833 return false; 1882 return false;
1834 } 1883 }
1884
1885 top = top * fMCRec->fMatrix.getScaleY() + fMCRec->fMatrix.getTranslateY();
mtklein 2016/08/11 01:24:41 :,( "top " lines up so much more nicely with "b
msarett 2016/08/11 16:04:01 Acknowledged.
1886 bottom = bottom * fMCRec->fMatrix.getScaleY() + fMCRec->fMatrix.getTranslate Y();
1887
1888 // In the case where the clip is empty and we are provided with a
1889 // negative top and positive bottom parameter then this test will return
1890 // false even though it will be clipped. We have chosen to exclude that
1891 // check as it is rare and would result double the comparisons.
1892 return top >= fDeviceClipBounds.fBottom || bottom <= fDeviceClipBounds.fTop;
1835 } 1893 }
1836 1894
1837 bool SkCanvas::quickReject(const SkPath& path) const { 1895 bool SkCanvas::quickReject(const SkPath& path) const {
1838 return path.isEmpty() || this->quickReject(path.getBounds()); 1896 return path.isEmpty() || this->quickReject(path.getBounds());
1839 } 1897 }
1840 1898
1841 bool SkCanvas::getClipBounds(SkRect* bounds) const { 1899 bool SkCanvas::getClipBounds(SkRect* bounds) const {
1842 SkIRect ibounds; 1900 SkIRect ibounds;
1843 if (!this->getClipDeviceBounds(&ibounds)) { 1901 if (!this->getClipDeviceBounds(&ibounds)) {
1844 return false; 1902 return false;
(...skipping 1323 matching lines...) Expand 10 before | Expand all | Expand 10 after
3168 3226
3169 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() { 3227 SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
3170 fCanvas->restoreToCount(fSaveCount); 3228 fCanvas->restoreToCount(fSaveCount);
3171 } 3229 }
3172 3230
3173 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API 3231 #ifdef SK_SUPPORT_LEGACY_NEW_SURFACE_API
3174 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) { 3232 SkSurface* SkCanvas::newSurface(const SkImageInfo& info, const SkSurfaceProps* p rops) {
3175 return this->makeSurface(info, props).release(); 3233 return this->makeSurface(info, props).release();
3176 } 3234 }
3177 #endif 3235 #endif
OLDNEW
« no previous file with comments | « include/core/SkCanvas.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698