Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2013 Google Inc.
      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 "SkAlphaThresholdFilter.h"
      9 #include "SkBitmap.h"
     10 #include "SkDevice.h"
     11 #include "SkReadBuffer.h"
     12 #include "SkWriteBuffer.h"
     13 #include "SkRegion.h"
     14 #if SK_SUPPORT_GPU
     15 #include "GrDrawContext.h"
     16 #endif
     17 
     18 class SK_API SkAlphaThresholdFilterImpl : public SkImageFilter {
     19 public:
     20     SkAlphaThresholdFilterImpl(const SkRegion& region, SkScalar innerThreshold,
     21                                SkScalar outerThreshold, SkImageFilter* input);
     22 
     23     SK_TO_STRING_OVERRIDE()
     24     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkAlphaThresholdFilterImpl)
     25     friend void SkAlphaThresholdFilter::InitializeFlattenables();
     26 
     27 protected:
     28     void flatten(SkWriteBuffer&) const override;
     29 
     30     bool onFilterImageDeprecated(Proxy*, const SkBitmap& src, const Context&,
     31                                  SkBitmap* result, SkIPoint* offset) const override;
     32 #if SK_SUPPORT_GPU
     33     bool asFragmentProcessor(GrFragmentProcessor**, GrTexture*, const SkMatrix&,
     34                              const SkIRect& bounds) const override;
     35 #endif
     36 
     37 private:
     38     SkRegion fRegion;
     39     SkScalar fInnerThreshold;
     40     SkScalar fOuterThreshold;
     41     typedef SkImageFilter INHERITED;
     42 };
     43 
     44 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkAlphaThresholdFilter)
     45     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkAlphaThresholdFilterImpl)
     46 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
     47 
     48 static SkScalar pin_0_1(SkScalar x) {
     49     return SkMinScalar(SkMaxScalar(x, 0), 1);
     50 }
     51 
     52 SkImageFilter* SkAlphaThresholdFilter::Create(const SkRegion& region,
     53                                               SkScalar innerThreshold,
     54                                               SkScalar outerThreshold,
     55                                               SkImageFilter* input) {
     56     innerThreshold = pin_0_1(innerThreshold);
     57     outerThreshold = pin_0_1(outerThreshold);
     58     if (!SkScalarIsFinite(innerThreshold) || !SkScalarIsFinite(outerThreshold)) {
     59         return nullptr;
     60     }
     61     return new SkAlphaThresholdFilterImpl(region, innerThreshold, outerThreshold, input);
     62 }
     63 
     64 #if SK_SUPPORT_GPU
     65 #include "GrContext.h"
     66 #include "GrCoordTransform.h"
     67 #include "GrFragmentProcessor.h"
     68 #include "GrInvariantOutput.h"
     69 #include "GrTextureAccess.h"
     70 #include "effects/GrPorterDuffXferProcessor.h"
     71 
     72 #include "SkGr.h"
     73 
     74 #include "glsl/GrGLSLFragmentProcessor.h"
     75 #include "glsl/GrGLSLFragmentShaderBuilder.h"
     76 #include "glsl/GrGLSLProgramDataManager.h"
     77 #include "glsl/GrGLSLUniformHandler.h"
     78 
     79 namespace {
     80 
     81 SkMatrix make_div_and_translate_matrix(GrTexture* texture, int x, int y) {
     82     SkMatrix matrix = GrCoordTransform::MakeDivByTextureWHMatrix(texture);
     83     matrix.preTranslate(SkIntToScalar(x), SkIntToScalar(y));
     84     return matrix;
     85 }
     86 
     87 };
     88 
     89 class AlphaThresholdEffect : public GrFragmentProcessor {
     90 
     91 public:
     92     static GrFragmentProcessor* Create(GrTexture* texture,
     93                                        GrTexture* maskTexture,
     94                                        float innerThreshold,
     95                                        float outerThreshold,
     96                                        const SkIRect& bounds) {
     97         return new AlphaThresholdEffect(texture, maskTexture, innerThreshold, outerThreshold,
     98                                         bounds);
     99     }
    100 
    101     virtual ~AlphaThresholdEffect() {};
    102 
    103     const char* name() const override { return "Alpha Threshold"; }
    104 
    105     float innerThreshold() const { return fInnerThreshold; }
    106     float outerThreshold() const { return fOuterThreshold; }
    107 
    108 private:
    109     AlphaThresholdEffect(GrTexture* texture,
    110                          GrTexture* maskTexture,
    111                          float innerThreshold,
    112                          float outerThreshold,
    113                          const SkIRect& bounds)
    114         : fInnerThreshold(innerThreshold)
    115         , fOuterThreshold(outerThreshold)
    116         , fImageCoordTransform(kLocal_GrCoordSet,
    117                                GrCoordTransform::MakeDivByTextureWHMatrix(texture), texture,
    118                                GrTextureParams::kNone_FilterMode)
    119         , fImageTextureAccess(texture)
    120         , fMaskCoordTransform(kLocal_GrCoordSet,
    121                               make_div_and_translate_matrix(maskTexture, -bounds.x(), -bounds.y()),
    122                               maskTexture,
    123                               GrTextureParams::kNone_FilterMode)
    124         , fMaskTextureAccess(maskTexture) {
    125         this->initClassID<AlphaThresholdEffect>();
    126         this->addCoordTransform(&fImageCoordTransform);
    127         this->addTextureAccess(&fImageTextureAccess);
    128         this->addCoordTransform(&fMaskCoordTransform);
    129         this->addTextureAccess(&fMaskTextureAccess);
    130     }
    131 
    132     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    133 
    134     void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
    135 
    136     bool onIsEqual(const GrFragmentProcessor&) const override;
    137 
    138     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
    139 
    140     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
    141 
    142     float fInnerThreshold;
    143     float fOuterThreshold;
    144     GrCoordTransform fImageCoordTransform;
    145     GrTextureAccess  fImageTextureAccess;
    146     GrCoordTransform fMaskCoordTransform;
    147     GrTextureAccess  fMaskTextureAccess;
    148 
    149     typedef GrFragmentProcessor INHERITED;
    150 };
    151 
    152 class GrGLAlphaThresholdEffect : public GrGLSLFragmentProcessor {
    153 public:
    154     void emitCode(EmitArgs&) override;
    155 
    156 protected:
    157     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
    158 
    159 private:
    160     GrGLSLProgramDataManager::UniformHandle fInnerThresholdVar;
    161     GrGLSLProgramDataManager::UniformHandle fOuterThresholdVar;
    162 
    163     typedef GrGLSLFragmentProcessor INHERITED;
    164 };
    165 
    166 void GrGLAlphaThresholdEffect::emitCode(EmitArgs& args) {
    167     GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
    168     fInnerThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
    169                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
    170                                                     "inner_threshold");
    171     fOuterThresholdVar = uniformHandler->addUniform(kFragment_GrShaderFlag,
    172                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
    173                                                     "outer_threshold");
    174 
    175     GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
    176     SkString coords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
    177     SkString maskCoords2D = fragBuilder->ensureFSCoords2D(args.fCoords, 1);
    178 
    179     fragBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
    180     fragBuilder->codeAppendf("\t\tvec2 mask_coord = %s;\n", maskCoords2D.c_str());
    181     fragBuilder->codeAppend("\t\tvec4 input_color = ");
    182     fragBuilder->appendTextureLookup(args.fSamplers[0], "coord");
    183     fragBuilder->codeAppend(";\n");
    184     fragBuilder->codeAppend("\t\tvec4 mask_color = ");
    185     fragBuilder->appendTextureLookup(args.fSamplers[1], "mask_coord");
    186     fragBuilder->codeAppend(";\n");
    187 
    188     fragBuilder->codeAppendf("\t\tfloat inner_thresh = %s;\n",
    189                              uniformHandler->getUniformCStr(fInnerThresholdVar));
    190     fragBuilder->codeAppendf("\t\tfloat outer_thresh = %s;\n",
    191                              uniformHandler->getUniformCStr(fOuterThresholdVar));
    192     fragBuilder->codeAppend("\t\tfloat mask = mask_color.a;\n");
    193 
    194     fragBuilder->codeAppend("vec4 color = input_color;\n");
    195     fragBuilder->codeAppend("\t\tif (mask < 0.5) {\n"
    196                             "\t\t\tif (color.a > outer_thresh) {\n"
    197                             "\t\t\t\tfloat scale = outer_thresh / color.a;\n"
    198                             "\t\t\t\tcolor.rgb *= scale;\n"
    199                             "\t\t\t\tcolor.a = outer_thresh;\n"
    200                             "\t\t\t}\n"
    201                             "\t\t} else if (color.a < inner_thresh) {\n"
    202                             "\t\t\tfloat scale = inner_thresh / max(0.001, color.a);\n"
    203                             "\t\t\tcolor.rgb *= scale;\n"
    204                             "\t\t\tcolor.a = inner_thresh;\n"
    205                             "\t\t}\n");
    206 
    207     fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor,
    208                              (GrGLSLExpr4(args.fInputColor) * GrGLSLExpr4("color")).c_str());
    209 }
    210 
    211 void GrGLAlphaThresholdEffect::onSetData(const GrGLSLProgramDataManager& pdman,
    212                                        const GrProcessor& proc) {
    213     const AlphaThresholdEffect& alpha_threshold = proc.cast<AlphaThresholdEffect>();
    214     pdman.set1f(fInnerThresholdVar, alpha_threshold.innerThreshold());
    215     pdman.set1f(fOuterThresholdVar, alpha_threshold.outerThreshold());
    216 }
    217 
    218 /////////////////////////////////////////////////////////////////////
    219 
    220 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(AlphaThresholdEffect);
    221 
    222 const GrFragmentProcessor* AlphaThresholdEffect::TestCreate(GrProcessorTestData* d) {
    223     GrTexture* bmpTex = d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx];
    224     GrTexture* maskTex = d->fTextures[GrProcessorUnitTest::kAlphaTextureIdx];
    225     float innerThresh = d->fRandom->nextUScalar1();
    226     float outerThresh = d->fRandom->nextUScalar1();
    227     const int kMaxWidth = 1000;
    228     const int kMaxHeight = 1000;
    229     uint32_t width = d->fRandom->nextULessThan(kMaxWidth);
    230     uint32_t height = d->fRandom->nextULessThan(kMaxHeight);
    231     uint32_t x = d->fRandom->nextULessThan(kMaxWidth - width);
    232     uint32_t y = d->fRandom->nextULessThan(kMaxHeight - height);
    233     SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height);
    234     return AlphaThresholdEffect::Create(bmpTex, maskTex, innerThresh, outerThresh, bounds);
    235 }
    236 
    237 ///////////////////////////////////////////////////////////////////////////////
    238 
    239 void AlphaThresholdEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
    240                                                  GrProcessorKeyBuilder* b) const {
    241     GrGLAlphaThresholdEffect::GenKey(*this, caps, b);
    242 }
    243 
    244 GrGLSLFragmentProcessor* AlphaThresholdEffect::onCreateGLSLInstance() const {
    245     return new GrGLAlphaThresholdEffect;
    246 }
    247 
    248 bool AlphaThresholdEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
    249     const AlphaThresholdEffect& s = sBase.cast<AlphaThresholdEffect>();
    250     return (this->fInnerThreshold == s.fInnerThreshold &&
    251             this->fOuterThreshold == s.fOuterThreshold);
    252 }
    253 
    254 void AlphaThresholdEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
    255     if (GrPixelConfigIsAlphaOnly(this->texture(0)->config())) {
    256         inout->mulByUnknownSingleComponent();
    257     } else if (GrPixelConfigIsOpaque(this->texture(0)->config()) && fOuterThreshold >= 1.f) {
    258         inout->mulByUnknownOpaqueFourComponents();
    259     } else {
    260         inout->mulByUnknownFourComponents();
    261     }
    262 }
    263 
    264 #endif
    265 
    266 SkFlattenable* SkAlphaThresholdFilterImpl::CreateProc(SkReadBuffer& buffer) {
    267     SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 1);
    268     SkScalar inner = buffer.readScalar();
    269     SkScalar outer = buffer.readScalar();
    270     SkRegion rgn;
    271     buffer.readRegion(&rgn);
    272     return SkAlphaThresholdFilter::Create(rgn, inner, outer, common.getInput(0));
    273 }
    274 
    275 SkAlphaThresholdFilterImpl::SkAlphaThresholdFilterImpl(const SkRegion& region,
    276                                                        SkScalar innerThreshold,
    277                                                        SkScalar outerThreshold,
    278                                                        SkImageFilter* input)
    279     : INHERITED(1, &input)
    280     , fRegion(region)
    281     , fInnerThreshold(innerThreshold)
    282     , fOuterThreshold(outerThreshold) {
    283 }
    284 
    285 #if SK_SUPPORT_GPU
    286 bool SkAlphaThresholdFilterImpl::asFragmentProcessor(GrFragmentProcessor** fp,
    287                                                      GrTexture* texture,
    288                                                      const SkMatrix& inMatrix,
    289                                                      const SkIRect& bounds) const {
    290     if (fp) {
    291         GrContext* context = texture->getContext();
    292         GrSurfaceDesc maskDesc;
    293         if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
    294             maskDesc.fConfig = kAlpha_8_GrPixelConfig;
    295         } else {
    296             maskDesc.fConfig = kRGBA_8888_GrPixelConfig;
    297         }
    298         maskDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    299         // Add one pixel of border to ensure that clamp mode will be all zeros
    300         // the outside.
    301         maskDesc.fWidth = bounds.width();
    302         maskDesc.fHeight = bounds.height();
    303         SkAutoTUnref<GrTexture> maskTexture(
    304             context->textureProvider()->createApproxTexture(maskDesc));
    305         if (!maskTexture) {
    306             return false;
    307         }
    308 
    309         SkAutoTUnref<GrDrawContext> drawContext(
    310                                             context->drawContext(maskTexture->asRenderTarget()));
    311         if (drawContext) {
    312             GrPaint grPaint;
    313             grPaint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
    314             SkRegion::Iterator iter(fRegion);
    315             drawContext->clear(nullptr, 0x0, true);
    316 
    317             GrClip clip(SkRect::Make(SkIRect::MakeWH(bounds.width(), bounds.height())));
    318             while (!iter.done()) {
    319                 SkRect rect = SkRect::Make(iter.rect());
    320                 drawContext->drawRect(clip, grPaint, inMatrix, rect);
    321                 iter.next();
    322             }
    323         }
    324 
    325         *fp = AlphaThresholdEffect::Create(texture,
    326                                            maskTexture,
    327                                            fInnerThreshold,
    328                                            fOuterThreshold,
    329                                            bounds);
    330     }
    331     return true;
    332 }
    333 #endif
    334 
    335 void SkAlphaThresholdFilterImpl::flatten(SkWriteBuffer& buffer) const {
    336     this->INHERITED::flatten(buffer);
    337     buffer.writeScalar(fInnerThreshold);
    338     buffer.writeScalar(fOuterThreshold);
    339     buffer.writeRegion(fRegion);
    340 }
    341 
    342 bool SkAlphaThresholdFilterImpl::onFilterImageDeprecated(Proxy* proxy, const SkBitmap& src,
    343                                                          const Context& ctx, SkBitmap* dst,
    344                                                          SkIPoint* offset) const {
    345 
    346     if (src.colorType() != kN32_SkColorType) {
    347         return false;
    348     }
    349 
    350     SkMatrix localInverse;
    351     if (!ctx.ctm().invert(&localInverse)) {
    352         return false;
    353     }
    354 
    355     SkAutoLockPixels alp(src);
    356     SkASSERT(src.getPixels());
    357     if (!src.getPixels() || src.width() <= 0 || src.height() <= 0) {
    358         return false;
    359     }
    360 
    361     SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(src.width(), src.height()));
    362     if (!device) {
    363         return false;
    364     }
    365     *dst = device->accessBitmap(false);
    366     SkAutoLockPixels alp_dst(*dst);
    367 
    368     U8CPU innerThreshold = (U8CPU)(fInnerThreshold * 0xFF);
    369     U8CPU outerThreshold = (U8CPU)(fOuterThreshold * 0xFF);
    370     SkColor* sptr = src.getAddr32(0, 0);
    371     SkColor* dptr = dst->getAddr32(0, 0);
    372     int width = src.width(), height = src.height();
    373     for (int y = 0; y < height; ++y) {
    374         for (int x = 0; x < width; ++x) {
    375             const SkColor& source = sptr[y * width + x];
    376             SkColor output_color(source);
    377             SkPoint position;
    378             localInverse.mapXY((SkScalar)x, (SkScalar)y, &position);
    379             if (fRegion.contains((int32_t)position.x(), (int32_t)position.y())) {
    380                 if (SkColorGetA(source) < innerThreshold) {
    381                     U8CPU alpha = SkColorGetA(source);
    382                     if (alpha == 0)
    383                         alpha = 1;
    384                     float scale = (float)innerThreshold / alpha;
    385                     output_color = SkColorSetARGB(innerThreshold,
    386                                                   (U8CPU)(SkColorGetR(source) * scale),
    387                                                   (U8CPU)(SkColorGetG(source) * scale),
    388                                                   (U8CPU)(SkColorGetB(source) * scale));
    389                 }
    390             } else {
    391                 if (SkColorGetA(source) > outerThreshold) {
    392                     float scale = (float)outerThreshold / SkColorGetA(source);
    393                     output_color = SkColorSetARGB(outerThreshold,
    394                                                   (U8CPU)(SkColorGetR(source) * scale),
    395                                                   (U8CPU)(SkColorGetG(source) * scale),
    396                                                   (U8CPU)(SkColorGetB(source) * scale));
    397                 }
    398             }
    399             dptr[y * dst->width() + x] = output_color;
    400         }
    401     }
    402 
    403     return true;
    404 }
    405 
    406 #ifndef SK_IGNORE_TO_STRING
    407 void SkAlphaThresholdFilterImpl::toString(SkString* str) const {
    408     str->appendf("SkAlphaThresholdImageFilter: (");
    409     str->appendf("inner: %f outer: %f", fInnerThreshold, fOuterThreshold);
    410     str->append(")");
    411 }
    412 #endif
    413 
    414