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

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

Issue 716913003: Move SkRecordComputeLayers and CollectLayers into SkRecordDraw.cpp (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address code review issues Created 6 years, 1 month 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 | « src/core/SkRecordDraw.h ('k') | src/gpu/GrPictureUtils.h » ('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 2014 Google Inc. 2 * Copyright 2014 Google Inc.
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 "SkRecordDraw.h" 8 #include "SkRecordDraw.h"
9 #include "SkPatchUtils.h" 9 #include "SkPatchUtils.h"
10 10
11 #if SK_SUPPORT_GPU
12 #include "GrPictureUtils.h"
13 #endif
14
11 void SkRecordDraw(const SkRecord& record, 15 void SkRecordDraw(const SkRecord& record,
12 SkCanvas* canvas, 16 SkCanvas* canvas,
13 const SkBBoxHierarchy* bbh, 17 const SkBBoxHierarchy* bbh,
14 SkDrawPictureCallback* callback) { 18 SkDrawPictureCallback* callback) {
15 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); 19 SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
16 20
17 if (bbh) { 21 if (bbh) {
18 // Draw only ops that affect pixels in the canvas's current clip. 22 // Draw only ops that affect pixels in the canvas's current clip.
19 // The SkRecord and BBH were recorded in identity space. This canvas 23 // The SkRecord and BBH were recorded in identity space. This canvas
20 // is not necessarily in that same space. getClipBounds() returns us 24 // is not necessarily in that same space. getClipBounds() returns us
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 // non-drawing ("control") ops inside are exactly the union of the bounds of 139 // non-drawing ("control") ops inside are exactly the union of the bounds of
136 // the drawing ops inside that block. 140 // the drawing ops inside that block.
137 // 141 //
138 // To implement this, we keep a stack of active Save blocks. As we consume ops 142 // To implement this, we keep a stack of active Save blocks. As we consume ops
139 // inside the Save/Restore block, drawing ops are unioned with the bounds of 143 // inside the Save/Restore block, drawing ops are unioned with the bounds of
140 // the block, and control ops are stashed away for later. When we finish the 144 // the block, and control ops are stashed away for later. When we finish the
141 // block with a Restore, our bounds are complete, and we go back and fill them 145 // block with a Restore, our bounds are complete, and we go back and fill them
142 // in for all the control ops we stashed away. 146 // in for all the control ops we stashed away.
143 class FillBounds : SkNoncopyable { 147 class FillBounds : SkNoncopyable {
144 public: 148 public:
145 FillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHierarchy* bbh) 149 FillBounds(const SkRect& cullRect, const SkRecord& record)
146 : fCullRect(cullRect) 150 : fNumRecords(record.count())
151 , fCullRect(cullRect)
147 , fBounds(record.count()) { 152 , fBounds(record.count()) {
148 // Calculate bounds for all ops. This won't go quite in order, so we'll need 153 // Calculate bounds for all ops. This won't go quite in order, so we'll need
149 // to store the bounds separately then feed them in to the BBH later in order. 154 // to store the bounds separately then feed them in to the BBH later in order.
150 fCTM = &SkMatrix::I(); 155 fCTM = &SkMatrix::I();
151 fCurrentClipBounds = fCullRect; 156 fCurrentClipBounds = fCullRect;
152 for (fCurrentOp = 0; fCurrentOp < record.count(); fCurrentOp++) { 157 }
153 record.visit<void>(fCurrentOp, *this);
154 }
155 158
159 void setCurrentOp(unsigned currentOp) { fCurrentOp = currentOp; }
160
161 void cleanUp(SkBBoxHierarchy* bbh) {
156 // If we have any lingering unpaired Saves, simulate restores to make 162 // If we have any lingering unpaired Saves, simulate restores to make
157 // sure all ops in those Save blocks have their bounds calculated. 163 // sure all ops in those Save blocks have their bounds calculated.
158 while (!fSaveStack.isEmpty()) { 164 while (!fSaveStack.isEmpty()) {
159 this->popSaveBlock(); 165 this->popSaveBlock();
160 } 166 }
161 167
162 // Any control ops not part of any Save/Restore block draw everywhere. 168 // Any control ops not part of any Save/Restore block draw everywhere.
163 while (!fControlIndices.isEmpty()) { 169 while (!fControlIndices.isEmpty()) {
164 this->popControl(fCullRect); 170 this->popControl(fCullRect);
165 } 171 }
166 172
167 // Finally feed all stored bounds into the BBH. They'll be returned in this order. 173 // Finally feed all stored bounds into the BBH. They'll be returned in this order.
168 SkASSERT(bbh); 174 SkASSERT(bbh);
169 bbh->insert(&fBounds, record.count()); 175 bbh->insert(&fBounds, fNumRecords);
170 } 176 }
171 177
172 template <typename T> void operator()(const T& op) { 178 template <typename T> void operator()(const T& op) {
173 this->updateCTM(op); 179 this->updateCTM(op);
174 this->updateClipBounds(op); 180 this->updateClipBounds(op);
175 this->trackBounds(op); 181 this->trackBounds(op);
176 } 182 }
177 183
178 private:
179 // In this file, SkRect are in local coordinates, Bounds are translated back to identity space. 184 // In this file, SkRect are in local coordinates, Bounds are translated back to identity space.
180 typedef SkRect Bounds; 185 typedef SkRect Bounds;
181 186
187 unsigned currentOp() const { return fCurrentOp; }
188 const SkMatrix& ctm() const { return *fCTM; }
189 const Bounds& currentClipBounds() const { return fCurrentClipBounds; }
190 const Bounds& getBounds(unsigned index) const { return fBounds[index]; }
191
192 // Adjust rect for all paints that may affect its geometry, then map it to i dentity space.
193 Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
194 // Inverted rectangles really confuse our BBHs.
195 rect.sort();
196
197 // Adjust the rect for its own paint.
198 if (!AdjustForPaint(paint, &rect)) {
199 // The paint could do anything to our bounds. The only safe answer is the current clip.
200 return fCurrentClipBounds;
201 }
202
203 // Adjust rect for all the paints from the SaveLayers we're inside.
204 if (!this->adjustForSaveLayerPaints(&rect)) {
205 // Same deal as above.
206 return fCurrentClipBounds;
207 }
208
209 // Map the rect back to identity space.
210 fCTM->mapRect(&rect);
211
212 // Nothing can draw outside the current clip.
213 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
214 rect.intersect(fCurrentClipBounds);
215 return rect;
216 }
217
218 private:
182 struct SaveBounds { 219 struct SaveBounds {
183 int controlOps; // Number of control ops in this Save block, incl uding the Save. 220 int controlOps; // Number of control ops in this Save block, incl uding the Save.
184 Bounds bounds; // Bounds of everything in the block. 221 Bounds bounds; // Bounds of everything in the block.
185 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op s in this block. 222 const SkPaint* paint; // Unowned. If set, adjusts the bounds of all op s in this block.
186 }; 223 };
187 224
188 // Only Restore and SetMatrix change the CTM. 225 // Only Restore and SetMatrix change the CTM.
189 template <typename T> void updateCTM(const T&) {} 226 template <typename T> void updateCTM(const T&) {}
190 void updateCTM(const Restore& op) { fCTM = &op.matrix; } 227 void updateCTM(const Restore& op) { fCTM = &op.matrix; }
191 void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; } 228 void updateCTM(const SetMatrix& op) { fCTM = &op.matrix; }
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 544
508 bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const { 545 bool adjustForSaveLayerPaints(SkRect* rect, int savesToIgnore = 0) const {
509 for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) { 546 for (int i = fSaveStack.count() - 1 - savesToIgnore; i >= 0; i--) {
510 if (!AdjustForPaint(fSaveStack[i].paint, rect)) { 547 if (!AdjustForPaint(fSaveStack[i].paint, rect)) {
511 return false; 548 return false;
512 } 549 }
513 } 550 }
514 return true; 551 return true;
515 } 552 }
516 553
517 // Adjust rect for all paints that may affect its geometry, then map it to i dentity space. 554 const unsigned fNumRecords;
518 Bounds adjustAndMap(SkRect rect, const SkPaint* paint) const {
519 // Inverted rectangles really confuse our BBHs.
520 rect.sort();
521
522 // Adjust the rect for its own paint.
523 if (!AdjustForPaint(paint, &rect)) {
524 // The paint could do anything to our bounds. The only safe answer is the current clip.
525 return fCurrentClipBounds;
526 }
527
528 // Adjust rect for all the paints from the SaveLayers we're inside.
529 if (!this->adjustForSaveLayerPaints(&rect)) {
530 // Same deal as above.
531 return fCurrentClipBounds;
532 }
533
534 // Map the rect back to identity space.
535 fCTM->mapRect(&rect);
536
537 // Nothing can draw outside the current clip.
538 // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
539 rect.intersect(fCurrentClipBounds);
540 return rect;
541 }
542 555
543 // We do not guarantee anything for operations outside of the cull rect 556 // We do not guarantee anything for operations outside of the cull rect
544 const SkRect fCullRect; 557 const SkRect fCullRect;
545 558
546 // Conservative identity-space bounds for each op in the SkRecord. 559 // Conservative identity-space bounds for each op in the SkRecord.
547 SkAutoTMalloc<Bounds> fBounds; 560 SkAutoTMalloc<Bounds> fBounds;
548 561
549 // We walk fCurrentOp through the SkRecord, as we go using updateCTM() 562 // We walk fCurrentOp through the SkRecord, as we go using updateCTM()
550 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative 563 // and updateClipBounds() to maintain the exact CTM (fCTM) and conservative
551 // identity-space bounds of the current clip (fCurrentClipBounds). 564 // identity-space bounds of the current clip (fCurrentClipBounds).
552 unsigned fCurrentOp; 565 unsigned fCurrentOp;
553 const SkMatrix* fCTM; 566 const SkMatrix* fCTM;
554 Bounds fCurrentClipBounds; 567 Bounds fCurrentClipBounds;
555 568
556 // Used to track the bounds of Save/Restore blocks and the control ops insid e them. 569 // Used to track the bounds of Save/Restore blocks and the control ops insid e them.
557 SkTDArray<SaveBounds> fSaveStack; 570 SkTDArray<SaveBounds> fSaveStack;
558 SkTDArray<unsigned> fControlIndices; 571 SkTDArray<unsigned> fControlIndices;
559 }; 572 };
560 573
574 #if SK_SUPPORT_GPU
575 // SkRecord visitor to gather saveLayer/restore information.
576 class CollectLayers : SkNoncopyable {
577 public:
578 CollectLayers(const SkRect& cullRect, const SkRecord& record, GrAccelData* a ccelData)
579 : fSaveLayersInStack(0)
580 , fAccelData(accelData)
581 , fFillBounds(cullRect, record) {
582 }
583
584 void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); }
585
586 void cleanUp(SkBBoxHierarchy* bbh) {
587 // fFillBounds must perform its cleanUp first so that all the bounding
588 // boxes associated with unbalanced restores are updated (prior to
589 // fetching their bound in popSaveLayerInfo).
590 fFillBounds.cleanUp(bbh);
591
592 while (!fSaveLayerStack.isEmpty()) {
593 this->popSaveLayerInfo();
594 }
595 }
596
597 template <typename T> void operator()(const T& op) {
598 fFillBounds(op);
599 this->trackSaveLayers(op);
600 }
601
602 private:
603 struct SaveLayerInfo {
604 SaveLayerInfo() { }
605 SaveLayerInfo(int opIndex, bool isSaveLayer, const SkPaint* paint,
606 const FillBounds::Bounds& clipBound)
607 : fStartIndex(opIndex)
608 , fIsSaveLayer(isSaveLayer)
609 , fHasNestedSaveLayer(false)
610 , fPaint(paint)
611 , fClipBound(clipBound) {
612 }
613
614 int fStartIndex;
615 bool fIsSaveLayer;
616 bool fHasNestedSaveLayer;
617 const SkPaint* fPaint;
618 FillBounds::Bounds fClipBound;
619 };
620
621 template <typename T> void trackSaveLayers(const T& op) {
622 /* most ops aren't involved in saveLayers */
623 }
624 void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL); }
625 void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl .paint); }
626 void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
627
628 void trackSaveLayers(const DrawPicture& dp) {
629 // For sub-pictures, we wrap their layer information within the parent
630 // picture's rendering hierarchy
631 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
632
633 const GrAccelData* childData =
634 static_cast<const GrAccelData*>(dp.picture->EXPERIMENTAL_getAccelDat a(key));
635 if (!childData) {
636 // If the child layer hasn't been generated with saveLayer data we
637 // assume the worst (i.e., that it does contain layers which nest
638 // inside existing layers). Layers within sub-pictures that don't
639 // have saveLayer data cannot be hoisted.
640 // TODO: could the analysis data be use to fine tune this?
641 this->updateStackForSaveLayer();
642 return;
643 }
644
645 for (int i = 0; i < childData->numSaveLayers(); ++i) {
646 const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i);
647
648 FillBounds::Bounds newClip(fFillBounds.currentClipBounds());
649
650 if (!newClip.intersect(fFillBounds.adjustAndMap(src.fBounds, dp.pain t))) {
651 continue;
652 }
653
654 this->updateStackForSaveLayer();
655
656 GrAccelData::SaveLayerInfo& dst = fAccelData->addSaveLayerInfo();
657
658 // If src.fPicture is NULL the layer is in dp.picture; otherwise
659 // it belongs to a sub-picture.
660 dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPic ture*>(dp.picture);
661 dst.fPicture->ref();
662 dst.fBounds = newClip;
663 dst.fLocalMat = src.fLocalMat;
664 dst.fPreMat = src.fPreMat;
665 dst.fPreMat.postConcat(fFillBounds.ctm());
666 if (src.fPaint) {
667 dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
668 }
669 dst.fSaveLayerOpID = src.fSaveLayerOpID;
670 dst.fRestoreOpID = src.fRestoreOpID;
671 dst.fHasNestedLayers = src.fHasNestedLayers;
672 dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
673 }
674 }
675
676 // Inform all the saveLayers already on the stack that they now have a
677 // nested saveLayer inside them
678 void updateStackForSaveLayer() {
679 for (int index = fSaveLayerStack.count() - 1; index >= 0; --index) {
680 if (fSaveLayerStack[index].fHasNestedSaveLayer) {
681 break;
682 }
683 fSaveLayerStack[index].fHasNestedSaveLayer = true;
684 if (fSaveLayerStack[index].fIsSaveLayer) {
685 break;
686 }
687 }
688 }
689
690 void pushSaveLayerInfo(bool isSaveLayer, const SkPaint* paint) {
691 if (isSaveLayer) {
692 this->updateStackForSaveLayer();
693 ++fSaveLayersInStack;
694 }
695
696 fSaveLayerStack.push(SaveLayerInfo(fFillBounds.currentOp(), isSaveLayer, paint,
697 fFillBounds.currentClipBounds()));
698 }
699
700 void popSaveLayerInfo() {
701 if (fSaveLayerStack.count() <= 0) {
702 SkASSERT(false);
703 return;
704 }
705
706 SaveLayerInfo sli;
707 fSaveLayerStack.pop(&sli);
708
709 if (!sli.fIsSaveLayer) {
710 return;
711 }
712
713 --fSaveLayersInStack;
714
715 GrAccelData::SaveLayerInfo& slInfo = fAccelData->addSaveLayerInfo();
716
717 SkASSERT(NULL == slInfo.fPicture); // This layer is in the top-most pic ture
718
719 slInfo.fBounds = fFillBounds.getBounds(sli.fStartIndex);
720 slInfo.fBounds.intersect(sli.fClipBound);
721 slInfo.fLocalMat = fFillBounds.ctm();
722 slInfo.fPreMat = SkMatrix::I();
723 if (sli.fPaint) {
724 slInfo.fPaint = SkNEW_ARGS(SkPaint, (*sli.fPaint));
725 }
726 slInfo.fSaveLayerOpID = sli.fStartIndex;
727 slInfo.fRestoreOpID = fFillBounds.currentOp();
728 slInfo.fHasNestedLayers = sli.fHasNestedSaveLayer;
729 slInfo.fIsNested = fSaveLayersInStack > 0;
730 }
731
732 // Used to collect saveLayer information for layer hoisting
733 int fSaveLayersInStack;
734 SkTDArray<SaveLayerInfo> fSaveLayerStack;
735 GrAccelData* fAccelData;
736
737 SkRecords::FillBounds fFillBounds;
738 };
739 #endif
740
561 } // namespace SkRecords 741 } // namespace SkRecords
562 742
563 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi erarchy* bbh) { 743 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi erarchy* bbh) {
564 SkRecords::FillBounds(cullRect, record, bbh); 744 SkRecords::FillBounds visitor(cullRect, record);
745
746 for (unsigned curOp = 0; curOp < record.count(); curOp++) {
747 visitor.setCurrentOp(curOp);
748 record.visit<void>(curOp, visitor);
749 }
750
751 visitor.cleanUp(bbh);
565 } 752 }
753
754 #if SK_SUPPORT_GPU
755 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
756 SkBBoxHierarchy* bbh, GrAccelData* data) {
757 SkRecords::CollectLayers visitor(cullRect, record, data);
758
759 for (unsigned curOp = 0; curOp < record.count(); curOp++) {
760 visitor.setCurrentOp(curOp);
761 record.visit<void>(curOp, visitor);
762 }
763
764 visitor.cleanUp(bbh);
765 }
766 #endif
767
OLDNEW
« no previous file with comments | « src/core/SkRecordDraw.h ('k') | src/gpu/GrPictureUtils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698