• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkBitmapAlphaThresholdShader.h"
9 
10 class BATShader : public SkShader {
11 public:
12     SK_DECLARE_INST_COUNT(BATShader);
13 
14     BATShader(const SkBitmap& bitmap, SkRegion region, U8CPU);
BATShader(SkFlattenableReadBuffer & buffer)15     BATShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
16         // We should probably do something here.
17     }
18 
19 
shadeSpan(int x,int y,SkPMColor[],int count)20     virtual void shadeSpan(int x, int y, SkPMColor[], int count) SK_OVERRIDE {};
21 
22 #if SK_SUPPORT_GPU
23     virtual GrEffectRef* asNewEffect(GrContext* context, const SkPaint& paint) const SK_OVERRIDE;
24 #endif
25 
26     SK_DEVELOPER_TO_STRING();
27     SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(BATShader)
28 
29 private:
30     SkBitmap fBitmap;
31     SkRegion fRegion;
32     U8CPU    fThreshold;
33 
34     typedef SkShader INHERITED;
35 };
36 
Create(const SkBitmap & bitmap,const SkRegion & region,U8CPU threshold)37 SkShader* SkBitmapAlphaThresholdShader::Create(const SkBitmap& bitmap,
38                                                const SkRegion& region,
39                                                U8CPU threshold) {
40     SkASSERT(threshold < 256);
41     return SkNEW_ARGS(BATShader, (bitmap, region, threshold));
42 }
43 
BATShader(const SkBitmap & bitmap,SkRegion region,U8CPU threshold)44 BATShader::BATShader(const SkBitmap& bitmap, SkRegion region, U8CPU threshold)
45 : fBitmap(bitmap)
46 , fRegion(region)
47 , fThreshold(threshold) {
48 };
49 
50 
51 #ifdef SK_DEVELOPER
toString(SkString * str) const52 void BATShader::toString(SkString* str) const {
53     str->append("BATShader: (");
54 
55     fBitmap.toString(str);
56 
57     this->INHERITED::toString(str);
58 
59     str->append(")");
60 }
61 #endif
62 
63 #if SK_SUPPORT_GPU
64 #include "GrContext.h"
65 #include "GrCoordTransform.h"
66 #include "GrEffect.h"
67 #include "gl/GrGLEffect.h"
68 #include "GrTBackendEffectFactory.h"
69 #include "GrTextureAccess.h"
70 
71 #include "SkGr.h"
72 
73 /**
74  * Could create specializations for some simple cases:
75  *  - The region is empty.
76  *  - The region fully contains the bitmap.
77  *  - The regions is 1 rect (or maybe a small number of rects).
78  */
79 class ThresholdEffect : public GrEffect {
80 public:
getFactory() const81     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
82         return GrTBackendEffectFactory<ThresholdEffect>::getInstance();
83     }
84 
Create(GrTexture * bmpTexture,const SkMatrix & bmpMatrix,GrTexture * maskTexture,const SkMatrix & maskMatrix,U8CPU threshold)85     static GrEffectRef* Create(GrTexture* bmpTexture, const SkMatrix& bmpMatrix,
86                                GrTexture* maskTexture, const SkMatrix& maskMatrix,
87                                U8CPU threshold) {
88         SkScalar thresh = SkIntToScalar(threshold) / 255;
89 
90         AutoEffectUnref effect(SkNEW_ARGS(ThresholdEffect, (bmpTexture, bmpMatrix,
91                                                             maskTexture, maskMatrix,
92                                                             thresh)));
93         return CreateEffectRef(effect);
94     }
95 
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const96     virtual void getConstantColorComponents(GrColor* color,
97                                             uint32_t* validFlags) const SK_OVERRIDE {
98         if ((kA_GrColorComponentFlag & *validFlags) && 0 == GrColorUnpackA(*color)) {
99             return;
100         }
101         *validFlags = 0;
102         return;
103     }
104 
Name()105     static const char* Name() { return "Bitmap Alpha Threshold"; }
106 
107     class GLEffect : public GrGLEffect {
108     public:
GLEffect(const GrBackendEffectFactory & factory,const GrDrawEffect & e)109         GLEffect(const GrBackendEffectFactory& factory,
110                     const GrDrawEffect& e)
111         : GrGLEffect(factory)
112         , fPrevThreshold(-SK_Scalar1) {
113         }
114 
emitCode(GrGLShaderBuilder * builder,const GrDrawEffect & drawEffect,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray & coords,const TextureSamplerArray & samplers)115         virtual void emitCode(GrGLShaderBuilder* builder,
116                               const GrDrawEffect& drawEffect,
117                               EffectKey key,
118                               const char* outputColor,
119                               const char* inputColor,
120                               const TransformedCoordsArray& coords,
121                               const TextureSamplerArray& samplers) SK_OVERRIDE {
122             // put bitmap color in "color"
123             builder->fsCodeAppend("\t\tvec4 color = ");
124             builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
125             builder->fsCodeAppend(";\n");
126 
127             // put alpha from mask texture in "mask"
128             builder->fsCodeAppend("\t\tfloat mask = ");
129             builder->fsAppendTextureLookup(samplers[1], coords[1].c_str(), coords[1].type());
130             builder->fsCodeAppend(".a;\n");
131 
132             const char* threshold;
133 
134             fThresholdUniHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
135                                                       kFloat_GrSLType,
136                                                       "threshold",
137                                                       &threshold);
138             builder->fsCodeAppendf("\t\tfloat thresh = %s;\n", threshold);
139 
140             builder->fsCodeAppend("\t\tif (mask < 0.5) {\n"
141                                     "\t\t\tif (color.a > thresh) {\n"
142                                     "\t\t\t\tfloat scale = thresh / color.a;\n"
143                                     "\t\t\t\tcolor.rgb *= scale;\n"
144                                     "\t\t\t\tcolor.a = thresh;\n"
145                                     "\t\t\t}\n"
146                                     "\t\t} else if (color.a < thresh) {\n"
147                                     "\t\t\tfloat scale = thresh / color.a;\n"
148                                     "\t\t\tcolor.rgb *= scale;\n"
149                                     "\t\t\tcolor.a = thresh;\n"
150                                     "\t\t}\n");
151 
152             builder->fsCodeAppendf("color = %s = %s;\n", outputColor,
153                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr4("color")).c_str());
154         }
155 
setData(const GrGLUniformManager & uman,const GrDrawEffect & e)156         virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect& e) SK_OVERRIDE {
157             const ThresholdEffect& effect = e.castEffect<ThresholdEffect>();
158             if (fPrevThreshold != effect.fThreshold) {
159                 uman.set1f(fThresholdUniHandle, effect.fThreshold);
160             }
161         }
162 
163     private:
164         GrGLUniformManager::UniformHandle fThresholdUniHandle;
165         SkScalar                          fPrevThreshold;
166     };
167 
168     GR_DECLARE_EFFECT_TEST;
169 
170 private:
ThresholdEffect(GrTexture * bmpTexture,const SkMatrix & bmpMatrix,GrTexture * maskTexture,const SkMatrix & maskMatrix,SkScalar threshold)171     ThresholdEffect(GrTexture* bmpTexture, const SkMatrix& bmpMatrix,
172                     GrTexture* maskTexture, const SkMatrix& maskMatrix,
173                     SkScalar threshold)
174     : fBmpTransform(kLocal_GrCoordSet, bmpMatrix, bmpTexture)
175     , fBmpAccess(bmpTexture, GrTextureParams())
176     , fMaskTransform(kLocal_GrCoordSet, maskMatrix, maskTexture)
177     , fMaskAccess(maskTexture, GrTextureParams())
178     , fThreshold(threshold) {
179         this->addCoordTransform(&fBmpTransform);
180         this->addTextureAccess(&fBmpAccess);
181         this->addCoordTransform(&fMaskTransform);
182         this->addTextureAccess(&fMaskAccess);
183     }
184 
onIsEqual(const GrEffect & other) const185     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
186         const ThresholdEffect& e = CastEffect<ThresholdEffect>(other);
187         return e.fBmpAccess.getTexture() == fBmpAccess.getTexture() &&
188                e.fMaskAccess.getTexture() == fMaskAccess.getTexture() &&
189                e.fBmpTransform.getMatrix() == fBmpTransform.getMatrix() &&
190                e.fMaskTransform.getMatrix() == fMaskTransform.getMatrix() &&
191                e.fThreshold == fThreshold;
192     }
193 
194     GrCoordTransform fBmpTransform;
195     GrTextureAccess  fBmpAccess;
196     GrCoordTransform fMaskTransform;
197     GrTextureAccess  fMaskAccess;
198 
199     SkScalar fThreshold;
200 };
201 
202 GR_DEFINE_EFFECT_TEST(ThresholdEffect);
203 
TestCreate(SkRandom * rand,GrContext *,const GrDrawTargetCaps &,GrTexture * textures[])204 GrEffectRef* ThresholdEffect::TestCreate(SkRandom* rand,
205                                          GrContext*,
206                                          const GrDrawTargetCaps&,
207                                          GrTexture* textures[]) {
208     GrTexture* bmpTex = textures[GrEffectUnitTest::kSkiaPMTextureIdx];
209     GrTexture* maskTex = textures[GrEffectUnitTest::kAlphaTextureIdx];
210     U8CPU thresh = rand->nextU() % 0xff;
211     return ThresholdEffect::Create(bmpTex, SkMatrix::I(), maskTex, SkMatrix::I(), thresh);
212 }
213 
asNewEffect(GrContext * context,const SkPaint & paint) const214 GrEffectRef* BATShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
215     SkMatrix localInverse;
216     if (!this->getLocalMatrix().invert(&localInverse)) {
217         return NULL;
218     }
219 
220     GrTextureDesc maskDesc;
221     if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
222         maskDesc.fConfig = kAlpha_8_GrPixelConfig;
223     } else {
224         maskDesc.fConfig = kRGBA_8888_GrPixelConfig;
225     }
226     maskDesc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
227     const SkIRect& bounds = fRegion.getBounds();
228     // Add one pixel of border to ensure that clamp mode will be all zeros
229     // the outside.
230     maskDesc.fWidth = bounds.width() + 2;
231     maskDesc.fHeight = bounds.height() + 2;
232     GrAutoScratchTexture ast(context, maskDesc, GrContext::kApprox_ScratchTexMatch);
233     GrTexture*  maskTexture = ast.texture();
234     if (NULL == maskTexture) {
235         return NULL;
236     }
237 
238     GrPaint grPaint;
239     grPaint.setBlendFunc(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
240     SkRegion::Iterator iter(fRegion);
241     context->setRenderTarget(maskTexture->asRenderTarget());
242     context->clear(NULL, 0x0, true);
243 
244     // offset to ensure border is zero on top/left
245     SkMatrix matrix;
246     matrix.setTranslate(SK_Scalar1, SK_Scalar1);
247     context->setMatrix(matrix);
248 
249     while (!iter.done()) {
250         SkRect rect = SkRect::Make(iter.rect());
251         context->drawRect(grPaint, rect);
252         iter.next();
253     }
254 
255     GrTexture* bmpTexture = GrLockAndRefCachedBitmapTexture(context, fBitmap, NULL);
256     if (NULL == bmpTexture) {
257         return NULL;
258     }
259 
260     SkMatrix bmpMatrix = localInverse;
261     bmpMatrix.postIDiv(bmpTexture->width(), bmpTexture->height());
262 
263     SkMatrix maskMatrix = localInverse;
264     // compensate for the border
265     maskMatrix.postTranslate(SK_Scalar1, SK_Scalar1);
266     maskMatrix.postIDiv(maskTexture->width(), maskTexture->height());
267 
268     GrEffectRef* effect = ThresholdEffect::Create(bmpTexture, bmpMatrix,
269                                                   maskTexture, maskMatrix,
270                                                   fThreshold);
271 
272     GrUnlockAndUnrefCachedBitmapTexture(bmpTexture);
273 
274     return effect;
275 }
276 
277 #endif
278