| 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 |