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

Unified Diff: src/core/SkPictureShader.cpp

Issue 671683004: Picture shader resource caching. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: use the cache allocator Created 6 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkPictureShader.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkPictureShader.cpp
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 8a16ea3b0074c3221d73a683b935fb5d6783aa5b..a4928d4fa99fea07729ee8b1779801eed6c1b5d4 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -10,14 +10,130 @@
#include "SkBitmap.h"
#include "SkBitmapProcShader.h"
#include "SkCanvas.h"
+#include "SkDiscardableMemory.h"
#include "SkMatrixUtils.h"
#include "SkPicture.h"
#include "SkReadBuffer.h"
+#include "SkResourceCache.h"
+#include "SkThread.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#endif
+struct BitmapShaderKey : public SkResourceCache::Key {
+public:
+ BitmapShaderKey(uint32_t pictureID,
+ const SkRect& tile,
+ SkShader::TileMode tmx,
+ SkShader::TileMode tmy,
+ const SkSize& scale,
+ const SkMatrix& localMatrix)
+ : fPictureID(pictureID)
+ , fTile(tile)
+ , fTmx(tmx)
+ , fTmy(tmy)
+ , fScale(scale)
+ , fLocalMatrix(localMatrix) {
+
+ static const size_t keySize = sizeof(fPictureID) +
+ sizeof(fTile) +
+ sizeof(fTmx) + sizeof(fTmy) +
+ sizeof(fScale) +
+ sizeof(fLocalMatrix);
+ // This better be packed.
+ SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fPictureID) == keySize);
+ this->init(keySize);
+ }
+
+private:
+ uint32_t fPictureID;
+ SkRect fTile;
+ SkShader::TileMode fTmx, fTmy;
+ SkSize fScale;
+ SkMatrix fLocalMatrix;
+
+ SkDEBUGCODE(uint32_t fEndOfStruct;)
+};
+
+struct BitmapShaderRec : public SkResourceCache::Rec {
+ BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader, size_t bitmapBytes)
+ : fKey(key)
+ , fShader(SkRef(tileShader))
+ , fBitmapBytes(bitmapBytes) {}
+
+ BitmapShaderKey fKey;
+ SkAutoTUnref<SkShader> fShader;
+ size_t fBitmapBytes;
+
+ virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
+ virtual size_t bytesUsed() const SK_OVERRIDE {
+ return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes;
+ }
+
+ static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
+ const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
+ SkAutoTUnref<SkShader>* result = reinterpret_cast<SkAutoTUnref<SkShader>*>(contextShader);
+
+ result->reset(SkRef(rec.fShader.get()));
+ return true;
+ }
+};
+
+// FIXME: there's considerable boilerplate/duplication here vs. the global resource cache.
+SK_DECLARE_STATIC_MUTEX(gBitmapShaderCacheMutex);
+static SkResourceCache* gBitmapShaderCache = NULL;
+
+#ifndef SK_DEFAULT_TILE_CACHE_LIMIT
+ #define SK_DEFAULT_TILE_CACHE_LIMIT (2 * 1024 * 1024)
+#endif
+
+static void cleanup_cache() {
+ // We'll clean this up in our own tests, but disable for clients.
+ // Chrome seems to have funky multi-process things going on in unit tests that
+ // makes this unsafe to delete when the main process atexit()s.
+ // SkLazyPtr does the same sort of thing.
+#if SK_DEVELOPER
+ SkDELETE(gBitmapShaderCache);
+#endif
+}
+
+/** Must hold gBitmapShaderCacheMutex when calling. */
+static SkResourceCache* cache() {
+ // gTileCacheMutex is always held when this is called, so we don't need to be fancy in here.
+ gBitmapShaderCacheMutex.assertHeld();
+ if (NULL == gBitmapShaderCache) {
+#ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
+ gBitmapShaderCache = SkNEW_ARGS(SkResourceCache, (SkDiscardableMemory::Create));
+#else
+ gBitmapShaderCache = SkNEW_ARGS(SkResourceCache, (SK_DEFAULT_TILE_CACHE_LIMIT));
+#endif
+ atexit(cleanup_cache);
+ }
+ return gBitmapShaderCache;
+}
+
+static bool cache_find(const BitmapShaderKey& key, SkAutoTUnref<SkShader>* result) {
+ SkAutoMutexAcquire am(gBitmapShaderCacheMutex);
+ return cache()->find(key, BitmapShaderRec::Visitor, result);
+}
+
+static void cache_add(BitmapShaderRec* rec) {
+ SkAutoMutexAcquire am(gBitmapShaderCacheMutex);
+ cache()->add(rec);
+}
+
+static bool cache_try_alloc_pixels(SkBitmap* bitmap) {
+ SkAutoMutexAcquire am(gBitmapShaderCacheMutex);
+ SkBitmap::Allocator* allocator = cache()->allocator();
+
+ if (NULL != allocator) {
+ return allocator->allocPixelRef(bitmap, NULL);
+ } else {
+ return bitmap->tryAllocPixels();
+ }
+}
+
SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMode tmy,
const SkMatrix* localMatrix, const SkRect* tile)
: INHERITED(localMatrix)
@@ -103,11 +219,18 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri
SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.width(),
SkIntToScalar(tileSize.height()) / fTile.height());
- SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);
+ SkAutoTUnref<SkShader> tileShader;
+ BitmapShaderKey key(fPicture->uniqueID(),
+ fTile,
+ fTmx,
+ fTmy,
+ tileScale,
+ this->getLocalMatrix());
- if (!fCachedBitmapShader || tileScale != fCachedTileScale) {
+ if (!cache_find(key, &tileShader)) {
SkBitmap bm;
- if (!bm.tryAllocN32Pixels(tileSize.width(), tileSize.height())) {
+ bm.setInfo(SkImageInfo::MakeN32Premul(tileSize));
+ if (!cache_try_alloc_pixels(&bm)) {
return NULL;
}
bm.eraseColor(SK_ColorTRANSPARENT);
@@ -117,18 +240,14 @@ SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatri
canvas.translate(fTile.x(), fTile.y());
canvas.drawPicture(fPicture);
- fCachedTileScale = tileScale;
-
SkMatrix shaderMatrix = this->getLocalMatrix();
shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
- fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix));
+ tileShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix));
+
+ cache_add(SkNEW_ARGS(BitmapShaderRec, (key, tileShader.get(), bm.getSize())));
}
- // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
- // Otherwise, the pointer may have been overwritten on a different thread before the object's
- // ref count was incremented.
- fCachedBitmapShader.get()->ref();
- return fCachedBitmapShader;
+ return tileShader.detach();
}
size_t SkPictureShader::contextSize() const {
« no previous file with comments | « src/core/SkPictureShader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698