| Index: src/effects/SkMorphologyImageFilter.cpp
|
| diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
|
| index e895cacf13832605bf3558cc3e9a44a519987bc6..5e204183aba449b9491b14caae49d43cd1783798 100644
|
| --- a/src/effects/SkMorphologyImageFilter.cpp
|
| +++ b/src/effects/SkMorphologyImageFilter.cpp
|
| @@ -303,9 +303,16 @@ public:
|
| return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type));
|
| }
|
|
|
| + static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius,
|
| + MorphologyType type, float bounds[2]) {
|
| + return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type, bounds));
|
| + }
|
| +
|
| virtual ~GrMorphologyEffect();
|
|
|
| MorphologyType type() const { return fType; }
|
| + bool useRange() const { return fUseRange; }
|
| + const float* range() const { return fRange; }
|
|
|
| const char* name() const SK_OVERRIDE { return "Morphology"; }
|
|
|
| @@ -316,6 +323,8 @@ public:
|
| protected:
|
|
|
| MorphologyType fType;
|
| + bool fUseRange;
|
| + float fRange[2];
|
|
|
| private:
|
| bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
|
| @@ -323,6 +332,7 @@ private:
|
| void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
|
|
|
| GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType);
|
| + GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType, float bounds[2]);
|
|
|
| GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
|
|
|
| @@ -350,8 +360,11 @@ private:
|
| int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
|
|
|
| int fRadius;
|
| + Gr1DKernelEffect::Direction fDirection;
|
| + bool fUseRange;
|
| GrMorphologyEffect::MorphologyType fType;
|
| - GrGLProgramDataManager::UniformHandle fImageIncrementUni;
|
| + GrGLProgramDataManager::UniformHandle fPixelSizeUni;
|
| + GrGLProgramDataManager::UniformHandle fRangeUni;
|
|
|
| typedef GrGLFragmentProcessor INHERITED;
|
| };
|
| @@ -359,6 +372,8 @@ private:
|
| GrGLMorphologyEffect::GrGLMorphologyEffect(const GrProcessor& proc) {
|
| const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
|
| fRadius = m.radius();
|
| + fDirection = m.direction();
|
| + fUseRange = m.useRange();
|
| fType = m.type();
|
| }
|
|
|
| @@ -368,9 +383,14 @@ void GrGLMorphologyEffect::emitCode(GrGLFPBuilder* builder,
|
| const char* inputColor,
|
| const TransformedCoordsArray& coords,
|
| const TextureSamplerArray& samplers) {
|
| - fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| - kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| - "ImageIncrement");
|
| + fPixelSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| + kFloat_GrSLType, kDefault_GrSLPrecision,
|
| + "PixelSize");
|
| + const char* pixelSizeInc = builder->getUniformCStr(fPixelSizeUni);
|
| + fRangeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
|
| + kVec2f_GrSLType, kDefault_GrSLPrecision,
|
| + "Range");
|
| + const char* range = builder->getUniformCStr(fRangeUni);
|
|
|
| GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
|
| SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
|
| @@ -389,14 +409,41 @@ void GrGLMorphologyEffect::emitCode(GrGLFPBuilder* builder,
|
| func = ""; // suppress warning
|
| break;
|
| }
|
| - const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
|
|
|
| - fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
|
| - fsBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
|
| + const char* dir;
|
| + switch (fDirection) {
|
| + case Gr1DKernelEffect::kX_Direction:
|
| + dir = "x";
|
| + break;
|
| + case Gr1DKernelEffect::kY_Direction:
|
| + dir = "y";
|
| + break;
|
| + default:
|
| + SkFAIL("Unknown filter direction.");
|
| + dir = ""; // suppress warning
|
| + }
|
| +
|
| + // vec2 coord = coord2D;
|
| + fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
|
| + // coord.x -= radius * pixelSize;
|
| + fsBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, fRadius, pixelSizeInc);
|
| + if (fUseRange) {
|
| + // highBound = min(highBound, coord.x + (width-1) * pixelSize);
|
| + fsBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);",
|
| + range, dir, float(width() - 1), pixelSizeInc);
|
| + // coord.x = max(lowBound, coord.x);
|
| + fsBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir);
|
| + }
|
| + fsBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width());
|
| fsBuilder->codeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
|
| fsBuilder->appendTextureLookup(samplers[0], "coord");
|
| fsBuilder->codeAppend(");\n");
|
| - fsBuilder->codeAppendf("\t\t\tcoord += %s;\n", imgInc);
|
| + // coord.x += pixelSize;
|
| + fsBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc);
|
| + if (fUseRange) {
|
| + // coord.x = min(highBound, coord.x);
|
| + fsBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir);
|
| + }
|
| fsBuilder->codeAppend("\t\t}\n");
|
| SkString modulate;
|
| GrGLSLMulVarBy4f(&modulate, outputColor, inputColor);
|
| @@ -408,27 +455,41 @@ void GrGLMorphologyEffect::GenKey(const GrProcessor& proc,
|
| const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
|
| uint32_t key = static_cast<uint32_t>(m.radius());
|
| key |= (m.type() << 8);
|
| + key |= (m.direction() << 9);
|
| + if (m.useRange()) key |= 1 << 10;
|
| b->add32(key);
|
| }
|
|
|
| void GrGLMorphologyEffect::setData(const GrGLProgramDataManager& pdman,
|
| const GrProcessor& proc) {
|
| - const Gr1DKernelEffect& kern = proc.cast<Gr1DKernelEffect>();
|
| - GrTexture& texture = *kern.texture(0);
|
| - // the code we generated was for a specific kernel radius
|
| - SkASSERT(kern.radius() == fRadius);
|
| - float imageIncrement[2] = { 0 };
|
| - switch (kern.direction()) {
|
| + const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>();
|
| + GrTexture& texture = *m.texture(0);
|
| + // the code we generated was for a specific kernel radius, direction and bound usage
|
| + SkASSERT(m.radius() == fRadius);
|
| + SkASSERT(m.direction() == fDirection);
|
| + SkASSERT(m.useRange() == fUseRange);
|
| +
|
| + float pixelSize = 0.0f;
|
| + switch (fDirection) {
|
| case Gr1DKernelEffect::kX_Direction:
|
| - imageIncrement[0] = 1.0f / texture.width();
|
| + pixelSize = 1.0f / texture.width();
|
| break;
|
| case Gr1DKernelEffect::kY_Direction:
|
| - imageIncrement[1] = 1.0f / texture.height();
|
| + pixelSize = 1.0f / texture.height();
|
| break;
|
| default:
|
| SkFAIL("Unknown filter direction.");
|
| }
|
| - pdman.set2fv(fImageIncrementUni, 1, imageIncrement);
|
| + pdman.set1f(fPixelSizeUni, pixelSize);
|
| +
|
| + if (fUseRange) {
|
| + const float* range = m.range();
|
| + if (fDirection && texture.origin() == kBottomLeft_GrSurfaceOrigin) {
|
| + pdman.set2f(fRangeUni, 1.0f - range[1], 1.0f - range[0]);
|
| + } else {
|
| + pdman.set2f(fRangeUni, range[0], range[1]);
|
| + }
|
| + }
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| @@ -438,10 +499,22 @@ GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
|
| int radius,
|
| MorphologyType type)
|
| : Gr1DKernelEffect(texture, direction, radius)
|
| - , fType(type) {
|
| + , fType(type), fUseRange(false) {
|
| this->initClassID<GrMorphologyEffect>();
|
| }
|
|
|
| +GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture,
|
| + Direction direction,
|
| + int radius,
|
| + MorphologyType type,
|
| + float range[2])
|
| + : Gr1DKernelEffect(texture, direction, radius)
|
| + , fType(type), fUseRange(true) {
|
| + this->initClassID<GrMorphologyEffect>();
|
| + fRange[0] = range[0];
|
| + fRange[1] = range[1];
|
| +}
|
| +
|
| GrMorphologyEffect::~GrMorphologyEffect() {
|
| }
|
|
|
| @@ -456,6 +529,7 @@ bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const {
|
| const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>();
|
| return (this->radius() == s.radius() &&
|
| this->direction() == s.direction() &&
|
| + this->useRange() == s.useRange() &&
|
| this->type() == s.type());
|
| }
|
|
|
| @@ -486,7 +560,26 @@ GrFragmentProcessor* GrMorphologyEffect::TestCreate(SkRandom* random,
|
|
|
| namespace {
|
|
|
| -void apply_morphology_pass(GrContext* context,
|
| +
|
| +void apply_morphology_rect(GrContext* context,
|
| + GrTexture* texture,
|
| + const SkIRect& srcRect,
|
| + const SkIRect& dstRect,
|
| + int radius,
|
| + GrMorphologyEffect::MorphologyType morphType,
|
| + float bounds[2],
|
| + Gr1DKernelEffect::Direction direction) {
|
| + GrPaint paint;
|
| + paint.addColorProcessor(GrMorphologyEffect::Create(texture,
|
| + direction,
|
| + radius,
|
| + morphType,
|
| + bounds))->unref();
|
| + context->drawNonAARectToRect(paint, SkMatrix::I(), SkRect::Make(dstRect),
|
| + SkRect::Make(srcRect));
|
| +}
|
| +
|
| +void apply_morphology_rect_no_bounds(GrContext* context,
|
| GrTexture* texture,
|
| const SkIRect& srcRect,
|
| const SkIRect& dstRect,
|
| @@ -502,6 +595,51 @@ void apply_morphology_pass(GrContext* context,
|
| SkRect::Make(srcRect));
|
| }
|
|
|
| +void apply_morphology_pass(GrContext* context,
|
| + GrTexture* texture,
|
| + const SkIRect& srcRect,
|
| + const SkIRect& dstRect,
|
| + int radius,
|
| + GrMorphologyEffect::MorphologyType morphType,
|
| + Gr1DKernelEffect::Direction direction) {
|
| + float bounds[2] = { 0.0f, 1.0f };
|
| + SkIRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
|
| + SkIRect middleSrcRect = srcRect, middleDstRect = dstRect;
|
| + SkIRect upperSrcRect = srcRect, upperDstRect = dstRect;
|
| + if (direction == Gr1DKernelEffect::kX_Direction) {
|
| + bounds[0] = (SkIntToScalar(srcRect.left()) + 0.5f) / texture->width();
|
| + bounds[1] = (SkIntToScalar(srcRect.right()) - 0.5f) / texture->width();
|
| + lowerSrcRect.fRight = srcRect.left() + radius;
|
| + lowerDstRect.fRight = dstRect.left() + radius;
|
| + upperSrcRect.fLeft = srcRect.right() - radius;
|
| + upperDstRect.fLeft = dstRect.right() - radius;
|
| + middleSrcRect.inset(radius, 0);
|
| + middleDstRect.inset(radius, 0);
|
| + } else {
|
| + bounds[0] = (SkIntToScalar(srcRect.top()) + 0.5f) / texture->height();
|
| + bounds[1] = (SkIntToScalar(srcRect.bottom()) - 0.5f) / texture->height();
|
| + lowerSrcRect.fBottom = srcRect.top() + radius;
|
| + lowerDstRect.fBottom = dstRect.top() + radius;
|
| + upperSrcRect.fTop = srcRect.bottom() - radius;
|
| + upperDstRect.fTop = dstRect.bottom() - radius;
|
| + middleSrcRect.inset(0, radius);
|
| + middleDstRect.inset(0, radius);
|
| + }
|
| + if (middleSrcRect.fLeft - middleSrcRect.fRight >= 0) {
|
| + // radius covers srcRect; use bounds over entire draw
|
| + apply_morphology_rect(context, texture, srcRect, dstRect, radius,
|
| + morphType, bounds, direction);
|
| + } else {
|
| + // Draw upper and lower margins with bounds; middle without.
|
| + apply_morphology_rect(context, texture, lowerSrcRect, lowerDstRect, radius,
|
| + morphType, bounds, direction);
|
| + apply_morphology_rect(context, texture, upperSrcRect, upperDstRect, radius,
|
| + morphType, bounds, direction);
|
| + apply_morphology_rect_no_bounds(context, texture, middleSrcRect, middleDstRect, radius,
|
| + morphType, direction);
|
| + }
|
| +}
|
| +
|
| bool apply_morphology(const SkBitmap& input,
|
| const SkIRect& rect,
|
| GrMorphologyEffect::MorphologyType morphType,
|
|
|