OLD | NEW |
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 "SkPictureShader.h" | 8 #include "SkPictureShader.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
11 #include "SkBitmapProcShader.h" | 11 #include "SkBitmapProcShader.h" |
12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
| 13 #include "SkDiscardableMemory.h" |
13 #include "SkMatrixUtils.h" | 14 #include "SkMatrixUtils.h" |
14 #include "SkPicture.h" | 15 #include "SkPicture.h" |
15 #include "SkReadBuffer.h" | 16 #include "SkReadBuffer.h" |
| 17 #include "SkResourceCache.h" |
| 18 #include "SkThread.h" |
16 | 19 |
17 #if SK_SUPPORT_GPU | 20 #if SK_SUPPORT_GPU |
18 #include "GrContext.h" | 21 #include "GrContext.h" |
19 #endif | 22 #endif |
20 | 23 |
| 24 struct BitmapShaderKey : public SkResourceCache::Key { |
| 25 public: |
| 26 BitmapShaderKey(uint32_t pictureID, |
| 27 const SkRect& tile, |
| 28 SkShader::TileMode tmx, |
| 29 SkShader::TileMode tmy, |
| 30 const SkSize& scale, |
| 31 const SkMatrix& localMatrix) |
| 32 : fPictureID(pictureID) |
| 33 , fTile(tile) |
| 34 , fTmx(tmx) |
| 35 , fTmy(tmy) |
| 36 , fScale(scale) |
| 37 , fLocalMatrix(localMatrix) { |
| 38 |
| 39 static const size_t keySize = sizeof(fPictureID) + |
| 40 sizeof(fTile) + |
| 41 sizeof(fTmx) + sizeof(fTmy) + |
| 42 sizeof(fScale) + |
| 43 sizeof(fLocalMatrix); |
| 44 // This better be packed. |
| 45 SkASSERT(sizeof(uint32_t) * (&fEndOfStruct - &fPictureID) == keySize); |
| 46 this->init(keySize); |
| 47 } |
| 48 |
| 49 private: |
| 50 uint32_t fPictureID; |
| 51 SkRect fTile; |
| 52 SkShader::TileMode fTmx, fTmy; |
| 53 SkSize fScale; |
| 54 SkMatrix fLocalMatrix; |
| 55 |
| 56 SkDEBUGCODE(uint32_t fEndOfStruct;) |
| 57 }; |
| 58 |
| 59 struct BitmapShaderRec : public SkResourceCache::Rec { |
| 60 BitmapShaderRec(const BitmapShaderKey& key, SkShader* tileShader, size_t bit
mapBytes) |
| 61 : fKey(key) |
| 62 , fShader(SkRef(tileShader)) |
| 63 , fBitmapBytes(bitmapBytes) {} |
| 64 |
| 65 BitmapShaderKey fKey; |
| 66 SkAutoTUnref<SkShader> fShader; |
| 67 size_t fBitmapBytes; |
| 68 |
| 69 virtual const Key& getKey() const SK_OVERRIDE { return fKey; } |
| 70 virtual size_t bytesUsed() const SK_OVERRIDE { |
| 71 return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes; |
| 72 } |
| 73 |
| 74 static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader
) { |
| 75 const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec
); |
| 76 SkAutoTUnref<SkShader>* result = reinterpret_cast<SkAutoTUnref<SkShader>
*>(contextShader); |
| 77 |
| 78 result->reset(SkRef(rec.fShader.get())); |
| 79 return true; |
| 80 } |
| 81 }; |
| 82 |
| 83 // FIXME: there's considerable boilerplate/duplication here vs. the global resou
rce cache. |
| 84 SK_DECLARE_STATIC_MUTEX(gBitmapShaderCacheMutex); |
| 85 static SkResourceCache* gBitmapShaderCache = NULL; |
| 86 |
| 87 #ifndef SK_DEFAULT_TILE_CACHE_LIMIT |
| 88 #define SK_DEFAULT_TILE_CACHE_LIMIT (2 * 1024 * 1024) |
| 89 #endif |
| 90 |
| 91 static void cleanup_cache() { |
| 92 // We'll clean this up in our own tests, but disable for clients. |
| 93 // Chrome seems to have funky multi-process things going on in unit tests th
at |
| 94 // makes this unsafe to delete when the main process atexit()s. |
| 95 // SkLazyPtr does the same sort of thing. |
| 96 #if SK_DEVELOPER |
| 97 SkDELETE(gBitmapShaderCache); |
| 98 #endif |
| 99 } |
| 100 |
| 101 /** Must hold gBitmapShaderCacheMutex when calling. */ |
| 102 static SkResourceCache* cache() { |
| 103 // gTileCacheMutex is always held when this is called, so we don't need to b
e fancy in here. |
| 104 gBitmapShaderCacheMutex.assertHeld(); |
| 105 if (NULL == gBitmapShaderCache) { |
| 106 #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE |
| 107 gBitmapShaderCache = SkNEW_ARGS(SkResourceCache, (SkDiscardableMemory::C
reate)); |
| 108 #else |
| 109 gBitmapShaderCache = SkNEW_ARGS(SkResourceCache, (SK_DEFAULT_TILE_CACHE_
LIMIT)); |
| 110 #endif |
| 111 atexit(cleanup_cache); |
| 112 } |
| 113 return gBitmapShaderCache; |
| 114 } |
| 115 |
| 116 static bool cache_find(const BitmapShaderKey& key, SkAutoTUnref<SkShader>* resul
t) { |
| 117 SkAutoMutexAcquire am(gBitmapShaderCacheMutex); |
| 118 return cache()->find(key, BitmapShaderRec::Visitor, result); |
| 119 } |
| 120 |
| 121 static void cache_add(BitmapShaderRec* rec) { |
| 122 SkAutoMutexAcquire am(gBitmapShaderCacheMutex); |
| 123 cache()->add(rec); |
| 124 } |
| 125 |
| 126 static bool cache_try_alloc_pixels(SkBitmap* bitmap) { |
| 127 SkAutoMutexAcquire am(gBitmapShaderCacheMutex); |
| 128 SkBitmap::Allocator* allocator = cache()->allocator(); |
| 129 |
| 130 if (NULL != allocator) { |
| 131 return allocator->allocPixelRef(bitmap, NULL); |
| 132 } else { |
| 133 return bitmap->tryAllocPixels(); |
| 134 } |
| 135 } |
| 136 |
21 SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMod
e tmy, | 137 SkPictureShader::SkPictureShader(const SkPicture* picture, TileMode tmx, TileMod
e tmy, |
22 const SkMatrix* localMatrix, const SkRect* tile
) | 138 const SkMatrix* localMatrix, const SkRect* tile
) |
23 : INHERITED(localMatrix) | 139 : INHERITED(localMatrix) |
24 , fPicture(SkRef(picture)) | 140 , fPicture(SkRef(picture)) |
25 , fTile(tile ? *tile : picture->cullRect()) | 141 , fTile(tile ? *tile : picture->cullRect()) |
26 , fTmx(tmx) | 142 , fTmx(tmx) |
27 , fTmy(tmy) { | 143 , fTmy(tmy) { |
28 } | 144 } |
29 | 145 |
30 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING | 146 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 | 212 |
97 SkISize tileSize = scaledSize.toRound(); | 213 SkISize tileSize = scaledSize.toRound(); |
98 if (tileSize.isEmpty()) { | 214 if (tileSize.isEmpty()) { |
99 return NULL; | 215 return NULL; |
100 } | 216 } |
101 | 217 |
102 // The actual scale, compensating for rounding & clamping. | 218 // The actual scale, compensating for rounding & clamping. |
103 SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.widt
h(), | 219 SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fTile.widt
h(), |
104 SkIntToScalar(tileSize.height()) / fTile.hei
ght()); | 220 SkIntToScalar(tileSize.height()) / fTile.hei
ght()); |
105 | 221 |
106 SkAutoMutexAcquire ama(fCachedBitmapShaderMutex); | 222 SkAutoTUnref<SkShader> tileShader; |
| 223 BitmapShaderKey key(fPicture->uniqueID(), |
| 224 fTile, |
| 225 fTmx, |
| 226 fTmy, |
| 227 tileScale, |
| 228 this->getLocalMatrix()); |
107 | 229 |
108 if (!fCachedBitmapShader || tileScale != fCachedTileScale) { | 230 if (!cache_find(key, &tileShader)) { |
109 SkBitmap bm; | 231 SkBitmap bm; |
110 if (!bm.tryAllocN32Pixels(tileSize.width(), tileSize.height())) { | 232 bm.setInfo(SkImageInfo::MakeN32Premul(tileSize)); |
| 233 if (!cache_try_alloc_pixels(&bm)) { |
111 return NULL; | 234 return NULL; |
112 } | 235 } |
113 bm.eraseColor(SK_ColorTRANSPARENT); | 236 bm.eraseColor(SK_ColorTRANSPARENT); |
114 | 237 |
115 SkCanvas canvas(bm); | 238 SkCanvas canvas(bm); |
116 canvas.scale(tileScale.width(), tileScale.height()); | 239 canvas.scale(tileScale.width(), tileScale.height()); |
117 canvas.translate(fTile.x(), fTile.y()); | 240 canvas.translate(fTile.x(), fTile.y()); |
118 canvas.drawPicture(fPicture); | 241 canvas.drawPicture(fPicture); |
119 | 242 |
120 fCachedTileScale = tileScale; | |
121 | |
122 SkMatrix shaderMatrix = this->getLocalMatrix(); | 243 SkMatrix shaderMatrix = this->getLocalMatrix(); |
123 shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); | 244 shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); |
124 fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatr
ix)); | 245 tileShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix)); |
| 246 |
| 247 cache_add(SkNEW_ARGS(BitmapShaderRec, (key, tileShader.get(), bm.getSize
()))); |
125 } | 248 } |
126 | 249 |
127 // Increment the ref counter inside the mutex to ensure the returned pointer
is still valid. | 250 return tileShader.detach(); |
128 // Otherwise, the pointer may have been overwritten on a different thread be
fore the object's | |
129 // ref count was incremented. | |
130 fCachedBitmapShader.get()->ref(); | |
131 return fCachedBitmapShader; | |
132 } | 251 } |
133 | 252 |
134 size_t SkPictureShader::contextSize() const { | 253 size_t SkPictureShader::contextSize() const { |
135 return sizeof(PictureShaderContext); | 254 return sizeof(PictureShaderContext); |
136 } | 255 } |
137 | 256 |
138 SkShader::Context* SkPictureShader::onCreateContext(const ContextRec& rec, void*
storage) const { | 257 SkShader::Context* SkPictureShader::onCreateContext(const ContextRec& rec, void*
storage) const { |
139 SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.
fLocalMatrix)); | 258 SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.
fLocalMatrix)); |
140 if (NULL == bitmapShader.get()) { | 259 if (NULL == bitmapShader.get()) { |
141 return NULL; | 260 return NULL; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 } | 340 } |
222 return bitmapShader->asFragmentProcessor(context, paint, NULL, paintColor, f
p); | 341 return bitmapShader->asFragmentProcessor(context, paint, NULL, paintColor, f
p); |
223 } | 342 } |
224 #else | 343 #else |
225 bool SkPictureShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMa
trix*, GrColor*, | 344 bool SkPictureShader::asFragmentProcessor(GrContext*, const SkPaint&, const SkMa
trix*, GrColor*, |
226 GrFragmentProcessor**) const { | 345 GrFragmentProcessor**) const { |
227 SkDEBUGFAIL("Should not call in GPU-less build"); | 346 SkDEBUGFAIL("Should not call in GPU-less build"); |
228 return false; | 347 return false; |
229 } | 348 } |
230 #endif | 349 #endif |
OLD | NEW |