diff options
author | reed <reed@google.com> | 2014-11-24 14:41:51 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-24 14:41:51 -0800 |
commit | 1bdfd3f4f09e47364f76d3f08177b1ce844ac786 (patch) | |
tree | 91b83cdc89f884513bacac06ee8f008f4e8276f8 | |
parent | 89ff0846fd9dacf5f081373746624d450a5f8c26 (diff) |
option to return drawable from recording
patch from issue 747033005 at patchset 80001 (http://crrev.com/747033005#ps80001)
BUG=skia:
Review URL: https://codereview.chromium.org/732653004
-rw-r--r-- | include/core/SkPicture.h | 7 | ||||
-rw-r--r-- | include/core/SkPictureRecorder.h | 36 | ||||
-rw-r--r-- | samplecode/SampleArc.cpp | 51 | ||||
-rw-r--r-- | src/core/SkCanvasDrawable.cpp | 8 | ||||
-rw-r--r-- | src/core/SkCanvasDrawable.h | 9 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 8 | ||||
-rw-r--r-- | src/core/SkPictureRecorder.cpp | 104 | ||||
-rw-r--r-- | src/core/SkRecord.h | 4 | ||||
-rw-r--r-- | src/core/SkRecordDraw.cpp | 51 | ||||
-rw-r--r-- | src/core/SkRecordDraw.h | 13 | ||||
-rw-r--r-- | src/core/SkRecorder.cpp | 49 | ||||
-rw-r--r-- | src/core/SkRecorder.h | 25 | ||||
-rw-r--r-- | src/gpu/GrRecordReplaceDraw.cpp | 2 | ||||
-rw-r--r-- | tests/PictureTest.cpp | 18 | ||||
-rw-r--r-- | tests/RecordDrawTest.cpp | 10 | ||||
-rw-r--r-- | tools/DumpRecord.cpp | 2 |
16 files changed, 280 insertions, 117 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index ebaeef0b7e..07eca144b8 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -268,9 +268,9 @@ private: const uint32_t fUniqueID; const SkRect fCullRect; mutable SkAutoTUnref<const AccelData> fAccelData; - SkAutoTDelete<const SkRecord> fRecord; - SkAutoTUnref<const SkBBoxHierarchy> fBBH; - SkAutoTDelete<const SnapshotArray> fDrawablePicts; + SkAutoTUnref<const SkRecord> fRecord; + SkAutoTUnref<const SkBBoxHierarchy> fBBH; + SkAutoTDelete<const SnapshotArray> fDrawablePicts; // helpers for fDrawablePicts int drawableCount() const; @@ -298,6 +298,7 @@ private: friend class GrLayerHoister; // access to fRecord friend class ReplaceDraw; friend class SkPictureUtils; + friend class SkRecordedDrawable; }; SK_COMPILE_ASSERT(sizeof(SkPicture) <= 96, SkPictureSize); diff --git a/include/core/SkPictureRecorder.h b/include/core/SkPictureRecorder.h index 528472bc22..37cbe8692a 100644 --- a/include/core/SkPictureRecorder.h +++ b/include/core/SkPictureRecorder.h @@ -19,6 +19,7 @@ namespace android { #endif class SkCanvas; +class SkCanvasDrawable; class SkPictureRecord; class SkRecord; class SkRecorder; @@ -65,12 +66,32 @@ public: */ SkCanvas* getRecordingCanvas(); - /** Signal that the caller is done recording. This invalidates the canvas - returned by beginRecording/getRecordingCanvas, and returns the - created SkPicture. Note that the returned picture has its creation - ref which the caller must take ownership of. - */ - SkPicture* endRecording(); + /** + * Signal that the caller is done recording. This invalidates the canvas returned by + * beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who + * must call unref() when they are done using it. + * + * The returned picture is immutable. If during recording drawables were added to the canvas, + * these will have been "drawn" into a recording canvas, so that this resulting picture will + * reflect their current state, but will not contain a live reference to the drawables + * themselves. + */ + SkPicture* endRecordingAsPicture(); + + /** + * Signal that the caller is done recording. This invalidates the canvas returned by + * beginRecording/getRecordingCanvas. Ownership of the object is passed to the caller, who + * must call unref() when they are done using it. + * + * Unlike endRecordingAsPicture(), which returns an immutable picture, the returned drawable + * may contain live references to other drawables (if they were added to the recording canvas) + * and therefore this drawable will reflect the current state of those nested drawables anytime + * it is drawn or a new picture is snapped from it (by calling drawable->newPictureSnapshot()). + */ + SkCanvasDrawable* EXPERIMENTAL_endRecordingAsDrawable(); + + // Legacy API -- use endRecordingAsPicture instead. + SkPicture* endRecording() { return this->endRecordingAsPicture(); } private: void reset(); @@ -88,7 +109,8 @@ private: SkRect fCullRect; SkAutoTUnref<SkBBoxHierarchy> fBBH; SkAutoTUnref<SkRecorder> fRecorder; - SkAutoTDelete<SkRecord> fRecord; + SkAutoTUnref<SkRecord> fRecord; + SkBBHFactory* fBBHFactory; typedef SkNoncopyable INHERITED; }; diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp index a44eeb59ba..6943eb7a6c 100644 --- a/samplecode/SampleArc.cpp +++ b/samplecode/SampleArc.cpp @@ -17,6 +17,7 @@ #include "Sk1DPathEffect.h" #include "SkCornerPathEffect.h" #include "SkPathMeasure.h" +#include "SkPictureRecorder.h" #include "SkRandom.h" #include "SkColorPriv.h" #include "SkColorFilter.h" @@ -42,8 +43,7 @@ class ArcsView : public SampleView { SkRect fR; SkScalar fSweep; public: - MyDrawable(const SkRect& r) : fR(r), fSweep(0) { - } + MyDrawable(const SkRect& r) : fR(r), fSweep(0) {} void setSweep(SkScalar sweep) { if (fSweep != sweep) { @@ -82,7 +82,8 @@ class ArcsView : public SampleView { public: SkRect fRect; - MyDrawable* fDrawable; + MyDrawable* fAnimatingDrawable; + SkCanvasDrawable* fRootDrawable; ArcsView() { testparse(); @@ -91,16 +92,21 @@ public: fRect.set(0, 0, SkIntToScalar(200), SkIntToScalar(200)); fRect.offset(SkIntToScalar(20), SkIntToScalar(20)); - fDrawable = SkNEW_ARGS(MyDrawable, (fRect)); + fAnimatingDrawable = SkNEW_ARGS(MyDrawable, (fRect)); + + SkPictureRecorder recorder; + this->drawRoot(recorder.beginRecording(SkRect::MakeWH(800, 500))); + fRootDrawable = recorder.EXPERIMENTAL_endRecordingAsDrawable(); } virtual ~ArcsView() SK_OVERRIDE { - fDrawable->unref(); + fAnimatingDrawable->unref(); + fRootDrawable->unref(); } protected: // overrides from SkEventSink - virtual bool onQuery(SkEvent* evt) { + bool onQuery(SkEvent* evt) SK_OVERRIDE { if (SampleCode::TitleQ(*evt)) { SampleCode::TitleR(evt, "Arcs"); return true; @@ -108,7 +114,7 @@ protected: return this->INHERITED::onQuery(evt); } - static void drawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { + static void DrawRectWithLines(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { canvas->drawRect(r, p); canvas->drawLine(r.fLeft, r.fTop, r.fRight, r.fBottom, p); canvas->drawLine(r.fLeft, r.fBottom, r.fRight, r.fTop, p); @@ -116,7 +122,7 @@ protected: canvas->drawLine(r.centerX(), r.fTop, r.centerX(), r.fBottom, p); } - static void draw_label(SkCanvas* canvas, const SkRect& rect, + static void DrawLabel(SkCanvas* canvas, const SkRect& rect, int start, int sweep) { SkPaint paint; @@ -132,7 +138,7 @@ protected: rect.fBottom + paint.getTextSize() * 5/4, paint); } - static void drawArcs(SkCanvas* canvas) { + static void DrawArcs(SkCanvas* canvas) { SkPaint paint; SkRect r; SkScalar w = SkIntToScalar(75); @@ -161,13 +167,13 @@ protected: for (size_t i = 0; i < SK_ARRAY_COUNT(gAngles); i += 2) { paint.setColor(SK_ColorBLACK); - drawRectWithLines(canvas, r, paint); + DrawRectWithLines(canvas, r, paint); paint.setColor(SK_ColorRED); canvas->drawArc(r, SkIntToScalar(gAngles[i]), SkIntToScalar(gAngles[i+1]), false, paint); - draw_label(canvas, r, gAngles[i], gAngles[i+1]); + DrawLabel(canvas, r, gAngles[i], gAngles[i+1]); canvas->translate(w * 8 / 7, 0); } @@ -175,34 +181,31 @@ protected: canvas->restore(); } - virtual void onDrawContent(SkCanvas* canvas) { - fDrawable->setSweep(SampleCode::GetAnimScalar(SkIntToScalar(360)/24, - SkIntToScalar(360))); - + void drawRoot(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setStrokeWidth(SkIntToScalar(2)); paint.setStyle(SkPaint::kStroke_Style); - drawRectWithLines(canvas, fRect, paint); + DrawRectWithLines(canvas, fRect, paint); - canvas->EXPERIMENTAL_drawDrawable(fDrawable); + canvas->EXPERIMENTAL_drawDrawable(fAnimatingDrawable); - drawArcs(canvas); + DrawArcs(canvas); + } + + void onDrawContent(SkCanvas* canvas) SK_OVERRIDE { + fAnimatingDrawable->setSweep(SampleCode::GetAnimScalar(360/24, 360)); + canvas->EXPERIMENTAL_drawDrawable(fRootDrawable); this->inval(NULL); } - virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, - unsigned modi) { + SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) SK_OVERRIDE { // fSweep += SK_Scalar1; this->inval(NULL); return this->INHERITED::onFindClickHandler(x, y, modi); } - virtual bool onClick(Click* click) { - return this->INHERITED::onClick(click); - } - private: SkScalar fSweep; diff --git a/src/core/SkCanvasDrawable.cpp b/src/core/SkCanvasDrawable.cpp index e0120f0bb1..99a4996bc9 100644 --- a/src/core/SkCanvasDrawable.cpp +++ b/src/core/SkCanvasDrawable.cpp @@ -41,8 +41,8 @@ void SkCanvasDrawable::draw(SkCanvas* canvas) { } } -SkPicture* SkCanvasDrawable::newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) { - return this->onNewPictureSnapshot(bbhFactory, recordFlags); +SkPicture* SkCanvasDrawable::newPictureSnapshot() { + return this->onNewPictureSnapshot(); } uint32_t SkCanvasDrawable::getGenerationID() { @@ -64,11 +64,11 @@ void SkCanvasDrawable::notifyDrawingChanged() { #include "SkPictureRecorder.h" -SkPicture* SkCanvasDrawable::onNewPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) { +SkPicture* SkCanvasDrawable::onNewPictureSnapshot() { SkPictureRecorder recorder; const SkRect bounds = this->getBounds(); - SkCanvas* canvas = recorder.beginRecording(bounds, bbhFactory, recordFlags); + SkCanvas* canvas = recorder.beginRecording(bounds, NULL, 0); this->draw(canvas); if (false) { draw_bbox(canvas, bounds); diff --git a/src/core/SkCanvasDrawable.h b/src/core/SkCanvasDrawable.h index f189f2d2cc..bc5b4fd351 100644 --- a/src/core/SkCanvasDrawable.h +++ b/src/core/SkCanvasDrawable.h @@ -10,8 +10,8 @@ #include "SkRefCnt.h" -class SkBBHFactory; class SkCanvas; +class SkPicture; struct SkRect; /** @@ -32,10 +32,7 @@ public: */ void draw(SkCanvas*); - SkPicture* newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags); - SkPicture* newPictureSnapshot() { - return this->newPictureSnapshot(NULL, 0); - } + SkPicture* newPictureSnapshot(); /** * Return a unique value for this instance. If two calls to this return the same value, @@ -63,7 +60,7 @@ public: protected: virtual SkRect onGetBounds() = 0; virtual void onDraw(SkCanvas*) = 0; - virtual SkPicture* onNewPictureSnapshot(SkBBHFactory*, uint32_t recordFlags); + virtual SkPicture* onNewPictureSnapshot(); private: int32_t fGenerationID; diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index b4c3063991..3e006c1672 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -319,7 +319,7 @@ void SkPicture::playback(SkCanvas* canvas, SkDrawPictureCallback* callback) cons (void)canvas->getClipBounds(&clipBounds); const bool useBBH = !clipBounds.contains(this->cullRect()); - SkRecordDraw(*fRecord, canvas, this->drawablePicts(), this->drawableCount(), + SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(), useBBH ? fBBH.get() : NULL, callback); } @@ -474,7 +474,7 @@ SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info, SkPicture const* const drawablePicts[], int drawableCount) { SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/); rec.beginRecording(); - SkRecordDraw(src, &rec, drawablePicts, drawableCount, NULL/*bbh*/, NULL/*callback*/); + SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/); rec.endRecording(); return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/)); } @@ -526,8 +526,8 @@ SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SnapshotArray* dr SkBBoxHierarchy* bbh) : fUniqueID(next_picture_generation_id()) , fCullRect(cullRect) - , fRecord(record) + , fRecord(SkRef(record)) , fBBH(SkSafeRef(bbh)) - , fDrawablePicts(drawablePicts) + , fDrawablePicts(drawablePicts) // take ownership , fAnalysis(*fRecord) {} diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp index 3262938ed1..d64390c6ef 100644 --- a/src/core/SkPictureRecorder.cpp +++ b/src/core/SkPictureRecorder.cpp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +#include "SkCanvasDrawable.h" #include "SkData.h" #include "SkLayerInfo.h" #include "SkPictureRecorder.h" @@ -14,7 +15,7 @@ #include "SkRecordOpts.h" #include "SkTypes.h" -SkPictureRecorder::SkPictureRecorder() {} +SkPictureRecorder::SkPictureRecorder() : fBBHFactory(NULL) {} SkPictureRecorder::~SkPictureRecorder() {} @@ -22,6 +23,7 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect, SkBBHFactory* bbhFactory /* = NULL */, uint32_t recordFlags /* = 0 */) { fCullRect = cullRect; + fBBHFactory = bbhFactory; fFlags = recordFlags; if (bbhFactory) { @@ -38,7 +40,7 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() { return fRecorder.get(); } -SkPicture* SkPictureRecorder::endRecording() { +SkPicture* SkPictureRecorder::endRecordingAsPicture() { // TODO: delay as much of this work until just before first playback? SkRecordOptimize(fRecord); @@ -50,26 +52,23 @@ SkPicture* SkPictureRecorder::endRecording() { saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key))); } + SkCanvasDrawableList* drawableList = fRecorder->getDrawableList(); + SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL; + if (fBBH.get()) { if (saveLayerData) { - SkRecordComputeLayers(fCullRect, *fRecord, fBBH.get(), saveLayerData); + SkRecordComputeLayers(fCullRect, *fRecord, pictList, fBBH.get(), saveLayerData); } else { SkRecordFillBounds(fCullRect, *fRecord, fBBH.get()); } } - // TODO: we should remember these from our caller - SkBBHFactory* factory = NULL; - uint32_t recordFlags = 0; - SkAutoTDelete<SkPicture::SnapshotArray> drawablePicts( - fRecorder->newDrawableSnapshot(factory, recordFlags)); - SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord.detach(), - drawablePicts.detach(), fBBH.get())); + SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH)); if (saveLayerData) { pict->EXPERIMENTAL_addAccelData(saveLayerData); } - + return pict; } @@ -79,5 +78,86 @@ void SkPictureRecorder::partialReplay(SkCanvas* canvas) const { } int drawableCount = 0; - SkRecordDraw(*fRecord, canvas, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/); + SkCanvasDrawable* const* drawables = NULL; + SkCanvasDrawableList* drawableList = fRecorder->getDrawableList(); + if (drawableList) { + drawableCount = drawableList->count(); + drawables = drawableList->begin(); + } + SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, NULL/*bbh*/, NULL/*callback*/); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class SkRecordedDrawable : public SkCanvasDrawable { + SkAutoTUnref<SkRecord> fRecord; + SkAutoTUnref<SkBBoxHierarchy> fBBH; + SkAutoTDelete<SkCanvasDrawableList> fDrawableList; + const SkRect fBounds; + const bool fDoSaveLayerInfo; + +public: + SkRecordedDrawable(SkRecord* record, SkBBoxHierarchy* bbh, SkCanvasDrawableList* drawableList, + const SkRect& bounds, bool doSaveLayerInfo) + : fRecord(SkRef(record)) + , fBBH(SkSafeRef(bbh)) + , fDrawableList(drawableList) // we take ownership + , fBounds(bounds) + , fDoSaveLayerInfo(doSaveLayerInfo) + {} + +protected: + SkRect onGetBounds() SK_OVERRIDE { return fBounds; } + + void onDraw(SkCanvas* canvas) SK_OVERRIDE { + SkCanvasDrawable* const* drawables = NULL; + int drawableCount = 0; + if (fDrawableList) { + drawables = fDrawableList->begin(); + drawableCount = fDrawableList->count(); + } + SkRecordDraw(*fRecord, canvas, NULL, drawables, drawableCount, fBBH, NULL/*callback*/); + } + + SkPicture* onNewPictureSnapshot() SK_OVERRIDE { + SkPicture::SnapshotArray* pictList = NULL; + if (fDrawableList) { + // TODO: should we plumb-down the BBHFactory and recordFlags from our host + // PictureRecorder? + pictList = fDrawableList->newDrawableSnapshot(); + } + + SkAutoTUnref<SkLayerInfo> saveLayerData; + + if (fBBH && fDoSaveLayerInfo) { + SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); + + saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key))); + + SkBBoxHierarchy* bbh = NULL; // we've already computed fBBH (received in constructor) + // TODO: update saveLayer info computation to reuse the already computed + // bounds in 'fBBH' + SkRecordComputeLayers(fBounds, *fRecord, pictList, bbh, saveLayerData); + } + + SkPicture* pict = SkNEW_ARGS(SkPicture, (fBounds, fRecord, pictList, fBBH)); + + if (saveLayerData) { + pict->EXPERIMENTAL_addAccelData(saveLayerData); + } + return pict; + } +}; + +SkCanvasDrawable* SkPictureRecorder::EXPERIMENTAL_endRecordingAsDrawable() { + // TODO: delay as much of this work until just before first playback? + SkRecordOptimize(fRecord); + + if (fBBH.get()) { + SkRecordFillBounds(fCullRect, *fRecord, fBBH.get()); + } + + return SkNEW_ARGS(SkRecordedDrawable, (fRecord, fBBH, fRecorder->detachDrawableList(), + fCullRect, + SkToBool(fFlags & kComputeSaveLayerInfo_RecordFlag))); } diff --git a/src/core/SkRecord.h b/src/core/SkRecord.h index 403110d385..8179b06376 100644 --- a/src/core/SkRecord.h +++ b/src/core/SkRecord.h @@ -25,7 +25,7 @@ // only with SkRecords::* structs defined in SkRecords.h. Your compiler will helpfully yell if you // get this wrong. -class SkRecord : SkNoncopyable { +class SkRecord : public SkNVRefCnt<SkRecord> { enum { kFirstReserveCount = 64 / sizeof(void*), }; @@ -240,6 +240,6 @@ private: // Strangely the order of these fields matters. If the unsigneds don't go first we're 56 bytes. // tomhudson and mtklein have no idea why. }; -SK_COMPILE_ASSERT(sizeof(SkRecord) <= 48, SkRecordSize); +SK_COMPILE_ASSERT(sizeof(SkRecord) <= 56, SkRecordSize); #endif//SkRecord_DEFINED diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp index 7e35d8a2c7..5e1fe7f0aa 100644 --- a/src/core/SkRecordDraw.cpp +++ b/src/core/SkRecordDraw.cpp @@ -11,7 +11,9 @@ void SkRecordDraw(const SkRecord& record, SkCanvas* canvas, - SkPicture const* const drawablePicts[], int drawableCount, + SkPicture const* const drawablePicts[], + SkCanvasDrawable* const drawables[], + int drawableCount, const SkBBoxHierarchy* bbh, SkDrawPictureCallback* callback) { SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/); @@ -32,7 +34,7 @@ void SkRecordDraw(const SkRecord& record, SkTDArray<unsigned> ops; bbh->search(query, &ops); - SkRecords::Draw draw(canvas, drawablePicts, drawableCount); + SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); for (int i = 0; i < ops.count(); i++) { if (callback && callback->abortDrawing()) { return; @@ -44,7 +46,7 @@ void SkRecordDraw(const SkRecord& record, } } else { // Draw all ops. - SkRecords::Draw draw(canvas, drawablePicts, drawableCount); + SkRecords::Draw draw(canvas, drawablePicts, drawables, drawableCount); for (unsigned i = 0; i < record.count(); i++) { if (callback && callback->abortDrawing()) { return; @@ -133,7 +135,12 @@ DRAW(DrawData, drawData(r.data, r.length)); template <> void Draw::draw(const DrawDrawable& r) { SkASSERT(r.index >= 0); SkASSERT(r.index < fDrawableCount); - fCanvas->drawPicture(fDrawablePicts[r.index]); + if (fDrawables) { + SkASSERT(NULL == fDrawablePicts); + fCanvas->EXPERIMENTAL_drawDrawable(fDrawables[r.index]); + } else { + fCanvas->drawPicture(fDrawablePicts[r.index]); + } } // This is an SkRecord visitor that fills an SkBBoxHierarchy. @@ -159,7 +166,8 @@ public: FillBounds(const SkRect& cullRect, const SkRecord& record) : fNumRecords(record.count()) , fCullRect(cullRect) - , fBounds(record.count()) { + , fBounds(record.count()) + { // Calculate bounds for all ops. This won't go quite in order, so we'll need // to store the bounds separately then feed them in to the BBH later in order. fCTM = &SkMatrix::I(); @@ -591,11 +599,13 @@ private: // SkRecord visitor to gather saveLayer/restore information. class CollectLayers : SkNoncopyable { public: - CollectLayers(const SkRect& cullRect, const SkRecord& record, SkLayerInfo* accelData) + CollectLayers(const SkRect& cullRect, const SkRecord& record, + const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData) : fSaveLayersInStack(0) , fAccelData(accelData) - , fFillBounds(cullRect, record) { - } + , fPictList(pictList) + , fFillBounds(cullRect, record) + {} void setCurrentOp(unsigned currentOp) { fFillBounds.setCurrentOp(currentOp); } @@ -638,13 +648,13 @@ private: void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.paint); } void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); } - void trackSaveLayers(const DrawPicture& dp) { + void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) { // For sub-pictures, we wrap their layer information within the parent // picture's rendering hierarchy SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey(); const SkLayerInfo* childData = - static_cast<const SkLayerInfo*>(dp.picture->EXPERIMENTAL_getAccelData(key)); + static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key)); if (!childData) { // If the child layer hasn't been generated with saveLayer data we // assume the worst (i.e., that it does contain layers which nest @@ -658,7 +668,7 @@ private: for (int i = 0; i < childData->numBlocks(); ++i) { const SkLayerInfo::BlockInfo& src = childData->block(i); - FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, dp.paint); + FillBounds::Bounds newBound = fFillBounds.adjustAndMap(src.fBounds, paint); if (newBound.isEmpty()) { continue; } @@ -669,7 +679,7 @@ private: // If src.fPicture is NULL the layer is in dp.picture; otherwise // it belongs to a sub-picture. - dst.fPicture = src.fPicture ? src.fPicture : static_cast<const SkPicture*>(dp.picture); + dst.fPicture = src.fPicture ? src.fPicture : picture; dst.fPicture->ref(); dst.fBounds = newBound; dst.fLocalMat = src.fLocalMat; @@ -685,6 +695,17 @@ private: } } + void trackSaveLayers(const DrawPicture& dp) { + this->trackSaveLayersForPicture(dp.picture, dp.paint); + } + + void trackSaveLayers(const DrawDrawable& dp) { + SkASSERT(fPictList); + SkASSERT(dp.index >= 0 && dp.index < fPictList->count()); + const SkPaint* paint = NULL; // drawables don't get a side-car paint + this->trackSaveLayersForPicture(fPictList->begin()[dp.index], paint); + } + // Inform all the saveLayers already on the stack that they now have a // nested saveLayer inside them void updateStackForSaveLayer() { @@ -743,6 +764,7 @@ private: int fSaveLayersInStack; SkTDArray<SaveLayerInfo> fSaveLayerStack; SkLayerInfo* fAccelData; + const SkPicture::SnapshotArray* fPictList; SkRecords::FillBounds fFillBounds; }; @@ -761,8 +783,9 @@ void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi } void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record, - SkBBoxHierarchy* bbh, SkLayerInfo* data) { - SkRecords::CollectLayers visitor(cullRect, record, data); + const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh, + SkLayerInfo* data) { + SkRecords::CollectLayers visitor(cullRect, record, pictList, data); for (unsigned curOp = 0; curOp < record.count(); curOp++) { visitor.setCurrentOp(curOp); diff --git a/src/core/SkRecordDraw.h b/src/core/SkRecordDraw.h index 8ea1bbd72f..e95123bbe6 100644 --- a/src/core/SkRecordDraw.h +++ b/src/core/SkRecordDraw.h @@ -14,16 +14,19 @@ #include "SkMatrix.h" #include "SkRecord.h" +class SkCanvasDrawable; class SkLayerInfo; // Fill a BBH to be used by SkRecordDraw to accelerate playback. void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy*); void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record, + const SkPicture::SnapshotArray*, SkBBoxHierarchy* bbh, SkLayerInfo* data); // Draw an SkRecord into an SkCanvas. A convenience wrapper around SkRecords::Draw. -void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[], int drawableCount, +void SkRecordDraw(const SkRecord&, SkCanvas*, SkPicture const* const drawablePicts[], + SkCanvasDrawable* const drawables[], int drawableCount, const SkBBoxHierarchy*, SkDrawPictureCallback*); // Draw a portion of an SkRecord into an SkCanvas while replacing clears with drawRects. @@ -41,11 +44,13 @@ namespace SkRecords { // This is an SkRecord visitor that will draw that SkRecord to an SkCanvas. class Draw : SkNoncopyable { public: - explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount, + explicit Draw(SkCanvas* canvas, SkPicture const* const drawablePicts[], + SkCanvasDrawable* const drawables[], int drawableCount, const SkMatrix* initialCTM = NULL) : fInitialCTM(initialCTM ? *initialCTM : canvas->getTotalMatrix()) , fCanvas(canvas) , fDrawablePicts(drawablePicts) + , fDrawables(drawables) , fDrawableCount(drawableCount) {} @@ -67,6 +72,7 @@ private: const SkMatrix fInitialCTM; SkCanvas* fCanvas; SkPicture const* const* fDrawablePicts; + SkCanvasDrawable* const* fDrawables; int fDrawableCount; }; @@ -75,7 +81,8 @@ class PartialDraw : public Draw { public: PartialDraw(SkCanvas* canvas, SkPicture const* const drawablePicts[], int drawableCount, const SkRect& clearRect, const SkMatrix& initialCTM) - : INHERITED(canvas, drawablePicts, drawableCount, &initialCTM), fClearRect(clearRect) {} + : INHERITED(canvas, drawablePicts, NULL, drawableCount, &initialCTM), fClearRect(clearRect) + {} // Same as Draw for all ops except Clear. template <typename T> void operator()(const T& r) { diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp index 22d742f3e7..3548851a72 100644 --- a/src/core/SkRecorder.cpp +++ b/src/core/SkRecorder.cpp @@ -9,6 +9,28 @@ #include "SkPatchUtils.h" #include "SkPicture.h" +SkCanvasDrawableList::~SkCanvasDrawableList() { + fArray.unrefAll(); +} + +SkPicture::SnapshotArray* SkCanvasDrawableList::newDrawableSnapshot() { + const int count = fArray.count(); + if (0 == count) { + return NULL; + } + SkAutoTMalloc<const SkPicture*> pics(count); + for (int i = 0; i < count; ++i) { + pics[i] = fArray[i]->newPictureSnapshot(); + } + return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count)); +} + +void SkCanvasDrawableList::append(SkCanvasDrawable* drawable) { + *fArray.append() = SkRef(drawable); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + SkRecorder::SkRecorder(SkRecord* record, int width, int height) : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag) , fRecord(record) @@ -19,29 +41,11 @@ SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds) , fRecord(record) , fSaveLayerCount(0) {} -SkRecorder::~SkRecorder() { - fDrawableList.unrefAll(); -} - void SkRecorder::forgetRecord() { - fDrawableList.unrefAll(); - fDrawableList.reset(); + fDrawableList.reset(NULL); fRecord = NULL; } -SkPicture::SnapshotArray* SkRecorder::newDrawableSnapshot(SkBBHFactory* factory, - uint32_t recordFlags) { - const int count = fDrawableList.count(); - if (0 == count) { - return NULL; - } - SkAutoTMalloc<const SkPicture*> pics(count); - for (int i = 0; i < count; ++i) { - pics[i] = fDrawableList[i]->newPictureSnapshot(factory, recordFlags); - } - return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count)); -} - // To make appending to fRecord a little less verbose. #define APPEND(T, ...) \ SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__)) @@ -146,8 +150,11 @@ void SkRecorder::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const } void SkRecorder::onDrawDrawable(SkCanvasDrawable* drawable) { - *fDrawableList.append() = SkRef(drawable); - APPEND(DrawDrawable, drawable->getBounds(), fDrawableList.count() - 1); + if (!fDrawableList) { + fDrawableList.reset(SkNEW(SkCanvasDrawableList)); + } + fDrawableList->append(drawable); + APPEND(DrawDrawable, drawable->getBounds(), fDrawableList->count() - 1); } void SkRecorder::drawPath(const SkPath& path, const SkPaint& paint) { diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h index b532c89060..be67dddd2e 100644 --- a/src/core/SkRecorder.h +++ b/src/core/SkRecorder.h @@ -13,6 +13,24 @@ #include "SkRecords.h" #include "SkTDArray.h" +class SkBBHFactory; + +class SkCanvasDrawableList : SkNoncopyable { +public: + ~SkCanvasDrawableList(); + + int count() const { return fArray.count(); } + SkCanvasDrawable* const* begin() const { return fArray.begin(); } + + void append(SkCanvasDrawable* drawable); + + // Return a new or ref'd array of pictures that were snapped from our drawables. + SkPicture::SnapshotArray* newDrawableSnapshot(); + +private: + SkTDArray<SkCanvasDrawable*> fArray; +}; + // SkRecorder provides an SkCanvas interface for recording into an SkRecord. class SkRecorder : public SkCanvas { @@ -20,10 +38,9 @@ public: // Does not take ownership of the SkRecord. SkRecorder(SkRecord*, int width, int height); // legacy version SkRecorder(SkRecord*, const SkRect& bounds); - virtual ~SkRecorder() SK_OVERRIDE; - // Return a new or ref'd array of pictures that were snapped from our drawables. - SkPicture::SnapshotArray* newDrawableSnapshot(SkBBHFactory*, uint32_t recordFlags); + SkCanvasDrawableList* getDrawableList() const { return fDrawableList.get(); } + SkCanvasDrawableList* detachDrawableList() { return fDrawableList.detach(); } // Make SkRecorder forget entirely about its SkRecord*; all calls to SkRecorder will fail. void forgetRecord(); @@ -145,7 +162,7 @@ private: int fSaveLayerCount; SkTDArray<SkBool8> fSaveIsSaveLayer; - SkTDArray<SkCanvasDrawable*> fDrawableList; + SkAutoTDelete<SkCanvasDrawableList> fDrawableList; }; #endif//SkRecorder_DEFINED diff --git a/src/gpu/GrRecordReplaceDraw.cpp b/src/gpu/GrRecordReplaceDraw.cpp index 49ddf9a76c..dd686d33b9 100644 --- a/src/gpu/GrRecordReplaceDraw.cpp +++ b/src/gpu/GrRecordReplaceDraw.cpp @@ -60,7 +60,7 @@ public: const GrReplacements* replacements, const SkMatrix& initialMatrix, SkDrawPictureCallback* callback) - : INHERITED(canvas, drawablePicts, drawableCount) + : INHERITED(canvas, drawablePicts, NULL, drawableCount) , fCanvas(canvas) , fPicture(picture) , fReplacements(replacements) diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index ab2fcb7239..64073d3b00 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -1733,7 +1733,8 @@ static void test_bytes_used(skiatest::Reporter* reporter) { sizeof(SkPicture) + sizeof(SkRecord)); // Protect against any unintentional bloat. - REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) <= 128); + size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get()); + REPORTER_ASSERT(reporter, approxUsed <= 136); // Sanity check of nested SkPictures. SkPictureRecorder r2; @@ -1905,11 +1906,16 @@ DEF_TEST(Picture_BitmapLeak, r) { REPORTER_ASSERT(r, mut.pixelRef()->unique()); REPORTER_ASSERT(r, immut.pixelRef()->unique()); - SkPictureRecorder rec; - SkCanvas* canvas = rec.beginRecording(1920, 1200); - canvas->drawBitmap(mut, 0, 0); - canvas->drawBitmap(immut, 800, 600); - SkAutoTUnref<const SkPicture> pic(rec.endRecording()); + SkAutoTUnref<const SkPicture> pic; + { + // we want the recorder to go out of scope before our subsequent checks, so we + // place it inside local braces. + SkPictureRecorder rec; + SkCanvas* canvas = rec.beginRecording(1920, 1200); + canvas->drawBitmap(mut, 0, 0); + canvas->drawBitmap(immut, 800, 600); + pic.reset(rec.endRecording()); + } // The picture shares the immutable pixels but copies the mutable ones. REPORTER_ASSERT(r, mut.pixelRef()->unique()); diff --git a/tests/RecordDrawTest.cpp b/tests/RecordDrawTest.cpp index b7538f1e9a..48981ef0a2 100644 --- a/tests/RecordDrawTest.cpp +++ b/tests/RecordDrawTest.cpp @@ -41,7 +41,7 @@ DEF_TEST(RecordDraw_Abort, r) { SkRecorder canvas(&rerecord, W, H); JustOneDraw callback; - SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, &callback); + SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, &callback); REPORTER_ASSERT(r, 3 == rerecord.count()); assert_type<SkRecords::Save> (r, rerecord, 0); @@ -56,7 +56,7 @@ DEF_TEST(RecordDraw_Unbalanced, r) { SkRecord rerecord; SkRecorder canvas(&rerecord, W, H); - SkRecordDraw(record, &canvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/); + SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL/*bbh*/, NULL/*callback*/); REPORTER_ASSERT(r, 4 == rerecord.count()); assert_type<SkRecords::Save> (r, rerecord, 0); @@ -80,7 +80,7 @@ DEF_TEST(RecordDraw_SetMatrixClobber, r) { translate.setTranslate(20, 20); translateCanvas.setMatrix(translate); - SkRecordDraw(scaleRecord, &translateCanvas, NULL, 0, NULL/*bbh*/, NULL/*callback*/); + SkRecordDraw(scaleRecord, &translateCanvas, NULL, NULL, 0, NULL/*bbh*/, NULL/*callback*/); REPORTER_ASSERT(r, 4 == translateRecord.count()); assert_type<SkRecords::SetMatrix>(r, translateRecord, 0); assert_type<SkRecords::Save> (r, translateRecord, 1); @@ -320,7 +320,7 @@ DEF_TEST(RecordDraw_drawImage, r){ SkRecord record; SkRecorder recorder(&record, 10, 10); recorder.drawImage(image, 0, 0); - SkRecordDraw(record, &canvas, NULL, 0, NULL, 0); + SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0); } REPORTER_ASSERT(r, canvas.fDrawImageCalled); canvas.resetTestValues(); @@ -329,7 +329,7 @@ DEF_TEST(RecordDraw_drawImage, r){ SkRecord record; SkRecorder recorder(&record, 10, 10); recorder.drawImageRect(image, 0, SkRect::MakeWH(10, 10)); - SkRecordDraw(record, &canvas, NULL, 0, NULL, 0); + SkRecordDraw(record, &canvas, NULL, NULL, 0, NULL, 0); } REPORTER_ASSERT(r, canvas.fDrawImageRectCalled); diff --git a/tools/DumpRecord.cpp b/tools/DumpRecord.cpp index 2d055169c1..4f05fd46c1 100644 --- a/tools/DumpRecord.cpp +++ b/tools/DumpRecord.cpp @@ -21,7 +21,7 @@ public: : fDigits(0) , fIndent(0) , fIndex(0) - , fDraw(canvas, NULL, 0, NULL) + , fDraw(canvas, NULL, NULL, 0, NULL) , fTimeWithCommand(timeWithCommand) { while (count > 0) { count /= 10; |