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