2 * Copyright 2012 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkImageFilter.h"
11 #include "SkChecksum.h"
13 #include "SkLazyPtr.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
17 #include "SkTDynamicHash.h"
18 #include "SkTInternalLList.h"
19 #include "SkValidationUtils.h"
21 #include "GrContext.h"
22 #include "SkGrPixelRef.h"
26 enum { kDefaultCacheSize = 128 * 1024 * 1024 };
28 static int32_t next_image_filter_unique_id() {
29 static int32_t gImageFilterUniqueID;
34 id = sk_atomic_inc(&gImageFilterUniqueID) + 1;
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
51 bool operator==(const Key& other) const {
52 return fUniqueID == other.fUniqueID
53 && fMatrix == other.fMatrix
54 && fClipBounds == other.fClipBounds
55 && fSrcGenID == other.fSrcGenID;
59 SkImageFilter::Common::~Common() {
60 for (int i = 0; i < fInputs.count(); ++i) {
61 SkSafeUnref(fInputs[i]);
65 void SkImageFilter::Common::allocInputs(int count) {
66 const size_t size = count * sizeof(SkImageFilter*);
68 sk_bzero(fInputs.get(), size);
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);
77 bool SkImageFilter::Common::unflatten(SkReadBuffer& buffer, int expectedCount) {
78 const int count = buffer.readInt();
79 if (!buffer.validate(count >= 0)) {
82 if (!buffer.validate(expectedCount < 0 || count == expectedCount)) {
86 this->allocInputs(count);
87 for (int i = 0; i < count; i++) {
88 if (buffer.readBool()) {
89 fInputs[i] = buffer.readImageFilter();
91 if (!buffer.isValid()) {
96 buffer.readRect(&rect);
97 if (!buffer.isValid() || !buffer.validate(SkIsValidRect(rect))) {
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();
106 fUniqueID = buffer.readUInt();
108 return buffer.isValid();
111 ///////////////////////////////////////////////////////////////////////////////////////////////////
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;
123 fInputs[i] = inputs[i];
124 SkSafeRef(fInputs[i]);
128 SkImageFilter::~SkImageFilter() {
129 for (int i = 0; i < fInputCount; i++) {
130 SkSafeUnref(fInputs[i]);
135 SkImageFilter::SkImageFilter(int inputCount, SkReadBuffer& buffer)
136 : fUsesSrcInput(false) {
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;
148 fUniqueID = buffer.isCrossProcess() ? next_image_filter_unique_id() : common.uniqueID();
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);
161 buffer.writeFlattenable(input);
164 buffer.writeRect(fCropRect.rect());
165 buffer.writeUInt(fCropRect.flags());
166 buffer.writeUInt(fUniqueID);
169 bool SkImageFilter::filterImage(Proxy* proxy, const SkBitmap& src,
170 const Context& context,
171 SkBitmap* result, SkIPoint* offset) const {
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)) {
182 * Give the proxy first shot at the filter. If it returns false, ask
183 * the filter to do it.
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);
195 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
196 SkIRect* dst) const {
199 return this->onFilterBounds(src, ctm, dst);
202 void SkImageFilter::computeFastBounds(const SkRect& src, SkRect* dst) const {
203 if (0 == fInputCount) {
207 if (this->getInput(0)) {
208 this->getInput(0)->computeFastBounds(src, dst);
212 for (int i = 1; i < fInputCount; i++) {
213 SkImageFilter* input = this->getInput(i);
216 input->computeFastBounds(src, &bounds);
224 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
225 SkBitmap*, SkIPoint*) const {
229 bool SkImageFilter::canFilterImageGPU() const {
230 return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
233 bool SkImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, const Context& ctx,
234 SkBitmap* result, SkIPoint* offset) const {
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)) {
243 GrTexture* srcTexture = input.getTexture();
245 if (!this->applyCropRect(ctx, proxy, input, &srcOffset, &bounds, &input)) {
248 SkRect srcRect = SkRect::Make(bounds);
249 SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
250 GrContext* context = srcTexture->getContext();
253 desc.fFlags = kRenderTarget_GrTextureFlagBit,
254 desc.fWidth = bounds.width();
255 desc.fHeight = bounds.height();
256 desc.fConfig = kRGBA_8888_GrPixelConfig;
258 GrAutoScratchTexture dst(context, desc);
259 if (NULL == dst.texture()) {
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);
275 paint.addColorProcessor(fp)->unref();
276 context->drawRectToRect(paint, dstRect, srcRect);
278 SkAutoTUnref<GrTexture> resultTex(dst.detach());
279 WrapTexture(resultTex, bounds.width(), bounds.height(), result);
286 bool SkImageFilter::applyCropRect(const Context& ctx, const SkBitmap& src,
287 const SkIPoint& srcOffset, SkIRect* bounds) const {
289 src.getBounds(&srcBounds);
290 srcBounds.offset(srcOffset);
292 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
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())) {
307 bool SkImageFilter::applyCropRect(const Context& ctx, Proxy* proxy, const SkBitmap& src,
308 SkIPoint* srcOffset, SkIRect* bounds, SkBitmap* dst) const {
310 src.getBounds(&srcBounds);
311 srcBounds.offset(*srcOffset);
313 ctx.ctm().mapRect(&cropRect, fCropRect.rect());
315 cropRect.roundOut(&cropRectI);
316 uint32_t flags = fCropRect.flags();
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())) {
325 if (srcBounds.contains(*bounds)) {
329 SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(bounds->width(), bounds->height()));
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);
342 bool SkImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm,
343 SkIRect* dst) const {
344 if (fInputCount < 1) {
349 for (int i = 0; i < fInputCount; ++i) {
350 SkImageFilter* filter = this->getInput(i);
352 if (filter && !filter->filterBounds(src, ctm, &rect)) {
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.
368 bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
369 const SkIRect&) const {
373 bool SkImageFilter::asColorFilter(SkColorFilter**) const {
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();
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);
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()) {
402 GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL);
403 result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref();
404 GrUnlockAndUnrefCachedBitmapTexture(resultTex);
416 class CacheImpl : public SkImageFilter::Cache {
418 CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
420 virtual ~CacheImpl() {
421 SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
423 while (!iter.done()) {
430 Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
431 : fKey(key), fBitmap(bitmap), fOffset(offset) {}
435 static const Key& GetKey(const Value& v) {
438 static uint32_t Hash(const Key& key) {
439 return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
441 SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
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()) {
456 virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) {
457 SkAutoMutexAcquire mutex(fMutex);
458 if (Value* v = fLookup.find(key)) {
461 Value* v = new Value(key, result, offset);
464 fCurrentBytes += result.getSize();
465 while (fCurrentBytes > fMaxBytes) {
466 Value* tail = fLRU.tail();
471 removeInternal(tail);
475 void removeInternal(Value* v) {
476 fCurrentBytes -= v->fBitmap.getSize();
478 fLookup.remove(v->fKey);
482 SkTDynamicHash<Value, Key> fLookup;
483 mutable SkTInternalLList<Value> fLRU;
485 size_t fCurrentBytes;
486 mutable SkMutex fMutex;
489 SkImageFilter::Cache* CreateCache() {
490 return SkImageFilter::Cache::Create(kDefaultCacheSize);
495 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
496 return SkNEW_ARGS(CacheImpl, (maxBytes));
499 SkImageFilter::Cache* SkImageFilter::Cache::Get() {
500 SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);