OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 The Android Open Source Project | 2 * Copyright 2012 The Android Open Source Project |
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 "SkImageFilter.h" | 8 #include "SkImageFilter.h" |
9 | 9 |
10 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 static int32_t gImageFilterUniqueID; | 29 static int32_t gImageFilterUniqueID; |
30 | 30 |
31 // Never return 0. | 31 // Never return 0. |
32 int32_t id; | 32 int32_t id; |
33 do { | 33 do { |
34 id = sk_atomic_inc(&gImageFilterUniqueID) + 1; | 34 id = sk_atomic_inc(&gImageFilterUniqueID) + 1; |
35 } while (0 == id); | 35 } while (0 == id); |
36 return id; | 36 return id; |
37 } | 37 } |
38 | 38 |
39 struct SkImageFilter::UniqueIDCache::Key { | 39 struct SkImageFilter::Cache::Key { |
40 Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBoun
ds, uint32_t srcGenID) | 40 Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBoun
ds, uint32_t srcGenID) |
41 : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID
(srcGenID) { | 41 : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID
(srcGenID) { |
42 // Assert that Key is tightly-packed, since it is hashed. | 42 // Assert that Key is tightly-packed, since it is hashed. |
43 SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + s
izeof(SkIRect) + | 43 SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + s
izeof(SkIRect) + |
44 sizeof(uint32_t), image_filter_key_tigh
t_packing); | 44 sizeof(uint32_t), image_filter_key_tigh
t_packing); |
45 fMatrix.getType(); // force initialization of type, so hashes match | 45 fMatrix.getType(); // force initialization of type, so hashes match |
46 } | 46 } |
47 uint32_t fUniqueID; | 47 uint32_t fUniqueID; |
48 SkMatrix fMatrix; | 48 SkMatrix fMatrix; |
49 SkIRect fClipBounds; | 49 SkIRect fClipBounds; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 if (buffer.isVersionLT(SkReadBuffer::kImageFilterUniqueID_Version)) { | 103 if (buffer.isVersionLT(SkReadBuffer::kImageFilterUniqueID_Version)) { |
104 fUniqueID = next_image_filter_unique_id(); | 104 fUniqueID = next_image_filter_unique_id(); |
105 } else { | 105 } else { |
106 fUniqueID = buffer.readUInt(); | 106 fUniqueID = buffer.readUInt(); |
107 } | 107 } |
108 return buffer.isValid(); | 108 return buffer.isValid(); |
109 } | 109 } |
110 | 110 |
111 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 111 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
112 | 112 |
113 SkImageFilter::Cache* gExternalCache; | |
114 | |
115 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropR
ect* cropRect) | 113 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropR
ect* cropRect) |
116 : fInputCount(inputCount), | 114 : fInputCount(inputCount), |
117 fInputs(new SkImageFilter*[inputCount]), | 115 fInputs(new SkImageFilter*[inputCount]), |
118 fUsesSrcInput(false), | 116 fUsesSrcInput(false), |
119 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)), | 117 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)), |
120 fUniqueID(next_image_filter_unique_id()) { | 118 fUniqueID(next_image_filter_unique_id()) { |
121 for (int i = 0; i < inputCount; ++i) { | 119 for (int i = 0; i < inputCount; ++i) { |
122 if (NULL == inputs[i] || inputs[i]->usesSrcInput()) { | 120 if (NULL == inputs[i] || inputs[i]->usesSrcInput()) { |
123 fUsesSrcInput = true; | 121 fUsesSrcInput = true; |
124 } | 122 } |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 buffer.writeUInt(fCropRect.flags()); | 165 buffer.writeUInt(fCropRect.flags()); |
168 buffer.writeUInt(fUniqueID); | 166 buffer.writeUInt(fUniqueID); |
169 } | 167 } |
170 | 168 |
171 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src, | 169 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src, |
172 const Context& context, | 170 const Context& context, |
173 SkBitmap* result, SkIPoint* offset) const { | 171 SkBitmap* result, SkIPoint* offset) const { |
174 SkASSERT(result); | 172 SkASSERT(result); |
175 SkASSERT(offset); | 173 SkASSERT(offset); |
176 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0; | 174 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0; |
177 Cache* externalCache = GetExternalCache(); | 175 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID); |
178 UniqueIDCache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGe
nID); | 176 if (context.cache()) { |
179 if (NULL != externalCache) { | |
180 if (externalCache->get(this, result, offset)) { | |
181 return true; | |
182 } | |
183 } else if (context.cache()) { | |
184 if (context.cache()->get(key, result, offset)) { | 177 if (context.cache()->get(key, result, offset)) { |
185 return true; | 178 return true; |
186 } | 179 } |
187 } | 180 } |
188 /* | 181 /* |
189 * Give the proxy first shot at the filter. If it returns false, ask | 182 * Give the proxy first shot at the filter. If it returns false, ask |
190 * the filter to do it. | 183 * the filter to do it. |
191 */ | 184 */ |
192 if ((proxy && proxy->filterImage(this, src, context, result, offset)) || | 185 if ((proxy && proxy->filterImage(this, src, context, result, offset)) || |
193 this->onFilterImage(proxy, src, context, result, offset)) { | 186 this->onFilterImage(proxy, src, context, result, offset)) { |
194 if (externalCache) { | 187 if (context.cache()) { |
195 externalCache->set(this, *result, *offset); | |
196 } else if (context.cache()) { | |
197 context.cache()->set(key, *result, *offset); | 188 context.cache()->set(key, *result, *offset); |
198 } | 189 } |
199 return true; | 190 return true; |
200 } | 191 } |
201 return false; | 192 return false; |
202 } | 193 } |
203 | 194 |
204 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, | 195 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, |
205 SkIRect* dst) const { | 196 SkIRect* dst) const { |
206 SkASSERT(&src); | 197 SkASSERT(&src); |
207 SkASSERT(dst); | 198 SkASSERT(dst); |
208 if (SkImageFilter::GetExternalCache()) { | |
209 /* | |
210 * When the external cache is active, do not intersect the saveLayer | |
211 * bounds with the clip bounds. This is so that the cached result | |
212 * is always the full size of the primitive's bounds, | |
213 * regardless of the clip active on first draw. | |
214 */ | |
215 *dst = SkIRect::MakeLargest(); | |
216 return true; | |
217 } | |
218 return this->onFilterBounds(src, ctm, dst); | 199 return this->onFilterBounds(src, ctm, dst); |
219 } | 200 } |
220 | 201 |
221 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { | 202 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { |
222 if (0 == fInputCount) { | 203 if (0 == fInputCount) { |
223 *dst = src; | 204 *dst = src; |
224 return; | 205 return; |
225 } | 206 } |
226 if (this->getInput(0)) { | 207 if (this->getInput(0)) { |
227 this->getInput(0)->computeFastBounds(src, dst); | 208 this->getInput(0)->computeFastBounds(src, dst); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 } | 363 } |
383 | 364 |
384 bool SkImageFilter::asNewEffect(GrEffect**, GrTexture*, const SkMatrix&, const S
kIRect&) const { | 365 bool SkImageFilter::asNewEffect(GrEffect**, GrTexture*, const SkMatrix&, const S
kIRect&) const { |
385 return false; | 366 return false; |
386 } | 367 } |
387 | 368 |
388 bool SkImageFilter::asColorFilter(SkColorFilter**) const { | 369 bool SkImageFilter::asColorFilter(SkColorFilter**) const { |
389 return false; | 370 return false; |
390 } | 371 } |
391 | 372 |
392 void SkImageFilter::SetExternalCache(Cache* cache) { | |
393 SkRefCnt_SafeAssign(gExternalCache, cache); | |
394 } | |
395 | |
396 SkImageFilter::Cache* SkImageFilter::GetExternalCache() { | |
397 return gExternalCache; | |
398 } | |
399 | |
400 #if SK_SUPPORT_GPU | 373 #if SK_SUPPORT_GPU |
401 | 374 |
402 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBit
map* result) { | 375 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBit
map* result) { |
403 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); | 376 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); |
404 result->setInfo(info); | 377 result->setInfo(info); |
405 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); | 378 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); |
406 } | 379 } |
407 | 380 |
408 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy, | 381 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy, |
409 const SkBitmap& src, const Context& ctx, | 382 const SkBitmap& src, const Context& ctx, |
(...skipping 17 matching lines...) Expand all Loading... |
427 GrUnlockAndUnrefCachedBitmapTexture(resultTex); | 400 GrUnlockAndUnrefCachedBitmapTexture(resultTex); |
428 } | 401 } |
429 return true; | 402 return true; |
430 } else { | 403 } else { |
431 return false; | 404 return false; |
432 } | 405 } |
433 } | 406 } |
434 } | 407 } |
435 #endif | 408 #endif |
436 | 409 |
| 410 namespace { |
| 411 |
437 class CacheImpl : public SkImageFilter::Cache { | 412 class CacheImpl : public SkImageFilter::Cache { |
438 public: | 413 public: |
439 explicit CacheImpl(int minChildren) : fMinChildren(minChildren) { | 414 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { |
440 SkASSERT(fMinChildren <= 2); | |
441 } | 415 } |
442 | 416 virtual ~CacheImpl() { |
443 virtual ~CacheImpl(); | |
444 bool get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) SK_OV
ERRIDE; | |
445 void set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& o
ffset) SK_OVERRIDE; | |
446 void remove(const SkImageFilter* key) SK_OVERRIDE; | |
447 private: | |
448 typedef const SkImageFilter* Key; | |
449 struct Value { | |
450 Value(Key key, const SkBitmap& bitmap, const SkIPoint& offset) | |
451 : fKey(key), fBitmap(bitmap), fOffset(offset) {} | |
452 Key fKey; | |
453 SkBitmap fBitmap; | |
454 SkIPoint fOffset; | |
455 static const Key& GetKey(const Value& v) { | |
456 return v.fKey; | |
457 } | |
458 static uint32_t Hash(Key key) { | |
459 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key),
sizeof(Key)); | |
460 } | |
461 }; | |
462 SkTDynamicHash<Value, Key> fData; | |
463 int fMinChildren; | |
464 }; | |
465 | |
466 bool CacheImpl::get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset
) { | |
467 Value* v = fData.find(key); | |
468 if (v) { | |
469 *result = v->fBitmap; | |
470 *offset = v->fOffset; | |
471 return true; | |
472 } | |
473 return false; | |
474 } | |
475 | |
476 void CacheImpl::remove(const SkImageFilter* key) { | |
477 Value* v = fData.find(key); | |
478 if (v) { | |
479 fData.remove(key); | |
480 delete v; | |
481 } | |
482 } | |
483 | |
484 void CacheImpl::set(const SkImageFilter* key, const SkBitmap& result, const SkIP
oint& offset) { | |
485 if (fMinChildren < 2 || !key->unique()) { | |
486 // We take !key->unique() as a signal that there are probably at least 2
refs on the key, | |
487 // meaning this filter probably has at least two children and is worth c
aching when | |
488 // fMinChildren is 2. If fMinChildren is less than two, we'll just alwa
ys cache. | |
489 fData.add(new Value(key, result, offset)); | |
490 } | |
491 } | |
492 | |
493 SkImageFilter::Cache* SkImageFilter::Cache::Create(int minChildren) { | |
494 return new CacheImpl(minChildren); | |
495 } | |
496 | |
497 CacheImpl::~CacheImpl() { | |
498 SkTDynamicHash<Value, Key>::Iter iter(&fData); | |
499 | |
500 while (!iter.done()) { | |
501 Value* v = &*iter; | |
502 ++iter; | |
503 delete v; | |
504 } | |
505 } | |
506 | |
507 namespace { | |
508 | |
509 class UniqueIDCacheImpl : public SkImageFilter::UniqueIDCache { | |
510 public: | |
511 UniqueIDCacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { | |
512 } | |
513 virtual ~UniqueIDCacheImpl() { | |
514 SkTDynamicHash<Value, Key>::Iter iter(&fLookup); | 417 SkTDynamicHash<Value, Key>::Iter iter(&fLookup); |
515 | 418 |
516 while (!iter.done()) { | 419 while (!iter.done()) { |
517 Value* v = &*iter; | 420 Value* v = &*iter; |
518 ++iter; | 421 ++iter; |
519 delete v; | 422 delete v; |
520 } | 423 } |
521 } | 424 } |
522 struct Value { | 425 struct Value { |
523 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) | 426 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 delete v; | 475 delete v; |
573 } | 476 } |
574 private: | 477 private: |
575 SkTDynamicHash<Value, Key> fLookup; | 478 SkTDynamicHash<Value, Key> fLookup; |
576 mutable SkTInternalLList<Value> fLRU; | 479 mutable SkTInternalLList<Value> fLRU; |
577 size_t fMaxBytes; | 480 size_t fMaxBytes; |
578 size_t fCurrentBytes; | 481 size_t fCurrentBytes; |
579 mutable SkMutex fMutex; | 482 mutable SkMutex fMutex; |
580 }; | 483 }; |
581 | 484 |
582 SkImageFilter::UniqueIDCache* CreateCache() { | 485 SkImageFilter::Cache* CreateCache() { |
583 return SkImageFilter::UniqueIDCache::Create(kDefaultCacheSize); | 486 return SkImageFilter::Cache::Create(kDefaultCacheSize); |
584 } | 487 } |
585 | 488 |
586 } // namespace | 489 } // namespace |
587 | 490 |
588 SkImageFilter::UniqueIDCache* SkImageFilter::UniqueIDCache::Create(size_t maxByt
es) { | 491 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) { |
589 return SkNEW_ARGS(UniqueIDCacheImpl, (maxBytes)); | 492 return SkNEW_ARGS(CacheImpl, (maxBytes)); |
590 } | 493 } |
591 | 494 |
592 SkImageFilter::UniqueIDCache* SkImageFilter::UniqueIDCache::Get() { | 495 SkImageFilter::Cache* SkImageFilter::Cache::Get() { |
593 SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::UniqueIDCache, cache, CreateCache)
; | 496 SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache); |
594 return cache.get(); | 497 return cache.get(); |
595 } | 498 } |
OLD | NEW |