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

Unified Diff: src/effects/SkMorphologyImageFilter.cpp

Issue 781153002: Fix Morphology effects sourcing outside of the crop rect. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years 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 side-by-side diff with in-line comments
Download patch
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;
}

Powered by Google App Engine
This is Rietveld 408576698