blob: a10e623f4a5d8857b44e8886fd3b464d55243f1b [file] [log] [blame]
sugoi@google.com781cc762013-01-15 15:40:19 +00001/*
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 "SkDisplacementMapEffect.h"
9#include "SkFlattenableBuffers.h"
10#include "SkUnPreMultiply.h"
11#if SK_SUPPORT_GPU
12#include "SkGr.h"
13#include "SkGrPixelRef.h"
14#include "gl/GrGLEffect.h"
15#include "gl/GrGLEffectMatrix.h"
16#include "GrTBackendEffectFactory.h"
17#endif
18
19namespace {
20
21template<SkDisplacementMapEffect::ChannelSelectorType type>
22uint32_t getValue(SkColor, const SkUnPreMultiply::Scale*) {
23 SkASSERT(!"Unknown channel selector");
24 return 0;
25}
26
27template<> uint32_t getValue<SkDisplacementMapEffect::kR_ChannelSelectorType>(
28 SkColor l, const SkUnPreMultiply::Scale* table) {
29 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedR32(l));
30}
31
32template<> uint32_t getValue<SkDisplacementMapEffect::kG_ChannelSelectorType>(
33 SkColor l, const SkUnPreMultiply::Scale* table) {
34 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedG32(l));
35}
36
37template<> uint32_t getValue<SkDisplacementMapEffect::kB_ChannelSelectorType>(
38 SkColor l, const SkUnPreMultiply::Scale* table) {
39 return SkUnPreMultiply::ApplyScale(table[SkGetPackedA32(l)], SkGetPackedB32(l));
40}
41
42template<> uint32_t getValue<SkDisplacementMapEffect::kA_ChannelSelectorType>(
43 SkColor l, const SkUnPreMultiply::Scale*) {
44 return SkGetPackedA32(l);
45}
46
47template<SkDisplacementMapEffect::ChannelSelectorType typeX,
48 SkDisplacementMapEffect::ChannelSelectorType typeY>
49void computeDisplacement(SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
50{
51 static const SkScalar Inv8bit = SkScalarDiv(SK_Scalar1, SkFloatToScalar(255.0f));
52 static const SkScalar Half8bit = SkFloatToScalar(255.0f * 0.5f);
53 const int dstW = displ->width();
54 const int dstH = displ->height();
55 const int srcW = src->width();
56 const int srcH = src->height();
57 const SkScalar scaleX = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstW)), Inv8bit);
58 const SkScalar scaleY = SkScalarMul(SkScalarMul(scale, SkIntToScalar(dstH)), Inv8bit);
59 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
60 for (int y = 0; y < dstH; ++y) {
61 const SkPMColor* displPtr = displ->getAddr32(0, y);
62 SkPMColor* dstPtr = dst->getAddr32(0, y);
63 for (int x = 0; x < dstW; ++x, ++displPtr, ++dstPtr) {
64 const SkScalar displX =
65 SkScalarMul(scaleX, SkIntToScalar(getValue<typeX>(*displPtr, table))-Half8bit);
66 const SkScalar displY =
67 SkScalarMul(scaleY, SkIntToScalar(getValue<typeY>(*displPtr, table))-Half8bit);
68 const int coordX = x + SkScalarRoundToInt(displX);
69 const int coordY = y + SkScalarRoundToInt(displY);
70 *dstPtr = ((coordX < 0) || (coordX >= srcW) || (coordY < 0) || (coordY >= srcH)) ?
71 0 : *(src->getAddr32(coordX, coordY));
72 }
73 }
74}
75
76template<SkDisplacementMapEffect::ChannelSelectorType typeX>
77void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
78 SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
79{
80 switch (yChannelSelector) {
81 case SkDisplacementMapEffect::kR_ChannelSelectorType:
82 computeDisplacement<typeX, SkDisplacementMapEffect::kR_ChannelSelectorType>(
83 scale, dst, displ, src);
84 break;
85 case SkDisplacementMapEffect::kG_ChannelSelectorType:
86 computeDisplacement<typeX, SkDisplacementMapEffect::kG_ChannelSelectorType>(
87 scale, dst, displ, src);
88 break;
89 case SkDisplacementMapEffect::kB_ChannelSelectorType:
90 computeDisplacement<typeX, SkDisplacementMapEffect::kB_ChannelSelectorType>(
91 scale, dst, displ, src);
92 break;
93 case SkDisplacementMapEffect::kA_ChannelSelectorType:
94 computeDisplacement<typeX, SkDisplacementMapEffect::kA_ChannelSelectorType>(
95 scale, dst, displ, src);
96 break;
97 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
98 default:
99 SkASSERT(!"Unknown Y channel selector");
100 }
101}
102
103void computeDisplacement(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
104 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
105 SkScalar scale, SkBitmap* dst, SkBitmap* displ, SkBitmap* src)
106{
107 switch (xChannelSelector) {
108 case SkDisplacementMapEffect::kR_ChannelSelectorType:
109 computeDisplacement<SkDisplacementMapEffect::kR_ChannelSelectorType>(
110 yChannelSelector, scale, dst, displ, src);
111 break;
112 case SkDisplacementMapEffect::kG_ChannelSelectorType:
113 computeDisplacement<SkDisplacementMapEffect::kG_ChannelSelectorType>(
114 yChannelSelector, scale, dst, displ, src);
115 break;
116 case SkDisplacementMapEffect::kB_ChannelSelectorType:
117 computeDisplacement<SkDisplacementMapEffect::kB_ChannelSelectorType>(
118 yChannelSelector, scale, dst, displ, src);
119 break;
120 case SkDisplacementMapEffect::kA_ChannelSelectorType:
121 computeDisplacement<SkDisplacementMapEffect::kA_ChannelSelectorType>(
122 yChannelSelector, scale, dst, displ, src);
123 break;
124 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
125 default:
126 SkASSERT(!"Unknown X channel selector");
127 }
128}
129
130} // end namespace
131
132///////////////////////////////////////////////////////////////////////////////
133
134SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector,
135 ChannelSelectorType yChannelSelector,
136 SkScalar scale,
137 SkImageFilter* displacement,
138 SkImageFilter* color)
139 : INHERITED(displacement, color)
140 , fXChannelSelector(xChannelSelector)
141 , fYChannelSelector(yChannelSelector)
142 , fScale(scale)
143{
144}
145
146SkDisplacementMapEffect::~SkDisplacementMapEffect() {
147}
148
149SkDisplacementMapEffect::SkDisplacementMapEffect(SkFlattenableReadBuffer& buffer)
150 : INHERITED(buffer)
151{
152 fXChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
153 fYChannelSelector = (SkDisplacementMapEffect::ChannelSelectorType) buffer.readInt();
154 fScale = buffer.readScalar();
155}
156
157void SkDisplacementMapEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
158 this->INHERITED::flatten(buffer);
159 buffer.writeInt((int) fXChannelSelector);
160 buffer.writeInt((int) fYChannelSelector);
161 buffer.writeScalar(fScale);
162}
163
164bool SkDisplacementMapEffect::onFilterImage(Proxy* proxy,
165 const SkBitmap& src,
166 const SkMatrix& ctm,
167 SkBitmap* dst,
168 SkIPoint* offset) {
169 SkBitmap displ, color = src;
170 SkImageFilter* colorInput = getColorInput();
171 SkImageFilter* displacementInput = getDisplacementInput();
172 SkASSERT(NULL != displacementInput);
173 if ((colorInput && !colorInput->filterImage(proxy, src, ctm, &color, offset)) ||
174 !displacementInput->filterImage(proxy, src, ctm, &displ, offset)) {
175 return false;
176 }
177 if ((displ.config() != SkBitmap::kARGB_8888_Config) ||
178 (color.config() != SkBitmap::kARGB_8888_Config)) {
179 return false;
180 }
181
182 SkAutoLockPixels alp_displacement(displ), alp_color(color);
183 if (!displ.getPixels() || !color.getPixels()) {
184 return false;
185 }
186 dst->setConfig(displ.config(), displ.width(), displ.height());
187 dst->allocPixels();
188 if (!dst->getPixels()) {
189 return false;
190 }
191
192 computeDisplacement(fXChannelSelector, fYChannelSelector, fScale, dst, &displ, &color);
193
194 return true;
195}
196
197///////////////////////////////////////////////////////////////////////////////
198
199#if SK_SUPPORT_GPU
200class GrGLDisplacementMapEffect : public GrGLEffect {
201public:
202 GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
203 const GrEffect& effect);
204 virtual ~GrGLDisplacementMapEffect();
205
206 virtual void emitCode(GrGLShaderBuilder*,
207 const GrEffectStage&,
208 EffectKey,
209 const char* vertexCoords,
210 const char* outputColor,
211 const char* inputColor,
212 const TextureSamplerArray&) SK_OVERRIDE;
213
214 static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
215
216 virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
217
218private:
219 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
220 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
221 GrGLEffectMatrix fDisplacementEffectMatrix;
222 GrGLEffectMatrix fColorEffectMatrix;
223 GrGLUniformManager::UniformHandle fScaleUni;
224 GrGLUniformManager::UniformHandle fYSignColor;
225 GrGLUniformManager::UniformHandle fYSignDispl;
226
227 typedef GrGLEffect INHERITED;
228};
229
230///////////////////////////////////////////////////////////////////////////////
231
232class GrDisplacementMapEffect : public GrEffect {
233public:
234 GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
235 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
236 SkScalar scale, GrTexture* displacement, GrTexture* color);
237 virtual ~GrDisplacementMapEffect();
238
239 virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
240 const GrBackendEffectFactory& getFactory() const;
241 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
242 { return fXChannelSelector; }
243 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
244 { return fYChannelSelector; }
245 SkScalar scale() const { return fScale; }
246
247 typedef GrGLDisplacementMapEffect GLEffect;
248 static const char* Name() { return "DisplacementMap"; }
249
250 void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
251
252private:
253 GR_DECLARE_EFFECT_TEST;
254
255 GrTextureAccess fDisplacementAccess;
256 GrTextureAccess fColorAccess;
257 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
258 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
259 SkScalar fScale;
260
261 typedef GrEffect INHERITED;
262};
263
264// FIXME: This should be refactored with SkSingleInputImageFilter's version.
265static GrTexture* getInputResultAsTexture(SkImageFilter::Proxy* proxy,
266 SkImageFilter* input,
267 GrTexture* src,
268 const SkRect& rect) {
269 GrTexture* resultTex = NULL;
270 if (!input) {
271 resultTex = src;
272 } else if (input->canFilterImageGPU()) {
273 // filterImageGPU() already refs the result, so just return it here.
274 return input->filterImageGPU(proxy, src, rect);
275 } else {
276 SkBitmap srcBitmap, result;
277 srcBitmap.setConfig(SkBitmap::kARGB_8888_Config, src->width(), src->height());
278 srcBitmap.setPixelRef(new SkGrPixelRef(src))->unref();
279 SkIPoint offset;
280 if (input->filterImage(proxy, srcBitmap, SkMatrix(), &result, &offset)) {
281 if (result.getTexture()) {
282 resultTex = (GrTexture*) result.getTexture();
283 } else {
284 resultTex = GrLockCachedBitmapTexture(src->getContext(), result, NULL);
285 SkSafeRef(resultTex);
286 GrUnlockCachedBitmapTexture(resultTex);
287 return resultTex;
288 }
289 } else {
290 resultTex = src;
291 }
292 }
293 SkSafeRef(resultTex);
294 return resultTex;
295}
296
297GrTexture* SkDisplacementMapEffect::filterImageGPU(Proxy* proxy, GrTexture* src,
298 const SkRect& rect) {
299 SkAutoTUnref<GrTexture> color(getInputResultAsTexture(proxy, getColorInput(), src, rect));
300 SkAutoTUnref<GrTexture> displacement(getInputResultAsTexture(proxy, getDisplacementInput(),
301 src, rect));
302 GrContext* context = src->getContext();
303
304 GrTextureDesc desc;
305 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
306 desc.fWidth = SkScalarCeilToInt(rect.width());
307 desc.fHeight = SkScalarCeilToInt(rect.height());
308 desc.fConfig = kRGBA_8888_GrPixelConfig;
309
310 GrAutoScratchTexture ast(context, desc);
311 GrTexture* dst = ast.detach();
312
313 GrContext::AutoMatrix am;
314 am.setIdentity(context);
315
316 GrContext::AutoRenderTarget art(context, dst->asRenderTarget());
317 GrContext::AutoClip ac(context, rect);
318
319 GrPaint paint;
320 paint.colorStage(0)->setEffect(
321 SkNEW_ARGS(GrDisplacementMapEffect, (fXChannelSelector, fYChannelSelector, fScale,
322 displacement.get(), color.get())))->unref();
323 context->drawRect(paint, rect);
324 return dst;
325}
326
327///////////////////////////////////////////////////////////////////////////////
328
329GrDisplacementMapEffect::GrDisplacementMapEffect(
330 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
331 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector,
332 SkScalar scale,
333 GrTexture* displacement,
334 GrTexture* color)
335 : fDisplacementAccess(displacement)
336 , fColorAccess(color)
337 , fXChannelSelector(xChannelSelector)
338 , fYChannelSelector(yChannelSelector)
339 , fScale(scale) {
340 this->addTextureAccess(&fDisplacementAccess);
341 this->addTextureAccess(&fColorAccess);
342}
343
344GrDisplacementMapEffect::~GrDisplacementMapEffect() {
345}
346
347bool GrDisplacementMapEffect::isEqual(const GrEffect& sBase) const {
348 const GrDisplacementMapEffect& s = static_cast<const GrDisplacementMapEffect&>(sBase);
349 return INHERITED::isEqual(sBase) && fXChannelSelector == s.fXChannelSelector &&
350 fYChannelSelector == s.fYChannelSelector && fScale == s.fScale;
351}
352
353const GrBackendEffectFactory& GrDisplacementMapEffect::getFactory() const {
354 return GrTBackendEffectFactory<GrDisplacementMapEffect>::getInstance();
355}
356
357void GrDisplacementMapEffect::getConstantColorComponents(GrColor* color,
358 uint32_t* validFlags) const {
359 // Any displacement offset bringing a pixel out of bounds will output a color of (0,0,0,0),
360 // so the only way we'd get a constant alpha is if the input color image has a constant alpha
361 // and no displacement offset push any texture coordinates out of bounds OR if the constant
362 // alpha is 0. Since this isn't trivial to compute at this point, let's assume the output is
363 // not of constant color when a displacement effect is applied.
364 *validFlags = 0;
365}
366
367///////////////////////////////////////////////////////////////////////////////
368
369GR_DEFINE_EFFECT_TEST(GrDisplacementMapEffect);
370
371GrEffect* GrDisplacementMapEffect::TestCreate(SkRandom* random,
372 GrContext* context,
373 GrTexture* textures[]) {
374 int texIdxDispl = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
375 GrEffectUnitTest::kAlphaTextureIdx;
376 int texIdxColor = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
377 GrEffectUnitTest::kAlphaTextureIdx;
378 static const int kMaxComponent = 4;
379 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector =
380 static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
381 random->nextRangeU(1, kMaxComponent));
382 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector =
383 static_cast<SkDisplacementMapEffect::ChannelSelectorType>(
384 random->nextRangeU(1, kMaxComponent));
385 SkScalar scale = random->nextUScalar1();
386
387 return SkNEW_ARGS(GrDisplacementMapEffect, (xChannelSelector, yChannelSelector, scale,
388 textures[texIdxDispl], textures[texIdxColor]));
389}
390
391///////////////////////////////////////////////////////////////////////////////
392
393GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory, const GrEffect& effect)
394 : INHERITED(factory)
395 , fXChannelSelector(static_cast<const GrDisplacementMapEffect&>(effect).xChannelSelector())
396 , fYChannelSelector(static_cast<const GrDisplacementMapEffect&>(effect).yChannelSelector()) {
397}
398
399GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
400}
401
402void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
403 const GrEffectStage&,
404 EffectKey key,
405 const char* vertexCoords,
406 const char* outputColor,
407 const char* inputColor,
408 const TextureSamplerArray& samplers) {
409 fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
410 kVec2f_GrSLType, "Scale");
411 const char* scaleUni = builder->getUniformCStr(fScaleUni);
412
413 const char* dCoordsIn;
414 GrSLType dCoordsType = fDisplacementEffectMatrix.emitCode(
415 builder, key, vertexCoords, &dCoordsIn, NULL, "DISPL");
416 const char* cCoordsIn;
417 GrSLType cCoordsType = fColorEffectMatrix.emitCode(
418 builder, key, vertexCoords, &cCoordsIn, NULL, "COLOR");
419
420 SkString* code = &builder->fFSCode;
421 const char* dColor = "dColor";
422 const char* dCoords = "dCoords";
423 const char* cCoords = "cCoords";
424 const char* nearZero = "1e-6"; // Since 6.10352e−5 is the smallest half float, use
425 // a number smaller than that to approximate 0, but
426 // leave room for 32-bit float GPU rounding errors.
427
428 code->appendf("\t\tvec4 %s = ", dColor);
429 builder->appendTextureLookup(code, samplers[0], dCoordsIn, dCoordsType);
430 code->append(";\n");
431
432 // Unpremultiply the displacement
433 code->appendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
434 dColor, dColor, nearZero, dColor, dColor);
435
436 code->appendf("\t\tvec2 %s = %s + %s*(%s.",
437 cCoords, cCoordsIn, scaleUni, dColor);
438
439 switch (fXChannelSelector) {
440 case SkDisplacementMapEffect::kR_ChannelSelectorType:
441 code->append("r");
442 break;
443 case SkDisplacementMapEffect::kG_ChannelSelectorType:
444 code->append("g");
445 break;
446 case SkDisplacementMapEffect::kB_ChannelSelectorType:
447 code->append("b");
448 break;
449 case SkDisplacementMapEffect::kA_ChannelSelectorType:
450 code->append("a");
451 break;
452 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
453 default:
454 SkASSERT(!"Unknown X channel selector");
455 }
456
457 switch (fYChannelSelector) {
458 case SkDisplacementMapEffect::kR_ChannelSelectorType:
459 code->append("r");
460 break;
461 case SkDisplacementMapEffect::kG_ChannelSelectorType:
462 code->append("g");
463 break;
464 case SkDisplacementMapEffect::kB_ChannelSelectorType:
465 code->append("b");
466 break;
467 case SkDisplacementMapEffect::kA_ChannelSelectorType:
468 code->append("a");
469 break;
470 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
471 default:
472 SkASSERT(!"Unknown Y channel selector");
473 }
474 code->append("-vec2(0.5));\t\t");
475
476 // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
477 // a 0 border color instead of computing if cCoords is out of bounds here.
478 code->appendf(
479 "%s = any(greaterThan(vec4(vec2(0.0), %s), vec4(%s, vec2(1.0)))) ? vec4(0.0) : ",
480 outputColor, cCoords, cCoords);
481 builder->appendTextureLookup(code, samplers[1], cCoords, cCoordsType);
482 code->append(";\n");
483}
484
485void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
486 const GrDisplacementMapEffect& displacementMap = static_cast<const GrDisplacementMapEffect&>(*stage.getEffect());
487 GrTexture* displTex = displacementMap.texture(0);
488 GrTexture* colorTex = displacementMap.texture(1);
489 fDisplacementEffectMatrix.setData(uman,
490 GrEffect::MakeDivByTextureWHMatrix(displTex),
491 stage.getCoordChangeMatrix(),
492 displTex);
493 fColorEffectMatrix.setData(uman,
494 GrEffect::MakeDivByTextureWHMatrix(colorTex),
495 stage.getCoordChangeMatrix(),
496 colorTex);
497
498 uman.set2f(fScaleUni, SkScalarToFloat(displacementMap.scale()),
499 colorTex->origin() == GrSurface::kTopLeft_Origin ?
500 SkScalarToFloat(displacementMap.scale()) :
501 SkScalarToFloat(-displacementMap.scale()));
502}
503
504GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrEffectStage& stage,
505 const GrGLCaps&) {
506 const GrDisplacementMapEffect& displacementMap =
507 static_cast<const GrDisplacementMapEffect&>(*stage.getEffect());
508
509 GrTexture* displTex = displacementMap.texture(0);
510 GrTexture* colorTex = displacementMap.texture(1);
511
512 EffectKey displKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(displTex),
513 stage.getCoordChangeMatrix(),
514 displTex);
515
516 EffectKey colorKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(colorTex),
517 stage.getCoordChangeMatrix(),
518 colorTex);
519
520 colorKey <<= GrGLEffectMatrix::kKeyBits;
521 EffectKey xKey = displacementMap.xChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits);
522 EffectKey yKey = displacementMap.yChannelSelector() << (2 * GrGLEffectMatrix::kKeyBits +
523 SkDisplacementMapEffect::kKeyBits);
524
525 return xKey | yKey | displKey | colorKey;
526}
527#endif