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 "SkDevice.h" 12 #include "SkReadBuffer.h" 13 #include "SkWriteBuffer.h" 14 #include "SkRect.h" 15 #include "SkTDynamicHash.h" 16 #include "SkValidationUtils.h" 17 #if SK_SUPPORT_GPU 18 #include "GrContext.h" 19 #include "SkGrPixelRef.h" 20 #include "SkGr.h" 21 #endif 22 23 SkImageFilter::Cache* gExternalCache; 24 25 SkImageFilter::SkImageFilter(int inputCount, SkImageFilter** inputs, const CropRect* cropRect) 26 : fInputCount(inputCount), 27 fInputs(new SkImageFilter*[inputCount]), 28 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) { 29 for (int i = 0; i < inputCount; ++i) { 30 fInputs[i] = inputs[i]; 31 SkSafeRef(fInputs[i]); 32 } 33 } 34 35 SkImageFilter::SkImageFilter(SkImageFilter* input, const CropRect* cropRect) 36 : fInputCount(1), 37 fInputs(new SkImageFilter*[1]), 38 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) { 39 fInputs[0] = input; 40 SkSafeRef(fInputs[0]); 41 } 42 43 SkImageFilter::SkImageFilter(SkImageFilter* input1, SkImageFilter* input2, const CropRect* cropRect) 44 : fInputCount(2), fInputs(new SkImageFilter*[2]), 45 fCropRect(cropRect ? *cropRect : CropRect(SkRect(), 0x0)) { 46 fInputs[0] = input1; 47 fInputs[1] = input2; 48 SkSafeRef(fInputs[0]); 49 SkSafeRef(fInputs[1]); 50 } 51 52 SkImageFilter::~SkImageFilter() { 53 for (int i = 0; i < fInputCount; i++) { 54 SkSafeUnref(fInputs[i]); 55 } 56 delete[] fInputs; 57 } 58 59 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer) { 60 fInputCount = buffer.readInt(); 61 if (buffer.validate((fInputCount >= 0) && ((inputCount < 0) || (fInputCount == inputCount)))) { 62 fInputs = new SkImageFilter*[fInputCount]; 63 for (int i = 0; i < fInputCount; i++) { 64 if (buffer.readBool()) { 65 fInputs[i] = buffer.readImageFilter(); 66 } else { 67 fInputs[i] = NULL; 68 } 69 if (!buffer.isValid()) { 70 fInputCount = i; // Do not use fInputs past that point in the destructor 71 break; 72 } 73 } 74 SkRect rect; 75 buffer.readRect(&rect); 76 if (buffer.isValid() && buffer.validate(SkIsValidRect(rect))) { 77 uint32_t flags = buffer.readUInt(); 78 fCropRect = CropRect(rect, flags); 79 } 80 } else { 81 fInputCount = 0; 82 fInputs = NULL; 83 } 84 } 85 86 void SkImageFilter::flatten(SkWriteBuffer& buffer) const { 87 buffer.writeInt(fInputCount); 88 for (int i = 0; i < fInputCount; i++) { 89 SkImageFilter* input = getInput(i); 90 buffer.writeBool(input != NULL); 91 if (input != NULL) { 92 buffer.writeFlattenable(input); 93 } 94 } 95 buffer.writeRect(fCropRect.rect()); 96 buffer.writeUInt(fCropRect.flags()); 97 } 98 99 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src, 100 const Context& context, 101 SkBitmap* result, SkIPoint* offset) const { 102 Cache* cache = context.cache(); 103 SkASSERT(result); 104 SkASSERT(offset); 105 SkASSERT(cache); 106 if (cache->get(this, result, offset)) { 107 return true; 108 } 109 /* 110 * Give the proxy first shot at the filter. If it returns false, ask 111 * the filter to do it. 112 */ 113 if ((proxy && proxy->filterImage(this, src, context, result, offset)) || 114 this->onFilterImage(proxy, src, context, result, offset)) { 115 cache->set(this, *result, *offset); 116 return true; 117 } 118 return false; 119 } 120 121 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm, 122 SkIRect* dst) const { 123 SkASSERT(&src); 124 SkASSERT(dst); 125 if (SkImageFilter::GetExternalCache()) { 126 /* 127 * When the external cache is active, do not intersect the saveLayer 128 * bounds with the clip bounds. This is so that the cached result 129 * is always the full size of the primitive's bounds, 130 * regardless of the clip active on first draw. 131 */ 132 *dst = SkIRect::MakeLargest(); 133 return true; 134 } 135 return this->onFilterBounds(src, ctm, dst); 136 } 137 138 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const { 139 if (0 == fInputCount) { 140 *dst = src; 141 return; 142 } 143 if (this->getInput(0)) { 144 this->getInput(0)->computeFastBounds(src, dst); 145 } else { 146 *dst = src; 147 } 148 for (int i = 1; i < fInputCount; i++) { 149 SkImageFilter* input = this->getInput(i); 150 if (input) { 151 SkRect bounds; 152 input->computeFastBounds(src, &bounds); 153 dst->join(bounds); 154 } else { 155 dst->join(src); 156 } 157 } 158 } 159 160 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&, 161 SkBitmap*, SkIPoint*) const { 162 return false; 163 } 164 165 bool SkImageFilter::canFilterImageGPU() const { 166 return this->asNewEffect(NULL, NULL, SkMatrix::I(), SkIRect()); 167 } 168 169 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx, 170 SkBitmap* result, SkIPoint* offset) const { 171 #if SK_SUPPORT_GPU 172 SkBitmap input = src; 173 SkASSERT(fInputCount == 1); 174 SkIPoint srcOffset = SkIPoint::Make(0, 0); 175 if (this->getInput(0) && 176 !this->getInput(0)->getInputResultGPU(proxy, src, ctx, &input, &srcOffset)) { 177 return false; 178 } 179 GrTexture* srcTexture = input.getTexture(); 180 SkIRect bounds; 181 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) { 182 return false; 183 } 184 SkRect srcRect = SkRect::Make(bounds); 185 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); 186 GrContext* context = srcTexture->getContext(); 187 188 GrTextureDesc desc; 189 desc.fFlags = kRenderTarget_GrTextureFlagBit, 190 desc.fWidth = bounds.width(); 191 desc.fHeight = bounds.height(); 192 desc.fConfig = kRGBA_8888_GrPixelConfig; 193 194 GrAutoScratchTexture dst(context, desc); 195 GrContext::AutoMatrix am; 196 am.setIdentity(context); 197 GrContext::AutoRenderTarget art(context, dst.texture()->asRenderTarget()); 198 GrContext::AutoClip acs(context, dstRect); 199 GrEffectRef* effect; 200 offset->fX = bounds.left(); 201 offset->fY = bounds.top(); 202 bounds.offset(-srcOffset); 203 SkMatrix matrix(ctx.ctm()); 204 matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); 205 this->asNewEffect(&effect, srcTexture, matrix, bounds); 206 SkASSERT(effect); 207 SkAutoUnref effectRef(effect); 208 GrPaint paint; 209 paint.addColorEffect(effect); 210 context->drawRectToRect(paint, dstRect, srcRect); 211 212 SkAutoTUnref<GrTexture> resultTex(dst.detach()); 213 WrapTexture(resultTex, bounds.width(), bounds.height(), result); 214 return true; 215 #else 216 return false; 217 #endif 218 } 219 220 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src, 221 const SkIPoint& srcOffset, SkIRect* bounds) const { 222 SkIRect srcBounds; 223 src.getBounds(&srcBounds); 224 srcBounds.offset(srcOffset); 225 SkRect cropRect; 226 ctx.ctm().mapRect(&cropRect, fCropRect.rect()); 227 SkIRect cropRectI; 228 cropRect.roundOut(&cropRectI); 229 uint32_t flags = fCropRect.flags(); 230 if (flags & CropRect::kHasLeft_CropEdge) srcBounds.fLeft = cropRectI.fLeft; 231 if (flags & CropRect::kHasTop_CropEdge) srcBounds.fTop = cropRectI.fTop; 232 if (flags & CropRect::kHasRight_CropEdge) srcBounds.fRight = cropRectI.fRight; 233 if (flags & CropRect::kHasBottom_CropEdge) srcBounds.fBottom = cropRectI.fBottom; 234 if (!srcBounds.intersect(ctx.clipBounds())) { 235 return false; 236 } 237 *bounds = srcBounds; 238 return true; 239 } 240 241 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src, 242 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const { 243 SkIRect srcBounds; 244 src.getBounds(&srcBounds); 245 srcBounds.offset(*srcOffset); 246 SkRect cropRect; 247 ctx.ctm().mapRect(&cropRect, fCropRect.rect()); 248 SkIRect cropRectI; 249 cropRect.roundOut(&cropRectI); 250 uint32_t flags = fCropRect.flags(); 251 *bounds = srcBounds; 252 if (flags & CropRect::kHasLeft_CropEdge) bounds->fLeft = cropRectI.fLeft; 253 if (flags & CropRect::kHasTop_CropEdge) bounds->fTop = cropRectI.fTop; 254 if (flags & CropRect::kHasRight_CropEdge) bounds->fRight = cropRectI.fRight; 255 if (flags & CropRect::kHasBottom_CropEdge) bounds->fBottom = cropRectI.fBottom; 256 if (!bounds->intersect(ctx.clipBounds())) { 257 return false; 258 } 259 if (srcBounds.contains(*bounds)) { 260 *dst = src; 261 return true; 262 } else { 263 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height())); 264 if (!device) { 265 return false; 266 } 267 SkCanvas canvas(device); 268 canvas.clear(0x00000000); 269 canvas.drawBitmap(src, srcOffset->x() - bounds->x(), srcOffset->y() - bounds->y()); 270 *srcOffset = SkIPoint::Make(bounds->x(), bounds->y()); 271 *dst = device->accessBitmap(false); 272 return true; 273 } 274 } 275 276 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 277 SkIRect* dst) const { 278 if (fInputCount < 1) { 279 return false; 280 } 281 282 SkIRect bounds; 283 for (int i = 0; i < fInputCount; ++i) { 284 SkImageFilter* filter = this->getInput(i); 285 SkIRect rect = src; 286 if (filter && !filter->filterBounds(src, ctm, &rect)) { 287 return false; 288 } 289 if (0 == i) { 290 bounds = rect; 291 } else { 292 bounds.join(rect); 293 } 294 } 295 296 // don't modify dst until now, so we don't accidentally change it in the 297 // loop, but then return false on the next filter. 298 *dst = bounds; 299 return true; 300 } 301 302 bool SkImageFilter::asNewEffect(GrEffectRef**, GrTexture*, const SkMatrix&, const SkIRect&) const { 303 return false; 304 } 305 306 bool SkImageFilter::asColorFilter(SkColorFilter**) const { 307 return false; 308 } 309 310 void SkImageFilter::SetExternalCache(Cache* cache) { 311 SkRefCnt_SafeAssign(gExternalCache, cache); 312 } 313 314 SkImageFilter::Cache* SkImageFilter::GetExternalCache() { 315 return gExternalCache; 316 } 317 318 #if SK_SUPPORT_GPU 319 320 void SkImageFilter::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) { 321 SkImageInfo info = SkImageInfo::MakeN32Premul(width, height); 322 result->setInfo(info); 323 result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); 324 } 325 326 bool SkImageFilter::getInputResultGPU(SkImageFilter::Proxy* proxy, 327 const SkBitmap& src, const Context& ctx, 328 SkBitmap* result, SkIPoint* offset) const { 329 // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity 330 // matrix with no clip and that the matrix, clip, and render target set before this function was 331 // called are restored before we return to the caller. 332 GrContext* context = src.getTexture()->getContext(); 333 GrContext::AutoWideOpenIdentityDraw awoid(context, NULL); 334 if (this->canFilterImageGPU()) { 335 return this->filterImageGPU(proxy, src, ctx, result, offset); 336 } else { 337 if (this->filterImage(proxy, src, ctx, result, offset)) { 338 if (!result->getTexture()) { 339 const SkImageInfo info = result->info(); 340 if (kUnknown_SkColorType == info.colorType()) { 341 return false; 342 } 343 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL); 344 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); 345 GrUnlockAndUnrefCachedBitmapTexture(resultTex); 346 } 347 return true; 348 } else { 349 return false; 350 } 351 } 352 } 353 #endif 354 355 static uint32_t compute_hash(const uint32_t* data, int count) { 356 uint32_t hash = 0; 357 358 for (int i = 0; i < count; ++i) { 359 uint32_t k = data[i]; 360 k *= 0xcc9e2d51; 361 k = (k << 15) | (k >> 17); 362 k *= 0x1b873593; 363 364 hash ^= k; 365 hash = (hash << 13) | (hash >> 19); 366 hash *= 5; 367 hash += 0xe6546b64; 368 } 369 370 // hash ^= size; 371 hash ^= hash >> 16; 372 hash *= 0x85ebca6b; 373 hash ^= hash >> 13; 374 hash *= 0xc2b2ae35; 375 hash ^= hash >> 16; 376 377 return hash; 378 } 379 380 class CacheImpl : public SkImageFilter::Cache { 381 public: 382 explicit CacheImpl(int minChildren) : fMinChildren(minChildren) {} 383 virtual ~CacheImpl(); 384 bool get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) SK_OVERRIDE; 385 void set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) SK_OVERRIDE; 386 void remove(const SkImageFilter* key) SK_OVERRIDE; 387 private: 388 typedef const SkImageFilter* Key; 389 struct Value { 390 Value(Key key, const SkBitmap& bitmap, const SkIPoint& offset) 391 : fKey(key), fBitmap(bitmap), fOffset(offset) {} 392 Key fKey; 393 SkBitmap fBitmap; 394 SkIPoint fOffset; 395 static const Key& GetKey(const Value& v) { 396 return v.fKey; 397 } 398 static uint32_t Hash(Key key) { 399 return compute_hash(reinterpret_cast<const uint32_t*>(&key), sizeof(Key) / sizeof(uint32_t)); 400 } 401 }; 402 SkTDynamicHash<Value, Key> fData; 403 int fMinChildren; 404 }; 405 406 bool CacheImpl::get(const SkImageFilter* key, SkBitmap* result, SkIPoint* offset) { 407 Value* v = fData.find(key); 408 if (v) { 409 *result = v->fBitmap; 410 *offset = v->fOffset; 411 return true; 412 } 413 return false; 414 } 415 416 void CacheImpl::remove(const SkImageFilter* key) { 417 Value* v = fData.find(key); 418 if (v) { 419 fData.remove(key); 420 delete v; 421 } 422 } 423 424 void CacheImpl::set(const SkImageFilter* key, const SkBitmap& result, const SkIPoint& offset) { 425 if (key->getRefCnt() >= fMinChildren) { 426 fData.add(new Value(key, result, offset)); 427 } 428 } 429 430 SkImageFilter::Cache* SkImageFilter::Cache::Create(int minChildren) { 431 return new CacheImpl(minChildren); 432 } 433 434 CacheImpl::~CacheImpl() { 435 SkTDynamicHash<Value, Key>::Iter iter(&fData); 436 437 while (!iter.done()) { 438 Value* v = &*iter; 439 ++iter; 440 delete v; 441 } 442 } 443