SkImageFilter.cpp revision e30597375c19dfb5197fd065a3d1768401eb00fa
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
26enum { kDefaultCacheSize = 128 * 1024 * 1024 };
27
28static 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
39struct 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
59SkImageFilter::Common::~Common() {
60    for (int i = 0; i < fInputs.count(); ++i) {
61        SkSafeUnref(fInputs[i]);
62    }
63}
64
65void 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
71void 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
77bool 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
113SkImageFilter::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
128SkImageFilter::~SkImageFilter() {
129    for (int i = 0; i < fInputCount; i++) {
130        SkSafeUnref(fInputs[i]);
131    }
132    delete[] fInputs;
133}
134
135SkImageFilter::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
155void 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
169bool 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
195bool 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
202void 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
224bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
225                                  SkBitmap*, SkIPoint*) const {
226    return false;
227}
228
229bool SkImageFilter::canFilterImageGPU() const {
230    return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
231}
232
233bool 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    SkAutoTUnref<GrTexture> dst(
259        context->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
260    if (!dst) {
261        return false;
262    }
263    GrContext::AutoMatrix am;
264    am.setIdentity(context);
265    GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
266    GrContext::AutoClip acs(context, dstRect);
267    GrFragmentProcessor* fp;
268    offset->fX = bounds.left();
269    offset->fY = bounds.top();
270    bounds.offset(-srcOffset);
271    SkMatrix matrix(ctx.ctm());
272    matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
273    if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
274        SkASSERT(fp);
275        GrPaint paint;
276        paint.addColorProcessor(fp)->unref();
277        context->drawRectToRect(paint, dstRect, srcRect);
278
279        WrapTexture(dst, bounds.width(), bounds.height(), result);
280        return true;
281    }
282#endif
283    return false;
284}
285
286bool 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
307bool 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
342bool 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
368bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
369                                        const SkIRect&) const {
370    return false;
371}
372
373bool SkImageFilter::asColorFilter(SkColorFilter**) const {
374    return false;
375}
376
377#if SK_SUPPORT_GPU
378
379void 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
385bool 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                SkAutoTUnref<GrTexture> resultTex(GrRefCachedBitmapTexture(context, *result, NULL));
403                result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, resultTex)))->unref();
404            }
405            return true;
406        } else {
407            return false;
408        }
409    }
410}
411#endif
412
413namespace {
414
415class CacheImpl : public SkImageFilter::Cache {
416public:
417    CacheImpl(size_t maxBytes) : fMaxBytes(maxBytes), fCurrentBytes(0) {
418    }
419    virtual ~CacheImpl() {
420        SkTDynamicHash<Value, Key>::Iter iter(&fLookup);
421
422        while (!iter.done()) {
423            Value* v = &*iter;
424            ++iter;
425            delete v;
426        }
427    }
428    struct Value {
429        Value(const Key& key, const SkBitmap& bitmap, const SkIPoint& offset)
430            : fKey(key), fBitmap(bitmap), fOffset(offset) {}
431        Key fKey;
432        SkBitmap fBitmap;
433        SkIPoint fOffset;
434        static const Key& GetKey(const Value& v) {
435            return v.fKey;
436        }
437        static uint32_t Hash(const Key& key) {
438            return SkChecksum::Murmur3(reinterpret_cast<const uint32_t*>(&key), sizeof(Key));
439        }
440        SK_DECLARE_INTERNAL_LLIST_INTERFACE(Value);
441    };
442    virtual bool get(const Key& key, SkBitmap* result, SkIPoint* offset) const {
443        SkAutoMutexAcquire mutex(fMutex);
444        if (Value* v = fLookup.find(key)) {
445            *result = v->fBitmap;
446            *offset = v->fOffset;
447            if (v != fLRU.head()) {
448                fLRU.remove(v);
449                fLRU.addToHead(v);
450            }
451            return true;
452        }
453        return false;
454    }
455    virtual void set(const Key& key, const SkBitmap& result, const SkIPoint& offset) {
456        SkAutoMutexAcquire mutex(fMutex);
457        if (Value* v = fLookup.find(key)) {
458            removeInternal(v);
459        }
460        Value* v = new Value(key, result, offset);
461        fLookup.add(v);
462        fLRU.addToHead(v);
463        fCurrentBytes += result.getSize();
464        while (fCurrentBytes > fMaxBytes) {
465            Value* tail = fLRU.tail();
466            SkASSERT(tail);
467            if (tail == v) {
468                break;
469            }
470            removeInternal(tail);
471        }
472    }
473private:
474    void removeInternal(Value* v) {
475        fCurrentBytes -= v->fBitmap.getSize();
476        fLRU.remove(v);
477        fLookup.remove(v->fKey);
478        delete v;
479    }
480private:
481    SkTDynamicHash<Value, Key>         fLookup;
482    mutable SkTInternalLList<Value>    fLRU;
483    size_t                             fMaxBytes;
484    size_t                             fCurrentBytes;
485    mutable SkMutex                    fMutex;
486};
487
488SkImageFilter::Cache* CreateCache() {
489    return SkImageFilter::Cache::Create(kDefaultCacheSize);
490}
491
492} // namespace
493
494SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
495    return SkNEW_ARGS(CacheImpl, (maxBytes));
496}
497
498SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
499
500SkImageFilter::Cache* SkImageFilter::Cache::Get() {
501    return cache.get();
502}
503