bool suitableForGpuRasterization(GrContext*, const char ** = NULL) const;
#endif
- class DeletionListener : public SkRefCnt {
- public:
- virtual void onDeletion(uint32_t pictureID) = 0;
- };
-
- // Takes ref on listener.
- void addDeletionListener(DeletionListener* listener) const;
-
/** Return the approximate number of operations in this picture. This
* number may be greater or less than the number of SkCanvas calls
* recorded: some calls may be recorded as more than one operation, or some
int fCount;
};
+ // Sent via SkMessageBus from destructor.
+ struct DeletionMessage { int32_t fUniqueID; };
+
private:
// V2 : adds SkPixelRef's generation ID.
// V3 : PictInfo tag at beginning, and EOF tag at the end
static const uint32_t MIN_PICTURE_VERSION = 19;
static const uint32_t CURRENT_PICTURE_VERSION = 37;
- void callDeletionListeners();
-
void createHeader(SkPictInfo* info) const;
static bool IsValidPictInfo(const SkPictInfo& info);
const uint32_t fUniqueID;
const SkRect fCullRect;
mutable SkAutoTUnref<const AccelData> fAccelData;
- mutable SkTDArray<DeletionListener*> fDeletionListeners; // pointers are refed
SkAutoTDelete<const SkRecord> fRecord;
SkAutoTUnref<const SkBBoxHierarchy> fBBH;
SkAutoTDelete<const SnapshotArray> fDrawablePicts;
#include "SkCanvas.h"
#include "SkChunkAlloc.h"
#include "SkDrawPictureCallback.h"
+#include "SkMessageBus.h"
#include "SkPaintPriv.h"
#include "SkPathEffect.h"
#include "SkPicture.h"
#include "SkRecordOpts.h"
#include "SkRecorder.h"
+DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
+
template <typename T> int SafeCount(const T* obj) {
return obj ? obj->count() : 0;
}
}
SkPicture::~SkPicture() {
- this->callDeletionListeners();
+ SkPicture::DeletionMessage msg;
+ msg.fUniqueID = this->uniqueID();
+ SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
}
void SkPicture::EXPERIMENTAL_addAccelData(const SkPicture::AccelData* data) const {
, fDrawablePicts(drawablePicts)
, fAnalysis(*fRecord)
{}
-
-// Note that we are assuming that this entry point will only be called from
-// one thread. Currently the only client of this method is
-// SkGpuDevice::EXPERIMENTAL_optimize which should be only called from a single
-// thread.
-void SkPicture::addDeletionListener(DeletionListener* listener) const {
- SkASSERT(listener);
-
- *fDeletionListeners.append() = SkRef(listener);
-}
-
-void SkPicture::callDeletionListeners() {
- for (int i = 0; i < fDeletionListeners.count(); ++i) {
- fDeletionListeners[i]->onDeletion(this->uniqueID());
- }
-
- fDeletionListeners.unrefAll();
-}
#include "GrLayerCache.h"
#include "GrSurfacePriv.h"
-DECLARE_SKMESSAGEBUS_MESSAGE(GrPictureDeletedMessage);
-
#ifdef SK_DEBUG
void GrCachedLayer::validate(const GrTexture* backingTexture) const {
SkASSERT(SK_InvalidGenID != fKey.pictureID());
class GrAutoValidateLayer : ::SkNoncopyable {
public:
- GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer)
+ GrAutoValidateLayer(GrTexture* backingTexture, const GrCachedLayer* layer)
: fBackingTexture(backingTexture)
, fLayer(layer) {
if (fLayer) {
SkASSERT(0 == fPictureHash.count());
- // The atlas only lets go of its texture when the atlas is deleted.
- fAtlas.free();
+ // The atlas only lets go of its texture when the atlas is deleted.
+ fAtlas.free();
}
void GrLayerCache::initAtlas() {
}
fLayerHash.rewind();
- // The atlas only lets go of its texture when the atlas is deleted.
+ // The atlas only lets go of its texture when the atlas is deleted.
fAtlas.free();
}
-GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
- int start, int stop,
+GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
+ int start, int stop,
const SkIRect& bounds,
const SkMatrix& ctm,
const SkPaint* paint) {
}
GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID,
- int start,
+ int start,
const SkIRect& bounds,
const SkMatrix& ctm) {
SkASSERT(pictureID != SK_InvalidGenID && start > 0);
return layer;
}
-bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
- const GrSurfaceDesc& desc,
+bool GrLayerCache::tryToAtlas(GrCachedLayer* layer,
+ const GrSurfaceDesc& desc,
bool* needsRendering) {
SkDEBUGCODE(GrAutoValidateLayer avl(fAtlas ? fAtlas->getTexture() : NULL, layer);)
return true;
}
- // The layer was rejected by the atlas (even though we know it is
+ // The layer was rejected by the atlas (even though we know it is
// plausibly atlas-able). See if a plot can be purged and try again.
if (!this->purgePlot()) {
break; // We weren't able to purge any plots
SkDELETE(pictInfo);
}
}
-
+
layer->setPlot(NULL);
layer->setTexture(NULL, GrIRect16::MakeEmpty());
#endif
if (layer->locked()) {
plotLocks[layer->plot()->id()]++;
}
- }
+ }
}
for (int i = 0; i < kNumPlotsX*kNumPlotsY; ++i) {
}
#endif
-class GrPictureDeletionListener : public SkPicture::DeletionListener {
- virtual void onDeletion(uint32_t pictureID) SK_OVERRIDE{
- const GrPictureDeletedMessage message = { pictureID };
- SkMessageBus<GrPictureDeletedMessage>::Post(message);
- }
-};
-
-void GrLayerCache::trackPicture(const SkPicture* picture) {
- if (NULL == fDeletionListener) {
- fDeletionListener.reset(SkNEW(GrPictureDeletionListener));
- }
-
- picture->addDeletionListener(fDeletionListener);
-}
-
void GrLayerCache::processDeletedPictures() {
- SkTDArray<GrPictureDeletedMessage> deletedPictures;
+ SkTDArray<SkPicture::DeletionMessage> deletedPictures;
fPictDeletionInbox.poll(&deletedPictures);
for (int i = 0; i < deletedPictures.count(); i++) {
- this->purge(deletedPictures[i].pictureID);
+ this->purge(deletedPictures[i].fUniqueID);
}
}
// Set to 0 to disable caching of hoisted layers
#define GR_CACHE_HOISTED_LAYERS 0
-// The layer cache listens for these messages to purge picture-related resources.
-struct GrPictureDeletedMessage {
- uint32_t pictureID;
-};
-
-// GrPictureInfo stores the atlas plots used by a single picture. A single
+// GrPictureInfo stores the atlas plots used by a single picture. A single
// plot may be used to store layers from multiple pictures.
struct GrPictureInfo {
public:
}
}
- // Setup to be notified when 'picture' is deleted
- void trackPicture(const SkPicture* picture);
-
// Cleanup after any SkPicture deletions
void processDeletedPictures();
SkTDynamicHash<GrCachedLayer, GrCachedLayer::Key> fLayerHash;
- SkMessageBus<GrPictureDeletedMessage>::Inbox fPictDeletionInbox;
-
- SkAutoTUnref<SkPicture::DeletionListener> fDeletionListener;
+ SkMessageBus<SkPicture::DeletionMessage>::Inbox fPictDeletionInbox;
// This implements a plot-centric locking mechanism (since the atlas
// backing texture is always locked). Each layer that is locked (i.e.,
if (pict->fBBH.get()) {
byteCount += pict->fBBH->bytesUsed();
}
- byteCount +=
- pict->fDeletionListeners.reserved() * sizeof(SkPicture::DeletionListener*) +
- pict->fDeletionListeners.count() * sizeof(SkPicture::DeletionListener);
-
MeasureRecords visitor;
for (unsigned curOp = 0; curOp < pict->fRecord->count(); curOp++) {
byteCount += pict->fRecord->visit<size_t>(curOp, visitor);
REPORTER_ASSERT(reporter, NULL == layer->paint());
REPORTER_ASSERT(reporter, !layer->isAtlased());
}
-
- cache->trackPicture(&picture);
}
static void lock_layer(skiatest::Reporter* reporter,
kHeight/2.0 == info1.fBounds.height());
REPORTER_ASSERT(reporter, info1.fLocalMat.isIdentity());
REPORTER_ASSERT(reporter, info1.fPreMat.isIdentity());
- REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.fLeft &&
+ REPORTER_ASSERT(reporter, kWidth/2.0 == info1.fBounds.fLeft &&
kHeight/2.0 == info1.fBounds.fTop);
REPORTER_ASSERT(reporter, NULL == info1.fPaint);
REPORTER_ASSERT(reporter, !info1.fIsNested &&
sizeof(SkPicture) + sizeof(SkRecord));
// Protect against any unintentional bloat.
- REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) <= 144);
+ REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) <= 128);
// Sanity check of nested SkPictures.
SkPictureRecorder r2;