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 "SkDisplacementMapEffect.h" 9 10#include "SkBitmap.h" 11#include "SkColorSpaceXformer.h" 12#include "SkImageFilterPriv.h" 13#include "SkReadBuffer.h" 14#include "SkSpecialImage.h" 15#include "SkWriteBuffer.h" 16#include "SkUnPreMultiply.h" 17#include "SkColorData.h" 18#if SK_SUPPORT_GPU 19#include "GrClip.h" 20#include "GrColorSpaceXform.h" 21#include "GrContext.h" 22#include "GrCoordTransform.h" 23#include "GrRenderTargetContext.h" 24#include "GrTexture.h" 25#include "GrTextureProxy.h" 26#include "SkGr.h" 27#include "effects/GrTextureDomain.h" 28#include "glsl/GrGLSLFragmentProcessor.h" 29#include "glsl/GrGLSLFragmentShaderBuilder.h" 30#include "glsl/GrGLSLProgramDataManager.h" 31#include "glsl/GrGLSLUniformHandler.h" 32#endif 33 34namespace { 35 36#define kChannelSelectorKeyBits 3; // Max value is 4, so 3 bits are required at most 37 38const uint8_t gChannelTypeToShift[] = { 39 0, // unknown 40 SK_R32_SHIFT, 41 SK_G32_SHIFT, 42 SK_B32_SHIFT, 43 SK_A32_SHIFT, 44}; 45struct Extractor { 46 Extractor(SkDisplacementMapEffect::ChannelSelectorType typeX, 47 SkDisplacementMapEffect::ChannelSelectorType typeY) 48 : fShiftX(gChannelTypeToShift[typeX]) 49 , fShiftY(gChannelTypeToShift[typeY]) 50 {} 51 52 unsigned fShiftX, fShiftY; 53 54 unsigned getX(SkPMColor c) const { return (c >> fShiftX) & 0xFF; } 55 unsigned getY(SkPMColor c) const { return (c >> fShiftY) & 0xFF; } 56}; 57 58static SkPMColor unpremul_pm(SkPMColor c) { 59 const U8CPU a = SkGetPackedA32(c); 60 if (0 == a) { 61 return 0; 62 } else if (0xFF == a) { 63 return c; 64 } 65 const unsigned scale = SkUnPreMultiply::GetScale(a); 66 return SkPackARGB32NoCheck(a, 67 SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(c)), 68 SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(c)), 69 SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(c))); 70} 71 72void computeDisplacement(Extractor ex, const SkVector& scale, SkBitmap* dst, 73 const SkBitmap& displ, const SkIPoint& offset, 74 const SkBitmap& src, 75 const SkIRect& bounds) { 76 static const SkScalar Inv8bit = SkScalarInvert(255); 77 const int srcW = src.width(); 78 const int srcH = src.height(); 79 const SkVector scaleForColor = SkVector::Make(scale.fX * Inv8bit, scale.fY * Inv8bit); 80 const SkVector scaleAdj = SkVector::Make(SK_ScalarHalf - scale.fX * SK_ScalarHalf, 81 SK_ScalarHalf - scale.fY * SK_ScalarHalf); 82 SkPMColor* dstPtr = dst->getAddr32(0, 0); 83 for (int y = bounds.top(); y < bounds.bottom(); ++y) { 84 const SkPMColor* displPtr = displ.getAddr32(bounds.left() + offset.fX, y + offset.fY); 85 for (int x = bounds.left(); x < bounds.right(); ++x, ++displPtr) { 86 SkPMColor c = unpremul_pm(*displPtr); 87 88 SkScalar displX = scaleForColor.fX * ex.getX(c) + scaleAdj.fX; 89 SkScalar displY = scaleForColor.fY * ex.getY(c) + scaleAdj.fY; 90 // Truncate the displacement values 91 const int srcX = x + SkScalarTruncToInt(displX); 92 const int srcY = y + SkScalarTruncToInt(displY); 93 *dstPtr++ = ((srcX < 0) || (srcX >= srcW) || (srcY < 0) || (srcY >= srcH)) ? 94 0 : *(src.getAddr32(srcX, srcY)); 95 } 96 } 97} 98 99bool channel_selector_type_is_valid(SkDisplacementMapEffect::ChannelSelectorType cst) { 100 switch (cst) { 101 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: 102 case SkDisplacementMapEffect::kR_ChannelSelectorType: 103 case SkDisplacementMapEffect::kG_ChannelSelectorType: 104 case SkDisplacementMapEffect::kB_ChannelSelectorType: 105 case SkDisplacementMapEffect::kA_ChannelSelectorType: 106 return true; 107 default: 108 break; 109 } 110 return false; 111} 112 113} // end namespace 114 115/////////////////////////////////////////////////////////////////////////////// 116 117sk_sp<SkImageFilter> SkDisplacementMapEffect::Make(ChannelSelectorType xChannelSelector, 118 ChannelSelectorType yChannelSelector, 119 SkScalar scale, 120 sk_sp<SkImageFilter> displacement, 121 sk_sp<SkImageFilter> color, 122 const CropRect* cropRect) { 123 if (!channel_selector_type_is_valid(xChannelSelector) || 124 !channel_selector_type_is_valid(yChannelSelector)) { 125 return nullptr; 126 } 127 128 sk_sp<SkImageFilter> inputs[2] = { std::move(displacement), std::move(color) }; 129 return sk_sp<SkImageFilter>(new SkDisplacementMapEffect(xChannelSelector, 130 yChannelSelector, 131 scale, inputs, cropRect)); 132} 133 134SkDisplacementMapEffect::SkDisplacementMapEffect(ChannelSelectorType xChannelSelector, 135 ChannelSelectorType yChannelSelector, 136 SkScalar scale, 137 sk_sp<SkImageFilter> inputs[2], 138 const CropRect* cropRect) 139 : INHERITED(inputs, 2, cropRect) 140 , fXChannelSelector(xChannelSelector) 141 , fYChannelSelector(yChannelSelector) 142 , fScale(scale) { 143} 144 145SkDisplacementMapEffect::~SkDisplacementMapEffect() { 146} 147 148sk_sp<SkFlattenable> SkDisplacementMapEffect::CreateProc(SkReadBuffer& buffer) { 149 SK_IMAGEFILTER_UNFLATTEN_COMMON(common, 2); 150 151 ChannelSelectorType xsel = buffer.read32LE(kLast_ChannelSelectorType); 152 ChannelSelectorType ysel = buffer.read32LE(kLast_ChannelSelectorType); 153 SkScalar scale = buffer.readScalar(); 154 155 return Make(xsel, ysel, scale, common.getInput(0), common.getInput(1), &common.cropRect()); 156} 157 158void SkDisplacementMapEffect::flatten(SkWriteBuffer& buffer) const { 159 this->INHERITED::flatten(buffer); 160 buffer.writeInt((int) fXChannelSelector); 161 buffer.writeInt((int) fYChannelSelector); 162 buffer.writeScalar(fScale); 163} 164 165#if SK_SUPPORT_GPU 166class GrDisplacementMapEffect : public GrFragmentProcessor { 167public: 168 static std::unique_ptr<GrFragmentProcessor> Make( 169 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, 170 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, SkVector scale, 171 sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix, 172 sk_sp<GrTextureProxy> color, const SkISize& colorDimensions) { 173 return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect( 174 xChannelSelector, yChannelSelector, scale, std::move(displacement), offsetMatrix, 175 std::move(color), colorDimensions)); 176 } 177 178 ~GrDisplacementMapEffect() override; 179 180 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const { 181 return fXChannelSelector; 182 } 183 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const { 184 return fYChannelSelector; 185 } 186 const SkVector& scale() const { return fScale; } 187 188 const char* name() const override { return "DisplacementMap"; } 189 const GrTextureDomain& domain() const { return fDomain; } 190 191 std::unique_ptr<GrFragmentProcessor> clone() const override; 192 193private: 194 static OptimizationFlags OptimizationFlags(GrPixelConfig colorConfig); 195 196 GrDisplacementMapEffect(const GrDisplacementMapEffect&); 197 198 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; 199 200 void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; 201 202 bool onIsEqual(const GrFragmentProcessor&) const override; 203 204 GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, 205 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, 206 const SkVector& scale, 207 sk_sp<GrTextureProxy> displacement, const SkMatrix& offsetMatrix, 208 sk_sp<GrTextureProxy> color, const SkISize& colorDimensions); 209 210 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 211 212 GrCoordTransform fDisplacementTransform; 213 TextureSampler fDisplacementSampler; 214 GrCoordTransform fColorTransform; 215 GrTextureDomain fDomain; 216 TextureSampler fColorSampler; 217 SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector; 218 SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector; 219 SkVector fScale; 220 221 typedef GrFragmentProcessor INHERITED; 222}; 223#endif 224 225sk_sp<SkSpecialImage> SkDisplacementMapEffect::onFilterImage(SkSpecialImage* source, 226 const Context& ctx, 227 SkIPoint* offset) const { 228 SkIPoint colorOffset = SkIPoint::Make(0, 0); 229 sk_sp<SkSpecialImage> color(this->filterInput(1, source, ctx, &colorOffset)); 230 if (!color) { 231 return nullptr; 232 } 233 234 SkIPoint displOffset = SkIPoint::Make(0, 0); 235 // Creation of the displacement map should happen in a non-colorspace aware context. This 236 // texture is a purely mathematical construct, so we want to just operate on the stored 237 // values. Consider: 238 // User supplies an sRGB displacement map. If we're rendering to a wider gamut, then we could 239 // end up filtering the displacement map into that gamut, which has the effect of reducing 240 // the amount of displacement that it represents (as encoded values move away from the 241 // primaries). 242 // With a more complex DAG attached to this input, it's not clear that working in ANY specific 243 // color space makes sense, so we ignore color spaces (and gamma) entirely. This may not be 244 // ideal, but it's at least consistent and predictable. 245 Context displContext(ctx.ctm(), ctx.clipBounds(), ctx.cache(), OutputProperties(nullptr)); 246 sk_sp<SkSpecialImage> displ(this->filterInput(0, source, displContext, &displOffset)); 247 if (!displ) { 248 return nullptr; 249 } 250 251 const SkIRect srcBounds = SkIRect::MakeXYWH(colorOffset.x(), colorOffset.y(), 252 color->width(), color->height()); 253 254 // Both paths do bounds checking on color pixel access, we don't need to 255 // pad the color bitmap to bounds here. 256 SkIRect bounds; 257 if (!this->applyCropRect(ctx, srcBounds, &bounds)) { 258 return nullptr; 259 } 260 261 SkIRect displBounds; 262 displ = this->applyCropRect(ctx, displ.get(), &displOffset, &displBounds); 263 if (!displ) { 264 return nullptr; 265 } 266 267 if (!bounds.intersect(displBounds)) { 268 return nullptr; 269 } 270 271 const SkIRect colorBounds = bounds.makeOffset(-colorOffset.x(), -colorOffset.y()); 272 273 SkVector scale = SkVector::Make(fScale, fScale); 274 ctx.ctm().mapVectors(&scale, 1); 275 276#if SK_SUPPORT_GPU 277 if (source->isTextureBacked()) { 278 GrContext* context = source->getContext(); 279 280 sk_sp<GrTextureProxy> colorProxy(color->asTextureProxyRef(context)); 281 sk_sp<GrTextureProxy> displProxy(displ->asTextureProxyRef(context)); 282 if (!colorProxy || !displProxy) { 283 return nullptr; 284 } 285 286 SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX), 287 SkIntToScalar(colorOffset.fY - displOffset.fY)); 288 SkColorSpace* colorSpace = ctx.outputProperties().colorSpace(); 289 290 GrPixelConfig colorConfig = colorProxy->config(); 291 std::unique_ptr<GrFragmentProcessor> fp = 292 GrDisplacementMapEffect::Make(fXChannelSelector, 293 fYChannelSelector, 294 scale, 295 std::move(displProxy), 296 offsetMatrix, 297 std::move(colorProxy), 298 SkISize::Make(color->width(), color->height())); 299 fp = GrColorSpaceXformEffect::Make(std::move(fp), color->getColorSpace(), colorConfig, 300 colorSpace); 301 302 GrPaint paint; 303 paint.addColorFragmentProcessor(std::move(fp)); 304 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 305 SkMatrix matrix; 306 matrix.setTranslate(-SkIntToScalar(colorBounds.x()), -SkIntToScalar(colorBounds.y())); 307 308 sk_sp<GrRenderTargetContext> renderTargetContext( 309 context->makeDeferredRenderTargetContext(SkBackingFit::kApprox, 310 bounds.width(), bounds.height(), 311 GrRenderableConfigForColorSpace(colorSpace), 312 sk_ref_sp(colorSpace))); 313 if (!renderTargetContext) { 314 return nullptr; 315 } 316 paint.setGammaCorrect(renderTargetContext->colorSpaceInfo().isGammaCorrect()); 317 318 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, 319 SkRect::Make(colorBounds)); 320 321 offset->fX = bounds.left(); 322 offset->fY = bounds.top(); 323 return SkSpecialImage::MakeDeferredFromGpu( 324 context, 325 SkIRect::MakeWH(bounds.width(), bounds.height()), 326 kNeedNewImageUniqueID_SpecialImage, 327 renderTargetContext->asTextureProxyRef(), 328 renderTargetContext->colorSpaceInfo().refColorSpace()); 329 } 330#endif 331 332 SkBitmap colorBM, displBM; 333 334 if (!color->getROPixels(&colorBM) || !displ->getROPixels(&displBM)) { 335 return nullptr; 336 } 337 338 if ((colorBM.colorType() != kN32_SkColorType) || 339 (displBM.colorType() != kN32_SkColorType)) { 340 return nullptr; 341 } 342 343 if (!colorBM.getPixels() || !displBM.getPixels()) { 344 return nullptr; 345 } 346 347 SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), 348 colorBM.alphaType()); 349 350 SkBitmap dst; 351 if (!dst.tryAllocPixels(info)) { 352 return nullptr; 353 } 354 355 computeDisplacement(Extractor(fXChannelSelector, fYChannelSelector), scale, &dst, 356 displBM, colorOffset - displOffset, colorBM, colorBounds); 357 358 offset->fX = bounds.left(); 359 offset->fY = bounds.top(); 360 return SkSpecialImage::MakeFromRaster(SkIRect::MakeWH(bounds.width(), bounds.height()), 361 dst); 362} 363 364sk_sp<SkImageFilter> SkDisplacementMapEffect::onMakeColorSpace(SkColorSpaceXformer* xformer) const { 365 SkASSERT(2 == this->countInputs()); 366 // Intentionally avoid xforming the displacement filter. The values will be used as 367 // offsets, not as colors. 368 sk_sp<SkImageFilter> displacement = sk_ref_sp(const_cast<SkImageFilter*>(this->getInput(0))); 369 sk_sp<SkImageFilter> color = xformer->apply(this->getInput(1)); 370 371 if (color.get() != this->getInput(1)) { 372 return SkDisplacementMapEffect::Make(fXChannelSelector, fYChannelSelector, fScale, 373 std::move(displacement), std::move(color), 374 this->getCropRectIfSet()); 375 } 376 return this->refMe(); 377} 378 379SkRect SkDisplacementMapEffect::computeFastBounds(const SkRect& src) const { 380 SkRect bounds = this->getColorInput() ? this->getColorInput()->computeFastBounds(src) : src; 381 bounds.outset(SkScalarAbs(fScale) * SK_ScalarHalf, SkScalarAbs(fScale) * SK_ScalarHalf); 382 return bounds; 383} 384 385SkIRect SkDisplacementMapEffect::onFilterNodeBounds(const SkIRect& src, const SkMatrix& ctm, 386 MapDirection) const { 387 SkVector scale = SkVector::Make(fScale, fScale); 388 ctm.mapVectors(&scale, 1); 389 return src.makeOutset(SkScalarCeilToInt(SkScalarAbs(scale.fX) * SK_ScalarHalf), 390 SkScalarCeilToInt(SkScalarAbs(scale.fY) * SK_ScalarHalf)); 391} 392 393SkIRect SkDisplacementMapEffect::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, 394 MapDirection direction) const { 395 // Recurse only into color input. 396 if (this->getColorInput()) { 397 return this->getColorInput()->filterBounds(src, ctm, direction); 398 } 399 return src; 400} 401 402#ifndef SK_IGNORE_TO_STRING 403void SkDisplacementMapEffect::toString(SkString* str) const { 404 str->appendf("SkDisplacementMapEffect: ("); 405 str->appendf("scale: %f ", fScale); 406 str->appendf("displacement: ("); 407 if (this->getDisplacementInput()) { 408 this->getDisplacementInput()->toString(str); 409 } 410 str->appendf(") color: ("); 411 if (this->getColorInput()) { 412 this->getColorInput()->toString(str); 413 } 414 str->appendf("))"); 415} 416#endif 417 418/////////////////////////////////////////////////////////////////////////////// 419 420#if SK_SUPPORT_GPU 421class GrGLDisplacementMapEffect : public GrGLSLFragmentProcessor { 422public: 423 void emitCode(EmitArgs&) override; 424 425 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); 426 427protected: 428 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; 429 430private: 431 typedef GrGLSLProgramDataManager::UniformHandle UniformHandle; 432 433 UniformHandle fScaleUni; 434 GrTextureDomain::GLDomain fGLDomain; 435 436 typedef GrGLSLFragmentProcessor INHERITED; 437}; 438 439/////////////////////////////////////////////////////////////////////////////// 440 441GrGLSLFragmentProcessor* GrDisplacementMapEffect::onCreateGLSLInstance() const { 442 return new GrGLDisplacementMapEffect; 443} 444 445void GrDisplacementMapEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, 446 GrProcessorKeyBuilder* b) const { 447 GrGLDisplacementMapEffect::GenKey(*this, caps, b); 448} 449 450GrFragmentProcessor::OptimizationFlags GrDisplacementMapEffect::OptimizationFlags( 451 GrPixelConfig colorConfig) { 452 return GrPixelConfigIsOpaque(colorConfig) 453 ? GrFragmentProcessor::kPreservesOpaqueInput_OptimizationFlag 454 : GrFragmentProcessor::kNone_OptimizationFlags; 455} 456 457GrDisplacementMapEffect::GrDisplacementMapEffect( 458 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector, 459 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector, 460 const SkVector& scale, 461 sk_sp<GrTextureProxy> displacement, 462 const SkMatrix& offsetMatrix, 463 sk_sp<GrTextureProxy> color, 464 const SkISize& colorDimensions) 465 : INHERITED(kGrDisplacementMapEffect_ClassID, OptimizationFlags(color->config())) 466 , fDisplacementTransform(offsetMatrix, displacement.get()) 467 , fDisplacementSampler(displacement) 468 , fColorTransform(color.get()) 469 , fDomain(color.get(), GrTextureDomain::MakeTexelDomain(SkIRect::MakeSize(colorDimensions)), 470 GrTextureDomain::kDecal_Mode) 471 , fColorSampler(color) 472 , fXChannelSelector(xChannelSelector) 473 , fYChannelSelector(yChannelSelector) 474 , fScale(scale) { 475 this->addCoordTransform(&fDisplacementTransform); 476 this->addTextureSampler(&fDisplacementSampler); 477 this->addCoordTransform(&fColorTransform); 478 this->addTextureSampler(&fColorSampler); 479} 480 481GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& that) 482 : INHERITED(kGrDisplacementMapEffect_ClassID, 483 OptimizationFlags(that.fColorSampler.proxy()->config())) 484 , fDisplacementTransform(that.fDisplacementTransform) 485 , fDisplacementSampler(that.fDisplacementSampler) 486 , fColorTransform(that.fColorTransform) 487 , fDomain(that.fDomain) 488 , fColorSampler(that.fColorSampler) 489 , fXChannelSelector(that.fXChannelSelector) 490 , fYChannelSelector(that.fYChannelSelector) 491 , fScale(that.fScale) { 492 this->addCoordTransform(&fDisplacementTransform); 493 this->addTextureSampler(&fDisplacementSampler); 494 this->addCoordTransform(&fColorTransform); 495 this->addTextureSampler(&fColorSampler); 496} 497 498GrDisplacementMapEffect::~GrDisplacementMapEffect() {} 499 500std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::clone() const { 501 return std::unique_ptr<GrFragmentProcessor>(new GrDisplacementMapEffect(*this)); 502} 503 504bool GrDisplacementMapEffect::onIsEqual(const GrFragmentProcessor& sBase) const { 505 const GrDisplacementMapEffect& s = sBase.cast<GrDisplacementMapEffect>(); 506 return fXChannelSelector == s.fXChannelSelector && 507 fYChannelSelector == s.fYChannelSelector && 508 fScale == s.fScale; 509} 510 511/////////////////////////////////////////////////////////////////////////////// 512 513GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrDisplacementMapEffect); 514 515#if GR_TEST_UTILS 516std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::TestCreate(GrProcessorTestData* d) { 517 int texIdxDispl = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 518 GrProcessorUnitTest::kAlphaTextureIdx; 519 int texIdxColor = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 520 GrProcessorUnitTest::kAlphaTextureIdx; 521 sk_sp<GrTextureProxy> dispProxy = d->textureProxy(texIdxDispl); 522 sk_sp<GrTextureProxy> colorProxy = d->textureProxy(texIdxColor); 523 static const int kMaxComponent = 4; 524 SkDisplacementMapEffect::ChannelSelectorType xChannelSelector = 525 static_cast<SkDisplacementMapEffect::ChannelSelectorType>( 526 d->fRandom->nextRangeU(1, kMaxComponent)); 527 SkDisplacementMapEffect::ChannelSelectorType yChannelSelector = 528 static_cast<SkDisplacementMapEffect::ChannelSelectorType>( 529 d->fRandom->nextRangeU(1, kMaxComponent)); 530 SkVector scale = SkVector::Make(d->fRandom->nextRangeScalar(0, 100.0f), 531 d->fRandom->nextRangeScalar(0, 100.0f)); 532 SkISize colorDimensions; 533 colorDimensions.fWidth = d->fRandom->nextRangeU(0, colorProxy->width()); 534 colorDimensions.fHeight = d->fRandom->nextRangeU(0, colorProxy->height()); 535 return GrDisplacementMapEffect::Make(xChannelSelector, yChannelSelector, scale, 536 std::move(dispProxy), SkMatrix::I(), 537 std::move(colorProxy), colorDimensions); 538} 539 540#endif 541 542/////////////////////////////////////////////////////////////////////////////// 543 544void GrGLDisplacementMapEffect::emitCode(EmitArgs& args) { 545 const GrDisplacementMapEffect& displacementMap = args.fFp.cast<GrDisplacementMapEffect>(); 546 const GrTextureDomain& domain = displacementMap.domain(); 547 548 fScaleUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf2_GrSLType, "Scale"); 549 const char* scaleUni = args.fUniformHandler->getUniformCStr(fScaleUni); 550 const char* dColor = "dColor"; 551 const char* cCoords = "cCoords"; 552 const char* nearZero = "1e-6"; // Since 6.10352e-5 is the smallest half float, use 553 // a number smaller than that to approximate 0, but 554 // leave room for 32-bit float GPU rounding errors. 555 556 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 557 fragBuilder->codeAppendf("\t\thalf4 %s = ", dColor); 558 fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(), 559 args.fTransformedCoords[0].getType()); 560 fragBuilder->codeAppend(";\n"); 561 562 // Unpremultiply the displacement 563 fragBuilder->codeAppendf( 564 "\t\t%s.rgb = (%s.a < %s) ? half3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);", 565 dColor, dColor, nearZero, dColor, dColor); 566 SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[1]); 567 fragBuilder->codeAppendf("\t\tfloat2 %s = %s + %s*(%s.", 568 cCoords, coords2D.c_str(), scaleUni, dColor); 569 570 switch (displacementMap.xChannelSelector()) { 571 case SkDisplacementMapEffect::kR_ChannelSelectorType: 572 fragBuilder->codeAppend("r"); 573 break; 574 case SkDisplacementMapEffect::kG_ChannelSelectorType: 575 fragBuilder->codeAppend("g"); 576 break; 577 case SkDisplacementMapEffect::kB_ChannelSelectorType: 578 fragBuilder->codeAppend("b"); 579 break; 580 case SkDisplacementMapEffect::kA_ChannelSelectorType: 581 fragBuilder->codeAppend("a"); 582 break; 583 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: 584 default: 585 SkDEBUGFAIL("Unknown X channel selector"); 586 } 587 588 switch (displacementMap.yChannelSelector()) { 589 case SkDisplacementMapEffect::kR_ChannelSelectorType: 590 fragBuilder->codeAppend("r"); 591 break; 592 case SkDisplacementMapEffect::kG_ChannelSelectorType: 593 fragBuilder->codeAppend("g"); 594 break; 595 case SkDisplacementMapEffect::kB_ChannelSelectorType: 596 fragBuilder->codeAppend("b"); 597 break; 598 case SkDisplacementMapEffect::kA_ChannelSelectorType: 599 fragBuilder->codeAppend("a"); 600 break; 601 case SkDisplacementMapEffect::kUnknown_ChannelSelectorType: 602 default: 603 SkDEBUGFAIL("Unknown Y channel selector"); 604 } 605 fragBuilder->codeAppend("-half2(0.5));\t\t"); 606 607 fGLDomain.sampleTexture(fragBuilder, 608 args.fUniformHandler, 609 args.fShaderCaps, 610 domain, 611 args.fOutputColor, 612 SkString(cCoords), 613 args.fTexSamplers[1]); 614 fragBuilder->codeAppend(";\n"); 615} 616 617void GrGLDisplacementMapEffect::onSetData(const GrGLSLProgramDataManager& pdman, 618 const GrFragmentProcessor& proc) { 619 const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>(); 620 GrSurfaceProxy* proxy = displacementMap.textureSampler(1).proxy(); 621 GrTexture* colorTex = proxy->priv().peekTexture(); 622 623 SkScalar scaleX = displacementMap.scale().fX / colorTex->width(); 624 SkScalar scaleY = displacementMap.scale().fY / colorTex->height(); 625 pdman.set2f(fScaleUni, SkScalarToFloat(scaleX), 626 proxy->origin() == kTopLeft_GrSurfaceOrigin ? 627 SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY)); 628 fGLDomain.setData(pdman, displacementMap.domain(), proxy); 629} 630 631void GrGLDisplacementMapEffect::GenKey(const GrProcessor& proc, 632 const GrShaderCaps&, GrProcessorKeyBuilder* b) { 633 const GrDisplacementMapEffect& displacementMap = proc.cast<GrDisplacementMapEffect>(); 634 635 uint32_t xKey = displacementMap.xChannelSelector(); 636 uint32_t yKey = displacementMap.yChannelSelector() << kChannelSelectorKeyBits; 637 638 b->add32(xKey | yKey); 639} 640#endif 641