Home | History | Annotate | Download | only in core
      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 
     33 static 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 
     44 struct 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 
     64 SkImageFilter::Common::~Common() {
     65     for (int i = 0; i < fInputs.count(); ++i) {
     66         SkSafeUnref(fInputs[i]);
     67     }
     68 }
     69 
     70 void 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 
     76 void 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 
     82 bool 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 
    117 SkImageFilter::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 
    132 SkImageFilter::~SkImageFilter() {
    133     for (int i = 0; i < fInputCount; i++) {
    134         SkSafeUnref(fInputs[i]);
    135     }
    136     delete[] fInputs;
    137 }
    138 
    139 SkImageFilter::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 
    159 void 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 
    172 bool 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 
    198 bool SkImageFilter::filterBounds(const SkIRect& src, const SkMatrix& ctm,
    199                                  SkIRect* dst) const {
    200     SkASSERT(dst);
    201     return this->onFilterBounds(src, ctm, dst);
    202 }
    203 
    204 void 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 
    226 bool SkImageFilter::onFilterImage(Proxy*, const SkBitmap&, const Context&,
    227                                   SkBitmap*, SkIPoint*) const {
    228     return false;
    229 }
    230 
    231 bool SkImageFilter::canFilterImageGPU() const {
    232     return this->asFragmentProcessor(NULL, NULL, SkMatrix::I(), SkIRect());
    233 }
    234 
    235 bool 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 
    289 bool 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 
    309 bool 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 
    343 bool 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 
    370 bool SkImageFilter::asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
    371                                         const SkIRect&) const {
    372     return false;
    373 }
    374 
    375 SkImageFilter* 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 
    383 void 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 
    389 bool 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 
    417 namespace {
    418 
    419 class CacheImpl : public SkImageFilter::Cache {
    420 public:
    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     }
    477 private:
    478     void removeInternal(Value* v) {
    479         fCurrentBytes -= v->fBitmap.getSize();
    480         fLRU.remove(v);
    481         fLookup.remove(v->fKey);
    482         delete v;
    483     }
    484 private:
    485     SkTDynamicHash<Value, Key>         fLookup;
    486     mutable SkTInternalLList<Value>    fLRU;
    487     size_t                             fMaxBytes;
    488     size_t                             fCurrentBytes;
    489     mutable SkMutex                    fMutex;
    490 };
    491 
    492 SkImageFilter::Cache* CreateCache() {
    493     return SkImageFilter::Cache::Create(kDefaultCacheSize);
    494 }
    495 
    496 } // namespace
    497 
    498 SkImageFilter::Cache* SkImageFilter::Cache::Create(size_t maxBytes) {
    499     return SkNEW_ARGS(CacheImpl, (maxBytes));
    500 }
    501 
    502 SK_DECLARE_STATIC_LAZY_PTR(SkImageFilter::Cache, cache, CreateCache);
    503 
    504 SkImageFilter::Cache* SkImageFilter::Cache::Get() {
    505     return cache.get();
    506 }
    507