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