Chromium Code Reviews| Index: src/effects/SkMorphologyImageFilter.cpp |
| diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp |
| index 3d27d10ee12197d52d9cf9ffd4d3f2f369ec9b12..081a762aa156fb682b45f5923df68b3a1156ca85 100644 |
| --- a/src/effects/SkMorphologyImageFilter.cpp |
| +++ b/src/effects/SkMorphologyImageFilter.cpp |
| @@ -286,14 +286,16 @@ public: |
| kDilate_MorphologyType, |
| }; |
| - static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius, |
| + static GrFragmentProcessor* Create(GrTexture* tex, Direction dir, int radius, bool useBounds, float bounds[2], |
|
Justin Novosad
2014/12/22 20:11:11
Instead of having useBounds, you should consider h
cwallez
2015/01/19 21:34:38
Done.
|
| MorphologyType type) { |
| - return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, type)); |
| + return SkNEW_ARGS(GrMorphologyEffect, (tex, dir, radius, useBounds, bounds, type)); |
| } |
| virtual ~GrMorphologyEffect(); |
| MorphologyType type() const { return fType; } |
| + bool useBounds() const { return fUseBounds; } |
| + const float* bounds() const { return fBounds; } |
|
Justin Novosad
2014/12/22 20:11:11
"Bounds" are usually SkRect throughout skia. Perha
cwallez
2015/01/19 21:34:39
This is not an actual x-y par but more like a min-
|
| static const char* Name() { return "Morphology"; } |
| @@ -304,13 +306,15 @@ public: |
| protected: |
| MorphologyType fType; |
| + bool fUseBounds; |
| + float fBounds[2]; |
| private: |
| virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE; |
| virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE; |
| - GrMorphologyEffect(GrTexture*, Direction, int radius, MorphologyType); |
| + GrMorphologyEffect(GrTexture*, Direction, int radius, bool useBounds, float bounds[2], MorphologyType); |
| GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
| @@ -338,8 +342,11 @@ private: |
| int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); } |
| int fRadius; |
| + Gr1DKernelEffect::Direction fDirection; |
| + bool fUseBounds; |
| GrMorphologyEffect::MorphologyType fType; |
| - GrGLProgramDataManager::UniformHandle fImageIncrementUni; |
| + GrGLProgramDataManager::UniformHandle fPixelSizeUni; |
| + GrGLProgramDataManager::UniformHandle fBoundsUni; |
| typedef GrGLFragmentProcessor INHERITED; |
| }; |
| @@ -349,6 +356,8 @@ GrGLMorphologyEffect::GrGLMorphologyEffect(const GrBackendProcessorFactory& fact |
| : INHERITED(factory) { |
| const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); |
| fRadius = m.radius(); |
| + fDirection = m.direction(); |
| + fUseBounds = m.useBounds(); |
| fType = m.type(); |
| } |
| @@ -358,8 +367,12 @@ void GrGLMorphologyEffect::emitCode(GrGLFPBuilder* builder, |
| const char* inputColor, |
| const TransformedCoordsArray& coords, |
| const TextureSamplerArray& samplers) { |
| - fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| - kVec2f_GrSLType, "ImageIncrement"); |
| + fPixelSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| + kFloat_GrSLType, "PixelSize"); |
| + const char* pixelSizeInc = builder->getUniformCStr(fPixelSizeUni); |
| + fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| + kVec2f_GrSLType, "Bounds"); |
| + const char* bounds = builder->getUniformCStr(fBoundsUni); |
| GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); |
| SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0); |
| @@ -378,14 +391,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 (fUseBounds) { |
| + // highBound = min(highBound, coord.x + (width-1) * pixelSize); |
| + fsBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %d * %s);", |
| + bounds, dir, width() - 1, pixelSizeInc); |
| + // coord.x = max(lowBound, coord.x); |
| + fsBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, bounds, 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 (fUseBounds) { |
| + // 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); |
| @@ -397,27 +437,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.useBounds()) 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.useBounds() == fUseBounds); |
| + |
| + 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 (fUseBounds) { |
| + const float* bounds = m.bounds(); |
| + if (fDirection && texture.origin() == kBottomLeft_GrSurfaceOrigin) { |
| + pdman.set2f(fBoundsUni, 1.0f - bounds[1], 1.0f - bounds[0]); |
| + } else { |
| + pdman.set2f(fBoundsUni, bounds[0], bounds[1]); |
| + } |
| + } |
| } |
| /////////////////////////////////////////////////////////////////////////////// |
| @@ -425,9 +479,13 @@ void GrGLMorphologyEffect::setData(const GrGLProgramDataManager& pdman, |
| GrMorphologyEffect::GrMorphologyEffect(GrTexture* texture, |
| Direction direction, |
| int radius, |
| + bool useBounds, |
| + float bounds[2], |
| MorphologyType type) |
| : Gr1DKernelEffect(texture, direction, radius) |
| - , fType(type) { |
| + , fType(type), fUseBounds(useBounds) { |
| + fBounds[0] = bounds[0]; |
| + fBounds[1] = bounds[1]; |
| } |
| GrMorphologyEffect::~GrMorphologyEffect() { |
| @@ -441,6 +499,7 @@ bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const { |
| const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>(); |
| return (this->radius() == s.radius() && |
| this->direction() == s.direction() && |
| + this->useBounds() == s.useBounds() && |
| this->type() == s.type()); |
| } |
| @@ -454,6 +513,8 @@ void GrMorphologyEffect::onComputeInvariantOutput(GrInvariantOutput* inout) cons |
| GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMorphologyEffect); |
| +static float unusedBounds[2] = {0.0f, 0.0f}; |
| + |
| GrFragmentProcessor* GrMorphologyEffect::TestCreate(SkRandom* random, |
| GrContext*, |
| const GrDrawTargetCaps&, |
| @@ -466,26 +527,76 @@ GrFragmentProcessor* GrMorphologyEffect::TestCreate(SkRandom* random, |
| MorphologyType type = random->nextBool() ? GrMorphologyEffect::kErode_MorphologyType : |
| GrMorphologyEffect::kDilate_MorphologyType; |
| - return GrMorphologyEffect::Create(textures[texIdx], dir, radius, type); |
| + return GrMorphologyEffect::Create(textures[texIdx], dir, radius, false, unusedBounds, type); |
| } |
| 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, |
| + bool useBounds, |
| + float bounds[2], |
| Gr1DKernelEffect::Direction direction) { |
| GrPaint paint; |
| paint.addColorProcessor(GrMorphologyEffect::Create(texture, |
| direction, |
| radius, |
| + useBounds, |
| + bounds, |
| morphType))->unref(); |
| context->drawRectToRect(paint, SkRect::Make(dstRect), 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, true, bounds, direction); |
| + } else { |
| + // Draw upper and lower margins with bounds; middle without. |
| + apply_morphology_rect(context, texture, lowerSrcRect, lowerDstRect, radius, |
| + morphType, true, bounds, direction); |
| + apply_morphology_rect(context, texture, upperSrcRect, upperDstRect, radius, |
| + morphType, true, bounds, direction); |
| + apply_morphology_rect(context, texture, middleSrcRect, middleDstRect, radius, |
| + morphType, false, bounds, direction); |
| + } |
| +} |
| + |
| bool apply_morphology(const SkBitmap& input, |
| const SkIRect& rect, |
| GrMorphologyEffect::MorphologyType morphType, |
| @@ -517,12 +628,12 @@ bool apply_morphology(const SkBitmap& input, |
| GrContext::AutoRenderTarget art(context, texture->asRenderTarget()); |
| apply_morphology_pass(context, srcTexture, srcRect, dstRect, radius.fWidth, |
| morphType, Gr1DKernelEffect::kX_Direction); |
| - SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom, |
| + /*SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom, |
|
Justin Novosad
2014/12/22 20:11:11
Don't commit commented code
cwallez
2015/01/19 21:34:39
Done.
|
| dstRect.width(), radius.fHeight); |
| GrColor clearColor = GrMorphologyEffect::kErode_MorphologyType == morphType ? |
| SK_ColorWHITE : |
| SK_ColorTRANSPARENT; |
| - context->clear(&clearRect, clearColor, false, texture->asRenderTarget()); |
| + context->clear(&clearRect, clearColor, false, texture->asRenderTarget());*/ |
| srcTexture.reset(texture); |
| srcRect = dstRect; |
| } |