Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/effects/SkMatrixConvolutionImageFilter.cpp

Issue 379253003: Initial change to move 2D kernel to its own file (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: small cleanup Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2012 The Android Open Source Project 2 * Copyright 2012 The Android Open Source Project
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkMatrixConvolutionImageFilter.h" 8 #include "SkMatrixConvolutionImageFilter.h"
9 #include "SkBitmap.h" 9 #include "SkBitmap.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
11 #include "SkReadBuffer.h" 11 #include "SkReadBuffer.h"
12 #include "SkWriteBuffer.h" 12 #include "SkWriteBuffer.h"
13 #include "SkRect.h" 13 #include "SkRect.h"
14 #include "SkUnPreMultiply.h" 14 #include "SkUnPreMultiply.h"
15 15
16 #if SK_SUPPORT_GPU 16 #if SK_SUPPORT_GPU
17 #include "gl/GrGLEffect.h" 17 #include "effects/GrMatrixConvolutionEffect.h"
18 #include "gl/GrGLShaderBuilder.h"
19 #include "effects/GrSingleTextureEffect.h"
20 #include "GrTBackendEffectFactory.h"
21 #include "GrTexture.h"
22 #include "SkMatrix.h"
23 #endif 18 #endif
24 19
25 static bool tile_mode_is_valid(SkMatrixConvolutionImageFilter::TileMode tileMode ) { 20 static bool tile_mode_is_valid(SkMatrixConvolutionImageFilter::TileMode tileMode ) {
26 switch (tileMode) { 21 switch (tileMode) {
27 case SkMatrixConvolutionImageFilter::kClamp_TileMode: 22 case SkMatrixConvolutionImageFilter::kClamp_TileMode:
28 case SkMatrixConvolutionImageFilter::kRepeat_TileMode: 23 case SkMatrixConvolutionImageFilter::kRepeat_TileMode:
29 case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode: 24 case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode:
30 return true; 25 return true;
31 default: 26 default:
32 break; 27 break;
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
317 bounds.offset(-fKernelOffset); 312 bounds.offset(-fKernelOffset);
318 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { 313 if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) {
319 return false; 314 return false;
320 } 315 }
321 *dst = bounds; 316 *dst = bounds;
322 return true; 317 return true;
323 } 318 }
324 319
325 #if SK_SUPPORT_GPU 320 #if SK_SUPPORT_GPU
326 321
327 /////////////////////////////////////////////////////////////////////////////// 322 static GrMatrixConvolutionEffect::TileMode convert_tilemodes(
328 323 SkMatrixConvolutionImageFilter::TileMode tileMode) {
329 class GrGLMatrixConvolutionEffect; 324 GR_STATIC_ASSERT(static_cast<int>(SkMatrixConvolutionImageFilter::kClamp_Til eMode) ==
330 325 static_cast<int>(GrMatrixConvolutionEffect::kClamp_TileMode ));
331 class GrMatrixConvolutionEffect : public GrSingleTextureEffect { 326 GR_STATIC_ASSERT(static_cast<int>(SkMatrixConvolutionImageFilter::kRepeat_Ti leMode) ==
332 public: 327 static_cast<int>(GrMatrixConvolutionEffect::kRepeat_TileMod e));
333 typedef SkMatrixConvolutionImageFilter::TileMode TileMode; 328 GR_STATIC_ASSERT(static_cast<int>(SkMatrixConvolutionImageFilter::kClampToBl ack_TileMode) ==
334 static GrEffect* Create(GrTexture* texture, 329 static_cast<int>(GrMatrixConvolutionEffect::kClampToBlack_T ileMode));
335 const SkIRect& bounds, 330 GR_STATIC_ASSERT(static_cast<int>(SkMatrixConvolutionImageFilter::kMax_TileM ode) ==
336 const SkISize& kernelSize, 331 static_cast<int>(GrMatrixConvolutionEffect::kMax_TileMode)) ;
337 const SkScalar* kernel, 332 return static_cast<GrMatrixConvolutionEffect::TileMode>(tileMode);
338 SkScalar gain,
339 SkScalar bias,
340 const SkIPoint& kernelOffset,
341 TileMode tileMode,
342 bool convolveAlpha) {
343 return SkNEW_ARGS(GrMatrixConvolutionEffect, (texture,
344 bounds,
345 kernelSize,
346 kernel,
347 gain,
348 bias,
349 kernelOffset,
350 tileMode,
351 convolveAlpha));
352 }
353 virtual ~GrMatrixConvolutionEffect();
354
355 virtual void getConstantColorComponents(GrColor* color,
356 uint32_t* validFlags) const SK_OVERR IDE {
357 // TODO: Try to do better?
358 *validFlags = 0;
359 }
360
361 static const char* Name() { return "MatrixConvolution"; }
362 const SkIRect& bounds() const { return fBounds; }
363 const SkISize& kernelSize() const { return fKernelSize; }
364 const float* kernelOffset() const { return fKernelOffset; }
365 const float* kernel() const { return fKernel; }
366 float gain() const { return fGain; }
367 float bias() const { return fBias; }
368 TileMode tileMode() const { return fTileMode; }
369 bool convolveAlpha() const { return fConvolveAlpha; }
370
371 typedef GrGLMatrixConvolutionEffect GLEffect;
372
373 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
374
375 private:
376 GrMatrixConvolutionEffect(GrTexture*,
377 const SkIRect& bounds,
378 const SkISize& kernelSize,
379 const SkScalar* kernel,
380 SkScalar gain,
381 SkScalar bias,
382 const SkIPoint& kernelOffset,
383 TileMode tileMode,
384 bool convolveAlpha);
385
386 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
387
388 SkIRect fBounds;
389 SkISize fKernelSize;
390 float *fKernel;
391 float fGain;
392 float fBias;
393 float fKernelOffset[2];
394 TileMode fTileMode;
395 bool fConvolveAlpha;
396
397 GR_DECLARE_EFFECT_TEST;
398
399 typedef GrSingleTextureEffect INHERITED;
400 };
401
402 class GrGLMatrixConvolutionEffect : public GrGLEffect {
403 public:
404 GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory,
405 const GrDrawEffect& effect);
406 virtual void emitCode(GrGLShaderBuilder*,
407 const GrDrawEffect&,
408 const GrEffectKey&,
409 const char* outputColor,
410 const char* inputColor,
411 const TransformedCoordsArray&,
412 const TextureSamplerArray&) SK_OVERRIDE;
413
414 static inline void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyB uilder*);
415
416 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER RIDE;
417
418 private:
419 typedef GrGLUniformManager::UniformHandle UniformHandle;
420 typedef SkMatrixConvolutionImageFilter::TileMode TileMode;
421 SkISize fKernelSize;
422 TileMode fTileMode;
423 bool fConvolveAlpha;
424
425 UniformHandle fBoundsUni;
426 UniformHandle fKernelUni;
427 UniformHandle fImageIncrementUni;
428 UniformHandle fKernelOffsetUni;
429 UniformHandle fGainUni;
430 UniformHandle fBiasUni;
431
432 typedef GrGLEffect INHERITED;
433 };
434
435 GrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrBackendEffectFa ctory& factory,
436 const GrDrawEffect& dra wEffect)
437 : INHERITED(factory) {
438 const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvoluti onEffect>();
439 fKernelSize = m.kernelSize();
440 fTileMode = m.tileMode();
441 fConvolveAlpha = m.convolveAlpha();
442 }
443
444 static void appendTextureLookup(GrGLShaderBuilder* builder,
445 const GrGLShaderBuilder::TextureSampler& sampler ,
446 const char* coord,
447 const char* bounds,
448 SkMatrixConvolutionImageFilter::TileMode tileMod e) {
449 SkString clampedCoord;
450 switch (tileMode) {
451 case SkMatrixConvolutionImageFilter::kClamp_TileMode:
452 clampedCoord.printf("clamp(%s, %s.xy, %s.zw)", coord, bounds, bounds );
453 coord = clampedCoord.c_str();
454 break;
455 case SkMatrixConvolutionImageFilter::kRepeat_TileMode:
456 clampedCoord.printf("mod(%s - %s.xy, %s.zw - %s.xy) + %s.xy", coord, bounds, bounds, bounds, bounds);
457 coord = clampedCoord.c_str();
458 break;
459 case SkMatrixConvolutionImageFilter::kClampToBlack_TileMode:
460 builder->fsCodeAppendf("clamp(%s, %s.xy, %s.zw) != %s ? vec4(0, 0, 0 , 0) : ", coord, bounds, bounds, coord);
461 break;
462 }
463 builder->fsAppendTextureLookup(sampler, coord);
464 }
465
466 void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
467 const GrDrawEffect&,
468 const GrEffectKey& key,
469 const char* outputColor,
470 const char* inputColor,
471 const TransformedCoordsArray& coords,
472 const TextureSamplerArray& samplers) {
473 sk_ignore_unused_variable(inputColor);
474 SkString coords2D = builder->ensureFSCoords2D(coords, 0);
475 fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
476 kVec4f_GrSLType, "Bounds");
477 fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibi lity,
478 kVec2f_GrSLType, "ImageIncrement");
479 fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibilit y,
480 kFloat_GrSLType,
481 "Kernel",
482 fKernelSize.width() * fKernelSize.h eight());
483 fKernelOffsetUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibili ty,
484 kVec2f_GrSLType, "KernelOffset");
485 fGainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
486 kFloat_GrSLType, "Gain");
487 fBiasUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
488 kFloat_GrSLType, "Bias");
489
490 const char* bounds = builder->getUniformCStr(fBoundsUni);
491 const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni);
492 const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
493 const char* kernel = builder->getUniformCStr(fKernelUni);
494 const char* gain = builder->getUniformCStr(fGainUni);
495 const char* bias = builder->getUniformCStr(fBiasUni);
496 int kWidth = fKernelSize.width();
497 int kHeight = fKernelSize.height();
498
499 builder->fsCodeAppend("\t\tvec4 sum = vec4(0, 0, 0, 0);\n");
500 builder->fsCodeAppendf("\t\tvec2 coord = %s - %s * %s;\n", coords2D.c_str(), kernelOffset, imgInc);
501 builder->fsCodeAppendf("\t\tfor (int y = 0; y < %d; y++) {\n", kHeight);
502 builder->fsCodeAppendf("\t\t\tfor (int x = 0; x < %d; x++) {\n", kWidth);
503 builder->fsCodeAppendf("\t\t\t\tfloat k = %s[y * %d + x];\n", kernel, kWidth );
504 builder->fsCodeAppendf("\t\t\t\tvec2 coord2 = coord + vec2(x, y) * %s;\n", i mgInc);
505 builder->fsCodeAppend("\t\t\t\tvec4 c = ");
506 appendTextureLookup(builder, samplers[0], "coord2", bounds, fTileMode);
507 builder->fsCodeAppend(";\n");
508 if (!fConvolveAlpha) {
509 builder->fsCodeAppend("\t\t\t\tc.rgb /= c.a;\n");
510 }
511 builder->fsCodeAppend("\t\t\t\tsum += c * k;\n");
512 builder->fsCodeAppend("\t\t\t}\n");
513 builder->fsCodeAppend("\t\t}\n");
514 if (fConvolveAlpha) {
515 builder->fsCodeAppendf("\t\t%s = sum * %s + %s;\n", outputColor, gain, b ias);
516 builder->fsCodeAppendf("\t\t%s.rgb = clamp(%s.rgb, 0.0, %s.a);\n",
517 outputColor, outputColor, outputColor);
518 } else {
519 builder->fsCodeAppend("\t\tvec4 c = ");
520 appendTextureLookup(builder, samplers[0], coords2D.c_str(), bounds, fTil eMode);
521 builder->fsCodeAppend(";\n");
522 builder->fsCodeAppendf("\t\t%s.a = c.a;\n", outputColor);
523 builder->fsCodeAppendf("\t\t%s.rgb = sum.rgb * %s + %s;\n", outputColor, gain, bias);
524 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor );
525 }
526 }
527
528 namespace {
529
530 int encodeXY(int x, int y) {
531 SkASSERT(x >= 1 && y >= 1 && x * y <= 32);
532 if (y < x)
533 return 0x40 | encodeXY(y, x);
534 else
535 return (0x40 >> x) | (y - x);
536 }
537
538 };
539
540 void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
541 const GrGLCaps&, GrEffectKeyBuilder* b) {
542 const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvoluti onEffect>();
543 uint32_t key = encodeXY(m.kernelSize().width(), m.kernelSize().height());
544 key |= m.tileMode() << 7;
545 key |= m.convolveAlpha() ? 1 << 9 : 0;
546 b->add32(key);
547 }
548
549 void GrGLMatrixConvolutionEffect::setData(const GrGLUniformManager& uman,
550 const GrDrawEffect& drawEffect) {
551 const GrMatrixConvolutionEffect& conv = drawEffect.castEffect<GrMatrixConvol utionEffect>();
552 GrTexture& texture = *conv.texture(0);
553 // the code we generated was for a specific kernel size
554 SkASSERT(conv.kernelSize() == fKernelSize);
555 SkASSERT(conv.tileMode() == fTileMode);
556 float imageIncrement[2];
557 float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
558 imageIncrement[0] = 1.0f / texture.width();
559 imageIncrement[1] = ySign / texture.height();
560 uman.set2fv(fImageIncrementUni, 1, imageIncrement);
561 uman.set2fv(fKernelOffsetUni, 1, conv.kernelOffset());
562 uman.set1fv(fKernelUni, fKernelSize.width() * fKernelSize.height(), conv.ker nel());
563 uman.set1f(fGainUni, conv.gain());
564 uman.set1f(fBiasUni, conv.bias());
565 const SkIRect& bounds = conv.bounds();
566 float left = (float) bounds.left() / texture.width();
567 float top = (float) bounds.top() / texture.height();
568 float right = (float) bounds.right() / texture.width();
569 float bottom = (float) bounds.bottom() / texture.height();
570 if (texture.origin() == kBottomLeft_GrSurfaceOrigin) {
571 uman.set4f(fBoundsUni, left, 1.0f - bottom, right, 1.0f - top);
572 } else {
573 uman.set4f(fBoundsUni, left, top, right, bottom);
574 }
575 }
576
577 GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture,
578 const SkIRect& bounds,
579 const SkISize& kernelSize,
580 const SkScalar* kernel,
581 SkScalar gain,
582 SkScalar bias,
583 const SkIPoint& kernelOffse t,
584 TileMode tileMode,
585 bool convolveAlpha)
586 : INHERITED(texture, MakeDivByTextureWHMatrix(texture)),
587 fBounds(bounds),
588 fKernelSize(kernelSize),
589 fGain(SkScalarToFloat(gain)),
590 fBias(SkScalarToFloat(bias) / 255.0f),
591 fTileMode(tileMode),
592 fConvolveAlpha(convolveAlpha) {
593 fKernel = new float[kernelSize.width() * kernelSize.height()];
594 for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
595 fKernel[i] = SkScalarToFloat(kernel[i]);
596 }
597 fKernelOffset[0] = static_cast<float>(kernelOffset.x());
598 fKernelOffset[1] = static_cast<float>(kernelOffset.y());
599 this->setWillNotUseInputColor();
600 }
601
602 GrMatrixConvolutionEffect::~GrMatrixConvolutionEffect() {
603 delete[] fKernel;
604 }
605
606 const GrBackendEffectFactory& GrMatrixConvolutionEffect::getFactory() const {
607 return GrTBackendEffectFactory<GrMatrixConvolutionEffect>::getInstance();
608 }
609
610 bool GrMatrixConvolutionEffect::onIsEqual(const GrEffect& sBase) const {
611 const GrMatrixConvolutionEffect& s = CastEffect<GrMatrixConvolutionEffect>(s Base);
612 return this->texture(0) == s.texture(0) &&
613 fKernelSize == s.kernelSize() &&
614 !memcmp(fKernel, s.kernel(),
615 fKernelSize.width() * fKernelSize.height() * sizeof(float)) & &
616 fGain == s.gain() &&
617 fBias == s.bias() &&
618 fKernelOffset == s.kernelOffset() &&
619 fTileMode == s.tileMode() &&
620 fConvolveAlpha == s.convolveAlpha();
621 }
622
623 GR_DEFINE_EFFECT_TEST(GrMatrixConvolutionEffect);
624
625 // A little bit less than the minimum # uniforms required by DX9SM2 (32).
626 // Allows for a 5x5 kernel (or 25x1, for that matter).
627 #define MAX_KERNEL_SIZE 25
628
629 GrEffect* GrMatrixConvolutionEffect::TestCreate(SkRandom* random,
630 GrContext* context,
631 const GrDrawTargetCaps&,
632 GrTexture* textures[]) {
633 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
634 GrEffectUnitTest::kAlphaTextureIdx;
635 int width = random->nextRangeU(1, MAX_KERNEL_SIZE);
636 int height = random->nextRangeU(1, MAX_KERNEL_SIZE / width);
637 SkISize kernelSize = SkISize::Make(width, height);
638 SkAutoTDeleteArray<SkScalar> kernel(new SkScalar[width * height]);
639 for (int i = 0; i < width * height; i++) {
640 kernel.get()[i] = random->nextSScalar1();
641 }
642 SkScalar gain = random->nextSScalar1();
643 SkScalar bias = random->nextSScalar1();
644 SkIPoint kernelOffset = SkIPoint::Make(random->nextRangeU(0, kernelSize.widt h()),
645 random->nextRangeU(0, kernelSize.heig ht()));
646 SkIRect bounds = SkIRect::MakeXYWH(random->nextRangeU(0, textures[texIdx]->w idth()),
647 random->nextRangeU(0, textures[texIdx]->h eight()),
648 random->nextRangeU(0, textures[texIdx]->w idth()),
649 random->nextRangeU(0, textures[texIdx]->h eight()));
650 TileMode tileMode = static_cast<TileMode>(random->nextRangeU(0, 2));
651 bool convolveAlpha = random->nextBool();
652 return GrMatrixConvolutionEffect::Create(textures[texIdx],
653 bounds,
654 kernelSize,
655 kernel.get(),
656 gain,
657 bias,
658 kernelOffset,
659 tileMode,
660 convolveAlpha);
661 } 333 }
662 334
663 bool SkMatrixConvolutionImageFilter::asNewEffect(GrEffect** effect, 335 bool SkMatrixConvolutionImageFilter::asNewEffect(GrEffect** effect,
664 GrTexture* texture, 336 GrTexture* texture,
665 const SkMatrix&, 337 const SkMatrix&,
666 const SkIRect& bounds 338 const SkIRect& bounds
667 ) const { 339 ) const {
668 if (!effect) { 340 if (!effect) {
669 return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE; 341 return fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE;
670 } 342 }
671 SkASSERT(fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE); 343 SkASSERT(fKernelSize.width() * fKernelSize.height() <= MAX_KERNEL_SIZE);
672 *effect = GrMatrixConvolutionEffect::Create(texture, 344 *effect = GrMatrixConvolutionEffect::Create(texture,
673 bounds, 345 bounds,
674 fKernelSize, 346 fKernelSize,
675 fKernel, 347 fKernel,
676 fGain, 348 fGain,
677 fBias, 349 fBias,
678 fKernelOffset, 350 fKernelOffset,
679 fTileMode, 351 convert_tilemodes(fTileMode),
680 fConvolveAlpha); 352 fConvolveAlpha);
681 return true; 353 return true;
682 } 354 }
683
684 ///////////////////////////////////////////////////////////////////////////////
685
686 #endif 355 #endif
OLDNEW
« no previous file with comments | « include/effects/SkMatrixConvolutionImageFilter.h ('k') | src/gpu/effects/GrMatrixConvolutionEffect.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698