| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2012 The Android Open Source Project | |
| 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 "SkBlendImageFilter.h" | |
| 9 #include "SkCanvas.h" | |
| 10 #include "SkColorPriv.h" | |
| 11 #include "SkFlattenableBuffers.h" | |
| 12 #if SK_SUPPORT_GPU | |
| 13 #include "GrContext.h" | |
| 14 #include "gl/GrGLEffect.h" | |
| 15 #include "gl/GrGLEffectMatrix.h" | |
| 16 #include "GrTBackendEffectFactory.h" | |
| 17 #include "SkImageFilterUtils.h" | |
| 18 #endif | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 SkXfermode::Mode modeToXfermode(SkBlendImageFilter::Mode mode) { | |
| 23 switch (mode) { | |
| 24 case SkBlendImageFilter::kNormal_Mode: | |
| 25 return SkXfermode::kSrcOver_Mode; | |
| 26 case SkBlendImageFilter::kMultiply_Mode: | |
| 27 return SkXfermode::kMultiply_Mode; | |
| 28 case SkBlendImageFilter::kScreen_Mode: | |
| 29 return SkXfermode::kScreen_Mode; | |
| 30 case SkBlendImageFilter::kDarken_Mode: | |
| 31 return SkXfermode::kDarken_Mode; | |
| 32 case SkBlendImageFilter::kLighten_Mode: | |
| 33 return SkXfermode::kLighten_Mode; | |
| 34 } | |
| 35 SkASSERT(0); | |
| 36 return SkXfermode::kSrcOver_Mode; | |
| 37 } | |
| 38 | |
| 39 }; | |
| 40 | |
| 41 /////////////////////////////////////////////////////////////////////////////// | |
| 42 | |
| 43 SkBlendImageFilter::SkBlendImageFilter(SkBlendImageFilter::Mode mode, SkImageFil
ter* background, SkImageFilter* foreground) | |
| 44 : INHERITED(background, foreground), fMode(mode) | |
| 45 { | |
| 46 } | |
| 47 | |
| 48 SkBlendImageFilter::~SkBlendImageFilter() { | |
| 49 } | |
| 50 | |
| 51 SkBlendImageFilter::SkBlendImageFilter(SkFlattenableReadBuffer& buffer) | |
| 52 : INHERITED(buffer) | |
| 53 { | |
| 54 fMode = (SkBlendImageFilter::Mode) buffer.readInt(); | |
| 55 } | |
| 56 | |
| 57 void SkBlendImageFilter::flatten(SkFlattenableWriteBuffer& buffer) const { | |
| 58 this->INHERITED::flatten(buffer); | |
| 59 buffer.writeInt((int) fMode); | |
| 60 } | |
| 61 | |
| 62 bool SkBlendImageFilter::onFilterImage(Proxy* proxy, | |
| 63 const SkBitmap& src, | |
| 64 const SkMatrix& ctm, | |
| 65 SkBitmap* dst, | |
| 66 SkIPoint* offset) { | |
| 67 SkBitmap background, foreground = src; | |
| 68 SkImageFilter* backgroundInput = getBackgroundInput(); | |
| 69 SkImageFilter* foregroundInput = getForegroundInput(); | |
| 70 SkASSERT(NULL != backgroundInput); | |
| 71 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); | |
| 72 if (!backgroundInput->filterImage(proxy, src, ctm, &background, &backgroundO
ffset)) { | |
| 73 return false; | |
| 74 } | |
| 75 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); | |
| 76 if (foregroundInput && | |
| 77 !foregroundInput->filterImage(proxy, src, ctm, &foreground, &foregroundO
ffset)) { | |
| 78 return false; | |
| 79 } | |
| 80 SkAutoLockPixels alp_foreground(foreground), alp_background(background); | |
| 81 if (!foreground.getPixels() || !background.getPixels()) { | |
| 82 return false; | |
| 83 } | |
| 84 dst->setConfig(background.config(), background.width(), background.height())
; | |
| 85 dst->allocPixels(); | |
| 86 SkCanvas canvas(*dst); | |
| 87 SkPaint paint; | |
| 88 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
| 89 canvas.drawBitmap(background, SkIntToScalar(backgroundOffset.fX), | |
| 90 SkIntToScalar(backgroundOffset.fY), &paint); | |
| 91 paint.setXfermodeMode(modeToXfermode(fMode)); | |
| 92 canvas.drawBitmap(foreground, SkIntToScalar(foregroundOffset.fX), | |
| 93 SkIntToScalar(foregroundOffset.fY), &paint); | |
| 94 return true; | |
| 95 } | |
| 96 | |
| 97 /////////////////////////////////////////////////////////////////////////////// | |
| 98 | |
| 99 #if SK_SUPPORT_GPU | |
| 100 class GrGLBlendEffect : public GrGLEffect { | |
| 101 public: | |
| 102 GrGLBlendEffect(const GrBackendEffectFactory&, const GrDrawEffect&); | |
| 103 virtual ~GrGLBlendEffect(); | |
| 104 | |
| 105 virtual void emitCode(GrGLShaderBuilder*, | |
| 106 const GrDrawEffect&, | |
| 107 EffectKey, | |
| 108 const char* outputColor, | |
| 109 const char* inputColor, | |
| 110 const TextureSamplerArray&) SK_OVERRIDE; | |
| 111 | |
| 112 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); | |
| 113 | |
| 114 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER
RIDE; | |
| 115 | |
| 116 private: | |
| 117 static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; | |
| 118 | |
| 119 SkBlendImageFilter::Mode fMode; | |
| 120 GrGLEffectMatrix fForegroundEffectMatrix; | |
| 121 GrGLEffectMatrix fBackgroundEffectMatrix; | |
| 122 | |
| 123 typedef GrGLEffect INHERITED; | |
| 124 }; | |
| 125 | |
| 126 /////////////////////////////////////////////////////////////////////////////// | |
| 127 | |
| 128 class GrBlendEffect : public GrEffect { | |
| 129 public: | |
| 130 static GrEffectRef* Create(SkBlendImageFilter::Mode mode, | |
| 131 GrTexture* foreground, | |
| 132 const SkIPoint& foregroundOffset, | |
| 133 GrTexture* background, | |
| 134 const SkIPoint& backgroundOffset) { | |
| 135 AutoEffectUnref effect(SkNEW_ARGS(GrBlendEffect, (mode, foreground, fore
groundOffset, | |
| 136 background, background
Offset))); | |
| 137 return CreateEffectRef(effect); | |
| 138 } | |
| 139 | |
| 140 virtual ~GrBlendEffect(); | |
| 141 | |
| 142 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; | |
| 143 SkBlendImageFilter::Mode mode() const { return fMode; } | |
| 144 const SkMatrix& foregroundMatrix() const { return fForegroundMatrix; } | |
| 145 const SkMatrix& backgroundMatrix() const { return fBackgroundMatrix; } | |
| 146 | |
| 147 typedef GrGLBlendEffect GLEffect; | |
| 148 static const char* Name() { return "Blend"; } | |
| 149 | |
| 150 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags
) const SK_OVERRIDE; | |
| 151 | |
| 152 private: | |
| 153 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; | |
| 154 | |
| 155 GrBlendEffect(SkBlendImageFilter::Mode mode, | |
| 156 GrTexture* foreground, const SkIPoint& foregroundOffset, | |
| 157 GrTexture* background, const SkIPoint& backgroundOffset); | |
| 158 GrTextureAccess fForegroundAccess; | |
| 159 SkMatrix fForegroundMatrix; | |
| 160 GrTextureAccess fBackgroundAccess; | |
| 161 SkMatrix fBackgroundMatrix; | |
| 162 SkBlendImageFilter::Mode fMode; | |
| 163 | |
| 164 typedef GrEffect INHERITED; | |
| 165 }; | |
| 166 | |
| 167 bool SkBlendImageFilter::filterImageGPU(Proxy* proxy, const SkBitmap& src, SkBit
map* result, | |
| 168 SkIPoint* offset) { | |
| 169 SkBitmap backgroundBM; | |
| 170 SkIPoint backgroundOffset = SkIPoint::Make(0, 0); | |
| 171 if (!SkImageFilterUtils::GetInputResultGPU(getBackgroundInput(), proxy, src,
&backgroundBM, | |
| 172 &backgroundOffset)) { | |
| 173 return false; | |
| 174 } | |
| 175 GrTexture* background = backgroundBM.getTexture(); | |
| 176 SkBitmap foregroundBM; | |
| 177 SkIPoint foregroundOffset = SkIPoint::Make(0, 0); | |
| 178 if (!SkImageFilterUtils::GetInputResultGPU(getForegroundInput(), proxy, src,
&foregroundBM, | |
| 179 &foregroundOffset)) { | |
| 180 return false; | |
| 181 } | |
| 182 GrTexture* foreground = foregroundBM.getTexture(); | |
| 183 GrContext* context = foreground->getContext(); | |
| 184 | |
| 185 GrTextureDesc desc; | |
| 186 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; | |
| 187 desc.fWidth = src.width(); | |
| 188 desc.fHeight = src.height(); | |
| 189 desc.fConfig = kSkia8888_GrPixelConfig; | |
| 190 | |
| 191 GrAutoScratchTexture ast(context, desc); | |
| 192 SkAutoTUnref<GrTexture> dst(ast.detach()); | |
| 193 | |
| 194 GrContext::AutoRenderTarget art(context, dst->asRenderTarget()); | |
| 195 | |
| 196 GrPaint paint; | |
| 197 paint.addColorEffect(GrBlendEffect::Create(fMode, | |
| 198 foreground, foregroundOffset, | |
| 199 background, backgroundOffset))->u
nref(); | |
| 200 SkRect srcRect; | |
| 201 src.getBounds(&srcRect); | |
| 202 context->drawRect(paint, srcRect); | |
| 203 return SkImageFilterUtils::WrapTexture(dst, src.width(), src.height(), resul
t); | |
| 204 } | |
| 205 | |
| 206 /////////////////////////////////////////////////////////////////////////////// | |
| 207 | |
| 208 GrBlendEffect::GrBlendEffect(SkBlendImageFilter::Mode mode, | |
| 209 GrTexture* foreground, | |
| 210 const SkIPoint& foregroundOffset, | |
| 211 GrTexture* background, | |
| 212 const SkIPoint& backgroundOffset) | |
| 213 : fForegroundAccess(foreground) | |
| 214 , fBackgroundAccess(background) | |
| 215 , fMode(mode) { | |
| 216 this->addTextureAccess(&fForegroundAccess); | |
| 217 this->addTextureAccess(&fBackgroundAccess); | |
| 218 fForegroundMatrix = GrEffect::MakeDivByTextureWHMatrix(foreground); | |
| 219 fForegroundMatrix.preTranslate(SkIntToScalar(-foregroundOffset.fX), | |
| 220 SkIntToScalar(-foregroundOffset.fY)); | |
| 221 fBackgroundMatrix = GrEffect::MakeDivByTextureWHMatrix(background); | |
| 222 fBackgroundMatrix.preTranslate(SkIntToScalar(-backgroundOffset.fX), | |
| 223 SkIntToScalar(-backgroundOffset.fY)); | |
| 224 } | |
| 225 | |
| 226 GrBlendEffect::~GrBlendEffect() { | |
| 227 } | |
| 228 | |
| 229 bool GrBlendEffect::onIsEqual(const GrEffect& sBase) const { | |
| 230 const GrBlendEffect& s = CastEffect<GrBlendEffect>(sBase); | |
| 231 return fForegroundAccess.getTexture() == s.fForegroundAccess.getTexture() && | |
| 232 fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture() && | |
| 233 fMode == s.fMode; | |
| 234 } | |
| 235 | |
| 236 const GrBackendEffectFactory& GrBlendEffect::getFactory() const { | |
| 237 return GrTBackendEffectFactory<GrBlendEffect>::getInstance(); | |
| 238 } | |
| 239 | |
| 240 void GrBlendEffect::getConstantColorComponents(GrColor* color, uint32_t* validFl
ags) const { | |
| 241 // The output alpha is always 1 - (1 - FGa) * (1 - BGa). So if either FGa or
BGa is known to | |
| 242 // be one then the output alpha is one. (This effect ignores its input. We s
hould have a way to | |
| 243 // communicate this.) | |
| 244 if (GrPixelConfigIsOpaque(fForegroundAccess.getTexture()->config()) || | |
| 245 GrPixelConfigIsOpaque(fBackgroundAccess.getTexture()->config())) { | |
| 246 *validFlags = kA_GrColorComponentFlag; | |
| 247 *color = GrColorPackRGBA(0, 0, 0, 0xff); | |
| 248 } else { | |
| 249 *validFlags = 0; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 /////////////////////////////////////////////////////////////////////////////// | |
| 254 | |
| 255 GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory, | |
| 256 const GrDrawEffect& drawEffect) | |
| 257 : INHERITED(factory) | |
| 258 , fMode(drawEffect.castEffect<GrBlendEffect>().mode()) | |
| 259 , fForegroundEffectMatrix(kCoordsType) | |
| 260 , fBackgroundEffectMatrix(kCoordsType) { | |
| 261 } | |
| 262 | |
| 263 GrGLBlendEffect::~GrGLBlendEffect() { | |
| 264 } | |
| 265 | |
| 266 void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder, | |
| 267 const GrDrawEffect&, | |
| 268 EffectKey key, | |
| 269 const char* outputColor, | |
| 270 const char* inputColor, | |
| 271 const TextureSamplerArray& samplers) { | |
| 272 const char* fgCoords; | |
| 273 const char* bgCoords; | |
| 274 GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCo
ords, NULL, "FG"); | |
| 275 GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCo
ords, NULL, "BG"); | |
| 276 | |
| 277 const char* bgColor = "bgColor"; | |
| 278 const char* fgColor = "fgColor"; | |
| 279 | |
| 280 builder->fsCodeAppendf("\t\tvec4 %s = ", fgColor); | |
| 281 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
| 282 samplers[0], | |
| 283 fgCoords, | |
| 284 fgCoordsType); | |
| 285 builder->fsCodeAppend(";\n"); | |
| 286 | |
| 287 builder->fsCodeAppendf("\t\tvec4 %s = ", bgColor); | |
| 288 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, | |
| 289 samplers[1], | |
| 290 bgCoords, | |
| 291 bgCoordsType); | |
| 292 builder->fsCodeAppendf(";\n"); | |
| 293 | |
| 294 builder->fsCodeAppendf("\t\t%s.a = 1.0 - (1.0 - %s.a) * (1.0 - %s.b);\n", ou
tputColor, bgColor, fgColor); | |
| 295 switch (fMode) { | |
| 296 case SkBlendImageFilter::kNormal_Mode: | |
| 297 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + %s.rgb;\n",
outputColor, fgColor, bgColor, fgColor); | |
| 298 break; | |
| 299 case SkBlendImageFilter::kMultiply_Mode: | |
| 300 builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + (1.0 - %s.a
) * %s.rgb + %s.rgb * %s.rgb;\n", outputColor, fgColor, bgColor, bgColor, fgColo
r, fgColor, bgColor); | |
| 301 break; | |
| 302 case SkBlendImageFilter::kScreen_Mode: | |
| 303 builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - %s.rgb * %s.rgb;\
n", outputColor, bgColor, fgColor, fgColor, bgColor); | |
| 304 break; | |
| 305 case SkBlendImageFilter::kDarken_Mode: | |
| 306 builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb,
(1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bg
Color, fgColor, bgColor); | |
| 307 break; | |
| 308 case SkBlendImageFilter::kLighten_Mode: | |
| 309 builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb,
(1.0 - %s.a) * %s.rgb + %s.rgb);\n", outputColor, fgColor, bgColor, fgColor, bg
Color, fgColor, bgColor); | |
| 310 break; | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect
& drawEffect) { | |
| 315 const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>(); | |
| 316 GrTexture* fgTex = blend.texture(0); | |
| 317 GrTexture* bgTex = blend.texture(1); | |
| 318 fForegroundEffectMatrix.setData(uman, | |
| 319 blend.foregroundMatrix(), | |
| 320 drawEffect, | |
| 321 fgTex); | |
| 322 fBackgroundEffectMatrix.setData(uman, | |
| 323 blend.backgroundMatrix(), | |
| 324 drawEffect, | |
| 325 bgTex); | |
| 326 | |
| 327 } | |
| 328 | |
| 329 GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrDrawEffect& drawEffect, co
nst GrGLCaps&) { | |
| 330 const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>(); | |
| 331 | |
| 332 GrTexture* fgTex = blend.texture(0); | |
| 333 GrTexture* bgTex = blend.texture(1); | |
| 334 | |
| 335 EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri
x(fgTex), | |
| 336 drawEffect, | |
| 337 kCoordsType, | |
| 338 fgTex); | |
| 339 | |
| 340 EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatri
x(bgTex), | |
| 341 drawEffect, | |
| 342 kCoordsType, | |
| 343 bgTex); | |
| 344 bgKey <<= GrGLEffectMatrix::kKeyBits; | |
| 345 EffectKey modeKey = blend.mode() << (2 * GrGLEffectMatrix::kKeyBits); | |
| 346 | |
| 347 return modeKey | bgKey | fgKey; | |
| 348 } | |
| 349 #endif | |
| OLD | NEW |