1 /* 2 * Copyright 2012 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkImageFilter.h" 9 10 #include "SkBitmap.h" 11 #include "SkChecksum.h" 12 #include "SkDevice.h" 13 #include "SkLazyPtr.h" 14 #include "SkReadBuffer.h" 15 #include "SkWriteBuffer.h" 16 #include "SkRect.h" 17 #include "SkTDynamicHash.h" 18 #include "SkTInternalLList.h" 19 #include "SkValidationUtils.h" 20 #if SK_SUPPORT_GPU 21 #include "GrContext.h" 22 #include "SkGrPixelRef.h" 23 #include "SkGr.h" 24 #endif 25 26 enum { kDefaultCacheSize = 128 * 1024 * 1024 }; 27 28 static int32_t next_image_filter_unique_id() { 29 static int32_t gImageFilterUniqueID; 30 31 // Never return 0. 32 int32_t id; 33 do { 34 id = sk_atomic_inc(&gImageFilterUniqueID) + 1; 35 } while (0 == id); 36 return id; 37 } 38 39 struct SkImageFilter::Cache::Key { 40 Key(const uint32_t uniqueID, const SkMatrix& matrix, const SkIRect& clipBounds, uint32_t srcGenID) 41 : fUniqueID(uniqueID), fMatrix(matrix), fClipBounds(clipBounds), fSrcGenID(srcGenID) { 42 // Assert that Key is tightly-packed, since it is hashed. 43 SK_COMPILE_ASSERT(sizeof(Key) == sizeof(uint32_t) + sizeof(SkMatrix) + sizeof(SkIRect) + 44 sizeof(uint32_t), image_filter_key_tight_packing); 45 fMatrix.getType(); // force initialization of type, so hashes match 46 } 47 uint32_t fUniqueID; 48 SkMatrix fMatrix; 49 SkIRect fClipBounds; 50 uint32_t fSrcGenID; 51 bool operator==(const Key& other) const { 52 return fUniqueID == other.fUniqueID 53 && fMatrix == other.fMatrix 54 && fClipBounds == other.fClipBounds 55 && fSrcGenID == other.fSrcGenID; 56 } 57 }; 58 59 SkImageFilter::Common::~Common() { 60 for (int i = 0; i < fInputs.count(); ++i) { 61 SkSafeUnref(fInputs[i]); 62 } 63 } 64 65 void SkImageFilter::Common::allocInputs(int count) { 66 const size_t size = count * sizeof(SkImageFilter*); 67 fInputs.reset(count); 68 sk_bzero(fInputs.get(), size); 69 } 70 71 void SkImageFilter::Common::detachInputs(SkImageFilter** inputs) { 72 const size_t size = fInputs.count() * sizeof(SkImageFilter*); 73 memcpy(inputs, fInputs.get(), size); 74 sk_bzero(fInputs.get(), size); 75 } 76 77 bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) { 78 const int count = buffer.readInt(); 79 if (!buffer.validate(count >= 0)) { 80 return false; 81 } 82 if (!buffer.validate(expectedCount < 0 || count == expectedCount)) { 83 return false; 84 } 85 86 this->allocInputs(count); 87 for (int i = 0; i < count; i++) { 88 if (buffer.readBool()) { 89 fInputs[i] = buffer.readImageFilter(); 90 } 91 if (!buffer.isValid()) { 92 return false; 93 } 94 } 95 SkRect rect; 96 buffer.readRect(&rect); 97 if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) { 98 return false; 99 } 100 101 uint32_t flags = buffer.readUInt(); 102 fCropRect = CropRect(rect, flags); 103 if (buffer.isVersionLT(SkReadBuffer::kImageFilterUniqueID_Version)) { 104 fUniqueID = next_image_filter_unique_id(); 105 } else { 106 fUniqueID = buffer.readUInt(); 107 } 108 return buffer.isValid(); 109 } 110 111 /////////////////////////////////////////////////////////////////////////////////////////////////// 112 113 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect, uint32_t uniqueID) 114 : fInputCount(inputCount), 115 fInputs(new SkImageFilter*[inputCount]), 116 fUsesSrcInput(false), 117 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)), 118 fUniqueID(uniqueID ? uniqueID : next_image_filter_unique_id()) { 119 for (int i = 0; i < inputCount; ++i) { 120 if (NULL == inputs[i] || inputs[i]->usesSrcInput()) { 121 fUsesSrcInput = true; 122 } 123 fInputs[i] = inputs[i]; 124 SkSafeRef(fInputs[i]); 125 } 126 } 127 128 SkImageFilter::~SkImageFilter() { 129 for (int i = 0; i < fInputCount; i++) { 130 SkSafeUnref(fInputs[i]); 131 } 132 delete[] fInputs; 133 } 134 135 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) 136 : fUsesSrcInput(false) { 137 Common common; 138 if (common.unflatten(buffer, inputCount)) { 139 fCropRect = common.cropRect(); 140 fInputCount = common.inputCount(); 141 fInputs = SkNEW_ARRAY(SkImageFilter*, fInputCount); 142 common.detachInputs(fInputs); 143 for (int i = 0; i < fInputCount; ++i) { 144 if (NULL == fInputs[i] || fInputs[i]->usesSrcInput()) { 145 fUsesSrcInput = true; 146 } 147 } 148 fUniqueID = buffer.isCrossProcess() ? next_image_filter_unique_id() : common.uniqueID(); 149 } else { 150 fInputCount = 0; 151 fInputs = NULL; 152 } 153 } 154 155 void SkImageFilter::flatten(SkWriteBuffer& buffer) const { 156 buffer.writeInt(fInputCount); 157 for (int i = 0; i < fInputCount; i++) { 158 SkImageFilter* input = getInput(i); 159 buffer.writeBool(input != NULL); 160 if (input != NULL) { 161 buffer.writeFlattenable(input); 162 } 163 } 164 buffer.writeRect(fCropRect.rect()); 165 buffer.writeUInt(fCropRect.flags()); 166 buffer.writeUInt(fUniqueID); 167 } 168 169 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src, 170 const Context& context, 171 SkBitmap* result, SkIPoint* offset) const { 172 SkASSERT(result); 173 SkASSERT(offset); 174 uint32_t srcGenID = fUsesSrcInput ? src.getGenerationID() : 0; 175 Cache::Key key(fUniqueID, context.ctm(), context.clipBounds(), srcGenID); 176 if (context.cache()) { 177 if (context.cache()->get(key, result, offset)) { 178 return true; 179 } 180 } 181 /* 182 * Give the proxy first shot at the filter. If it returns false, ask 183 * the filter to do it. 184 */ 185 if ((proxy && proxy->filterImage(this, src, context, result, offset)) || 186 this->onFilterImage(proxy, src, context, result, offset)) { 187 if (context.cache()) { 188 context.cache()->set(key, *result, *offset); 189 } 190 return true; 191 } 192 return false; 193 } 194 195 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, 196 SkIRect* dst) const { 197 SkASSERT(&src); 198 SkASSERT(dst); 199 return this->onFilterBounds(src, ctm, dst); 200 } 201 202 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 203 if (0 == fInputCount) { 204 *dst = src; 205 return; 206 } 207 if (this->getInput(0)) { 208 this->getInput(0)->computeFastBounds(src, dst); 209 } else { 210 *dst = src; 211 } 212 for (int i = 1; i < fInputCount; i++) { 213 SkImageFilter* input = this->getInput(i); 214 if (input) { 215 SkRect bounds; 216 input->computeFastBounds(src, &bounds); 217 dst->join(bounds); 218 } else { 219 dst->join(src); 220 } 221 } 222 } 223 224 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&, 225 SkBitmap*, SkIPoint*) const { 226 return false; 227 } 228 229 bool SkImageFilter::canFilterImageGPU() const { 230 return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect()); 231 } 232 233 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, 234 SkBitmap* result, SkIPoint* offset) const { 235 #if SK_SUPPORT_GPU 236 SkBitmap input = src; 237 SkASSERT(fInputCount == 1); 238 SkIPoint srcOffset = SkIPoint::Make(0, 0); 239 if (this->getInput(0) && 240 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) { 241 return false; 242 } 243 GrTexture* srcTexture = input.getTexture(); 244 SkIRect bounds; 245 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { 246 return false; 247 } 248 SkRect srcRect = SkRect::Make(bounds); 249 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); 250 GrContext* context = srcTexture->getContext(); 251 252 GrTextureDesc desc; 253 desc.fFlags = kRenderTarget_GrTextureFlagBit, 254 desc.fWidth = bounds.width(); 255 desc.fHeight = bounds.height(); 256 desc.fConfig = kRGBA_8888_GrPixelConfig; 257 258 GrAutoScratchTexture dst(context, desc); 259 if (NULL == dst.texture()) { 260 return false; 261 } 262 GrContext::AutoMatrix am; 263 am.setIdentity(context); 264 GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget()); 265 GrContext::AutoClip acs(context, dstRect); 266 GrFragmentProcessor* fp; 267 offset->fX = bounds.left(); 268 offset->fY = bounds.top(); 269 bounds.offset(-srcOffset); 270 SkMatrix matrix(ctx.ctm()); 271 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 272 this->asFragmentProcessor(&fp, srcTexture, matrix, bounds); 273 SkASSERT(fp); 274 GrPaint paint; 275 paint.addColorProcessor(fp)->unref(); 276 context->drawRectToRect(paint, dstRect, srcRect); 277 278 SkAutoTUnref<GrTexture> resultTex(dst.detach()); 279 WrapTexture(resultTex, bounds.width(), bounds.height(), result); 280 return true; 281 #else 282 return false; 283 #endif 284 } 285 286 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, 287 const SkIPoint& srcOffset, SkIRect* bounds) const { 288 SkIRect srcBounds; 289 src.getBounds(&srcBounds); 290 srcBounds.offset(srcOffset); 291 SkRect cropRect; 292 ctx.ctm().mapRect(&cropRect, fCropRect.rect()); 293 SkIRect cropRectI; 294 cropRect.roundOut(&cropRectI); 295 uint32_t flags = fCropRect.flags(); 296 if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft; 297 if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop; 298 if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight; 299 if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom; 300 if (!srcBounds.intersect(ctx.clipBounds())) { 301 return false; 302 } 303 *bounds = srcBounds; 304 return true; 305 } 306 307 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src, 308 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const { 309 SkIRect srcBounds; 310 src.getBounds(&srcBounds); 311 srcBounds.offset(*srcOffset); 312 SkRect cropRect; 313 ctx.ctm().mapRect(&cropRect, fCropRect.rect()); 314 SkIRect cropRectI; 315 cropRect.roundOut(&cropRectI); 316 uint32_t flags = fCropRect.flags(); 317 *bounds = srcBounds; 318 if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft; 319 if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop; 320 if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight; 321 if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom; 322 if (!bounds->intersect(ctx.clipBounds())) { 323 return false; 324 } 325 if (srcBounds.contains(*bounds)) { 326 *dst = src; 327 return true; 328 } else { 329 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height())); 330 if (!device) { 331 return false; 332 } 333 SkCanvas canvas(device); 334 canvas.clear(0x00000000); 335 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y()); 336 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); 337 *dst = device->accessBitmap(false); 338 return true; 339 } 340 } 341 342 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 343 SkIRect* dst) const { 344 if (fInputCount < 1) { 345 return false; 346 } 347 348 SkIRect bounds; 349 for (int i = 0; i < fInputCount; ++i) { 350 SkImageFilter* filter = this->getInput(i); 351 SkIRect rect = src; 352 if (filter && !filter->filterBounds(src, ctm, &rect)) { 353 return false; 354 } 355 if (0 == i) { 356 bounds = rect; 357 } else { 358 bounds.join(rect); 359 } 360 } 361 362 // don't modify dst until now, so we don't accidentally change it in the 363 // loop, but then return false on the next filter. 364 *dst = bounds; 365 return true; 366 } 367 368 bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&, 369 const SkIRect&) const { 370 return false; 371 } 372 373 bool SkImageFilter::asColorFilter(SkColorFilter**) const { 374 return false; 375 } 376 377 #if SK_SUPPORT_GPU 378 379 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) { 380 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 381 result->setInfo(info); 382 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); 383 } 384 385 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy, 386 const SkBitmap& src, const Context& ctx, 387 SkBitmap* result, SkIPoint* offset) const { 388 // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity 389 // matrix with no clip and that the matrix, clip, and render target set before this function was 390 // called are restored before we return to the caller. 391 GrContext* context = src.getTexture()->getContext(); 392 GrContext::AutoWideOpenIdentityDraw awoid(context, NULL); 393 if (this->canFilterImageGPU()) { 394 return this->filterImageGPU(proxy, src, ctx, result, offset); 395 } else { 396 if (this->filterImage(proxy, src, ctx, result, offset)) { 397 if (!result->getTexture()) { 398 const SkImageInfo info = result->info(); 399 if (kUnknown_SkColorType == info.colorType()) { 400 return false; 401 } 402 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL); 403 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); 404 GrUnlockAndUnrefCachedBitmapTexture(resultTex); 405 } 406 return true; 407 } else { 408 return false; 409 } 410 } 411 } 412 #endif 413 414 namespace { 415 416 class CacheImpl : public SkImageFilter::Cache { 417 public: 418 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) { 419 } 420 virtual ~CacheImpl() { 421 SkTDynamicHash<Value, Key>::Iter iter(&fLookup); 422 423 while (!iter.done()) { 424 Value* v = &*iter; 425 ++iter; 426 delete v; 427 } 428 } 429 struct Value { 430 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset) 431 : fKey(key), fBitmap(bitmap), fOffset(offset) {} 432 Key fKey; 433 SkBitmap fBitmap; 434 SkIPoint fOffset; 435 static const Key& GetKey(const Value& v) { 436 return v.fKey; 437 } 438 static uint32_t Hash(const Key& key) { 439 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key)); 440 } 441 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value); 442 }; 443 virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const { 444 SkAutoMutexAcquire mutex(fMutex); 445 if (Value* v = fLookup.find(key)) { 446 *result = v->fBitmap; 447 *offset = v->fOffset; 448 if (v != fLRU.head()) { 449 fLRU.remove(v); 450 fLRU.addToHead(v); 451 } 452 return true; 453 } 454 return false; 455 } 456 virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) { 457 SkAutoMutexAcquire mutex(fMutex); 458 if (Value* v = fLookup.find(key)) { 459 removeInternal(v); 460 } 461 Value* v = new Value(key, result, offset); 462 fLookup.add(v); 463 fLRU.addToHead(v); 464 fCurrentBytes += result.getSize(); 465 while (fCurrentBytes > fMaxBytes) { 466 Value* tail = fLRU.tail(); 467 SkASSERT(tail); 468 if (tail == v) { 469 break; 470 } 471 removeInternal(tail); 472 } 473 } 474 private: 475 void removeInternal(Value* v) { 476 fCurrentBytes -= v->fBitmap.getSize(); 477 fLRU.remove(v); 478 fLookup.remove(v->fKey); 479 delete v; 480 } 481 private: 482 SkTDynamicHash<Value, Key> fLookup; 483 mutable SkTInternalLList<Value> fLRU; 484 size_t fMaxBytes; 485 size_t fCurrentBytes; 486 mutable SkMutex fMutex; 487 }; 488 489 SkImageFilter::Cache* CreateCache() { 490 return SkImageFilter::Cache::Create(kDefaultCacheSize); 491 } 492 493 } // namespace 494 495 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) { 496 return SkNEW_ARGS(CacheImpl, (maxBytes)); 497 } 498 499 SkImageFilter::Cache* SkImageFilter::Cache::Get() { 500 SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache); 501 return cache.get(); 502 } 503