OLD | NEW |
| (Empty) |
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); | |
15 BATShader(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) { | |
16 // We should probably do something here. | |
17 } | |
18 | |
19 | |
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) c
onst 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 | |
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 | |
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 | |
52 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: | |
81 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
82 return GrTBackendEffectFactory<ThresholdEffect>::getInstance(); | |
83 } | |
84 | |
85 static GrEffectRef* Create(GrTexture* bmpTexture, const SkMatrix& bmpMatrix, | |
86 GrTexture* maskTexture, const SkMatrix& maskMatri
x, | |
87 U8CPU threshold) { | |
88 SkScalar thresh = SkIntToScalar(threshold) / 255; | |
89 | |
90 AutoEffectUnref effect(SkNEW_ARGS(ThresholdEffect, (bmpTexture, bmpMatri
x, | |
91 maskTexture, maskMat
rix, | |
92 thresh))); | |
93 return CreateEffectRef(effect); | |
94 } | |
95 | |
96 virtual void getConstantColorComponents(GrColor* color, | |
97 uint32_t* validFlags) const SK_OVERR
IDE { | |
98 if ((kA_GrColorComponentFlag & *validFlags) && 0 == GrColorUnpackA(*colo
r)) { | |
99 return; | |
100 } | |
101 *validFlags = 0; | |
102 return; | |
103 } | |
104 | |
105 static const char* Name() { return "Bitmap Alpha Threshold"; } | |
106 | |
107 class GLEffect : public GrGLEffect { | |
108 public: | |
109 GLEffect(const GrBackendEffectFactory& factory, | |
110 const GrDrawEffect& e) | |
111 : GrGLEffect(factory) | |
112 , fPrevThreshold(-SK_Scalar1) { | |
113 } | |
114 | |
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(), coord
s[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(), coord
s[1].type()); | |
130 builder->fsCodeAppend(".a;\n"); | |
131 | |
132 const char* threshold; | |
133 | |
134 fThresholdUniHandle = builder->addUniform(GrGLShaderBuilder::kFragme
nt_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 | |
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: | |
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 | |
185 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 | |
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 | |
214 GrEffectRef* BATShader::asNewEffect(GrContext* context, const SkPaint& paint) co
nst { | |
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_GrTextureFlagB
it; | |
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_ScratchTexMat
ch); | |
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, NU
LL); | |
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 | |
OLD | NEW |