diff options
author | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-17 14:56:13 +0000 |
---|---|---|
committer | robertphillips@google.com <robertphillips@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2014-03-17 14:56:13 +0000 |
commit | 0b23f9e15f87363249cb66db2dd9918bc42d72ab (patch) | |
tree | 12c28a5bb6e9342732d30da5cffceb1790f58df4 | |
parent | d1c85d29204ad94950b23014c03e781409b9b682 (diff) |
Add a means of extracting active operations from SkPicture
https://codereview.chromium.org/195793010/
git-svn-id: http://skia.googlecode.com/svn/trunk@13831 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkPicture.h | 28 | ||||
-rw-r--r-- | src/core/SkPicture.cpp | 13 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.cpp | 76 | ||||
-rw-r--r-- | src/core/SkPicturePlayback.h | 27 |
4 files changed, 128 insertions, 16 deletions
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index 3718d3a579..d600ab943b 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -308,11 +308,39 @@ protected: // SkBBoxHierarchy implementation virtual SkBBoxHierarchy* createBBoxHierarchy() const; private: + // An OperationList encapsulates a set of operation offsets into the picture byte + // stream along with the CTMs needed for those operation. + class OperationList : public SkNoncopyable { + public: + // If valid returns false then there is no optimization data + // present. All the draw operations need to be issued. + virtual bool valid() const { return false; } + + // The following three entry points should only be accessed if + // 'valid' returns true. + virtual int numOps() const { SkASSERT(false); return 0; }; + // The offset in the picture of the operation to execute. + virtual uint32_t offset(int index) const { SkASSERT(false); return 0; }; + // The CTM that must be installed for the operation to behave correctly + virtual const SkMatrix& matrix(int index) const { SkASSERT(false); return SkMatrix::I(); } + + static const OperationList& InvalidList(); + + private: + typedef SkNoncopyable INHERITED; + }; + + /** PRIVATE / EXPERIMENTAL -- do not call + Return the operations required to render the content inside 'queryRect'. + */ + const OperationList& EXPERIMENTAL_getActiveOps(const SkIRect& queryRect); + void createHeader(SkPictInfo* info) const; static bool IsValidPictInfo(const SkPictInfo& info); friend class SkFlatPicture; friend class SkPicturePlayback; + friend class SkGpuDevice; typedef SkRefCnt INHERITED; }; diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp index 1285ff1eef..b3dd6a4f07 100644 --- a/src/core/SkPicture.cpp +++ b/src/core/SkPicture.cpp @@ -264,6 +264,19 @@ void SkPicture::endRecording() { SkASSERT(NULL == fRecord); } +const SkPicture::OperationList& SkPicture::OperationList::InvalidList() { + static OperationList gInvalid; + return gInvalid; +} + +const SkPicture::OperationList& SkPicture::EXPERIMENTAL_getActiveOps(const SkIRect& queryRect) { + this->endRecording(); + if (NULL != fPlayback) { + return fPlayback->getActiveOps(queryRect); + } + return OperationList::InvalidList(); +} + void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) { this->endRecording(); if (NULL != fPlayback) { diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp index d61e616c4d..c989061619 100644 --- a/src/core/SkPicturePlayback.cpp +++ b/src/core/SkPicturePlayback.cpp @@ -69,7 +69,7 @@ SkPicturePlayback::SkPicturePlayback(const SkPictureRecord& record, bool deepCop record.validate(record.writeStream().bytesWritten(), 0); const SkWriter32& writer = record.writeStream(); - init(); + this->init(); SkASSERT(!fOpData); if (writer.bytesWritten() == 0) { fOpData = SkData::NewEmpty(); @@ -261,6 +261,7 @@ void SkPicturePlayback::init() { fFactoryPlayback = NULL; fBoundingHierarchy = NULL; fStateTree = NULL; + fCachedActiveOps = NULL; } SkPicturePlayback::~SkPicturePlayback() { @@ -271,6 +272,8 @@ SkPicturePlayback::~SkPicturePlayback() { SkSafeUnref(fBoundingHierarchy); SkSafeUnref(fStateTree); + SkDELETE(fCachedActiveOps); + for (int i = 0; i < fPictureCount; i++) { fPictureRefs[i]->unref(); } @@ -754,8 +757,13 @@ static DrawType read_op_and_size(SkReader32* reader, uint32_t* size) { // The activeOps parameter is actually "const SkTDArray<SkPictureStateTree::Draw*>&". // It represents the operations about to be drawn, as generated by some spatial // subdivision helper class. It should already be in 'fOffset' sorted order. -void SkPicturePlayback::preLoadBitmaps(const SkTDArray<void*>& activeOps) { - if (0 == activeOps.count() || NULL == fBitmapUseOffsets) { +void SkPicturePlayback::preLoadBitmaps(const SkTDArray<void*>* activeOps) { + if ((NULL != activeOps && 0 == activeOps->count()) || NULL == fBitmapUseOffsets) { + return; + } + + if (NULL == activeOps) { + // going to need everything return; } @@ -766,10 +774,10 @@ void SkPicturePlayback::preLoadBitmaps(const SkTDArray<void*>& activeOps) { needToCheck.get()[i] = true; } - uint32_t max = ((SkPictureStateTree::Draw*)activeOps[activeOps.count()-1])->fOffset; + uint32_t max = ((SkPictureStateTree::Draw*)(*activeOps)[(*activeOps).count()-1])->fOffset; - for (int i = 0; i < activeOps.count(); ++i) { - SkPictureStateTree::Draw* draw = (SkPictureStateTree::Draw*) activeOps[i]; + for (int i = 0; i < activeOps->count(); ++i) { + SkPictureStateTree::Draw* draw = (SkPictureStateTree::Draw*) (*activeOps)[i]; for (int j = 0; j < fBitmapUseOffsets->numIDs(); ++j) { if (!needToCheck.get()[j]) { @@ -795,6 +803,41 @@ void SkPicturePlayback::preLoadBitmaps(const SkTDArray<void*>& activeOps) { } } +uint32_t SkPicturePlayback::CachedOperationList::offset(int index) const { + SkASSERT(index < fOps.count()); + return ((SkPictureStateTree::Draw*)fOps[index])->fOffset; +} + +const SkMatrix& SkPicturePlayback::CachedOperationList::matrix(int index) const { + SkASSERT(index < fOps.count()); + return *((SkPictureStateTree::Draw*)fOps[index])->fMatrix; +} + +const SkPicture::OperationList& SkPicturePlayback::getActiveOps(const SkIRect& query) { + if (NULL == fStateTree || NULL == fBoundingHierarchy) { + return SkPicture::OperationList::InvalidList(); + } + + if (NULL == fCachedActiveOps) { + fCachedActiveOps = SkNEW(CachedOperationList); + } + + if (query == fCachedActiveOps->fCacheQueryRect) { + return *fCachedActiveOps; + } + + fCachedActiveOps->fOps.rewind(); + + fBoundingHierarchy->search(query, &(fCachedActiveOps->fOps)); + + SkTQSort<SkPictureStateTree::Draw>( + reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.begin()), + reinterpret_cast<SkPictureStateTree::Draw**>(fCachedActiveOps->fOps.end()-1)); + + fCachedActiveOps->fCacheQueryRect = query; + return *fCachedActiveOps; +} + void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) { #ifdef ENABLE_TIME_DRAW SkAutoTime at("SkPicture::draw", 50); @@ -815,26 +858,29 @@ void SkPicturePlayback::draw(SkCanvas& canvas, SkDrawPictureCallback* callback) SkReader32 reader(fOpData->bytes(), fOpData->size()); TextContainer text; - SkTDArray<void*> activeOps; + const SkTDArray<void*>* activeOps = NULL; if (NULL != fStateTree && NULL != fBoundingHierarchy) { SkRect clipBounds; if (canvas.getClipBounds(&clipBounds)) { SkIRect query; clipBounds.roundOut(&query); - fBoundingHierarchy->search(query, &activeOps); - if (activeOps.count() == 0) { - return; + + const SkPicture::OperationList& activeOpsList = this->getActiveOps(query); + if (activeOpsList.valid()) { + if (0 == activeOpsList.numOps()) { + return; // nothing to draw + } + + // Since the opList is valid we know it is our derived class + activeOps = &((const CachedOperationList&)activeOpsList).fOps; } - SkTQSort<SkPictureStateTree::Draw>( - reinterpret_cast<SkPictureStateTree::Draw**>(activeOps.begin()), - reinterpret_cast<SkPictureStateTree::Draw**>(activeOps.end()-1)); } } - SkPictureStateTree::Iterator it = (NULL == fStateTree) ? + SkPictureStateTree::Iterator it = (NULL == activeOps) ? SkPictureStateTree::Iterator() : - fStateTree->getIterator(activeOps, &canvas); + fStateTree->getIterator(*activeOps, &canvas); if (it.isValid()) { uint32_t skipTo = it.draw(); diff --git a/src/core/SkPicturePlayback.h b/src/core/SkPicturePlayback.h index 512f24a77e..11624205d4 100644 --- a/src/core/SkPicturePlayback.h +++ b/src/core/SkPicturePlayback.h @@ -85,6 +85,8 @@ public: virtual ~SkPicturePlayback(); + const SkPicture::OperationList& getActiveOps(const SkIRect& queryRect); + void draw(SkCanvas& canvas, SkDrawPictureCallback*); void serialize(SkWStream*, SkPicture::EncodeBitmap) const; @@ -109,7 +111,7 @@ protected: virtual void postDraw(int opIndex); #endif - void preLoadBitmaps(const SkTDArray<void*>& results); + void preLoadBitmaps(const SkTDArray<void*>* results); private: class TextContainer { @@ -237,6 +239,29 @@ private: SkBBoxHierarchy* fBoundingHierarchy; SkPictureStateTree* fStateTree; + class CachedOperationList : public SkPicture::OperationList { + public: + CachedOperationList() { + fCacheQueryRect.setEmpty(); + } + + virtual bool valid() const { return true; } + virtual int numOps() const SK_OVERRIDE { return fOps.count(); } + virtual uint32_t offset(int index) const SK_OVERRIDE; + virtual const SkMatrix& matrix(int index) const SK_OVERRIDE; + + // The query rect for which the cached active ops are valid + SkIRect fCacheQueryRect; + + // The operations which are active within 'fCachedQueryRect' + SkTDArray<void*> fOps; + + private: + typedef SkPicture::OperationList INHERITED; + }; + + CachedOperationList* fCachedActiveOps; + SkTypefacePlayback fTFPlayback; SkFactoryPlayback* fFactoryPlayback; #ifdef SK_BUILD_FOR_ANDROID |