aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2016-08-16 09:30:03 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-16 09:30:03 -0700
commitc4d2f907311fca08303c254b2488bd7990fa2f32 (patch)
tree8b2a684a908b6760e729969b02de844a4dc67f3c /src/effects
parent2f4114a246e4753ef5dab63a4b40caf0cf7950ac (diff)
Update ComputeBlurredRRectParams to compute all the parameters needed for occluded blurred rrect ninepatch draws
This is split out of: https://codereview.chromium.org/2245653002/ (Start using vertex attributes for nine-patch blurred rrect draws) GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2248533002 Review-Url: https://codereview.chromium.org/2248533002
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/SkBlurMaskFilter.cpp193
1 files changed, 143 insertions, 50 deletions
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 0e6de9e8a1..c044333efb 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -139,59 +139,144 @@ sk_sp<SkMaskFilter> SkBlurMaskFilter::Make(SkBlurStyle style, SkScalar sigma,
return sk_sp<SkMaskFilter>(new SkBlurMaskFilterImpl(sigma, style, occluder, flags));
}
-bool SkBlurMaskFilter::ComputeBlurredRRectParams(const SkRRect& rrect,
- SkScalar sigma,
+// linearly interpolate between y1 & y3 to match x2's position between x1 & x3
+static SkScalar interp(SkScalar x1, SkScalar x2, SkScalar x3, SkScalar y1, SkScalar y3) {
+ SkASSERT(x1 <= x2 && x2 <= x3);
+ SkASSERT(y1 <= y3);
+
+ SkScalar t = (x2 - x1) / (x3 - x1);
+ return y1 + t * (y3 - y1);
+}
+
+// Insert 'lower' and 'higher' into 'array1' and insert a new value at each matching insertion
+// point in 'array2' that linearly interpolates between the existing values.
+// Return a bit mask which contains a copy of 'inputMask' for all the cells between the two
+// insertion points.
+static uint32_t insert_into_arrays(SkScalar* array1, SkScalar* array2,
+ SkScalar lower, SkScalar higher,
+ int* num, uint32_t inputMask, int maskSize) {
+ SkASSERT(lower < higher);
+ SkASSERT(lower >= array1[0] && higher <= array1[*num-1]);
+
+ int32_t skipMask = 0x0;
+ int i;
+ for (i = 0; i < *num; ++i) {
+ if (lower >= array1[i] && lower < array1[i+1]) {
+ if (!SkScalarNearlyEqual(lower, array1[i])) {
+ memmove(&array1[i+2], &array1[i+1], (*num-i-1)*sizeof(SkScalar));
+ array1[i+1] = lower;
+ memmove(&array2[i+2], &array2[i+1], (*num-i-1)*sizeof(SkScalar));
+ array2[i+1] = interp(array1[i], lower, array1[i+2], array2[i], array2[i+2]);
+ i++;
+ (*num)++;
+ }
+ break;
+ }
+ }
+ for ( ; i < *num; ++i) {
+ skipMask |= inputMask << (i*maskSize);
+ if (higher > array1[i] && higher <= array1[i+1]) {
+ if (!SkScalarNearlyEqual(higher, array1[i+1])) {
+ memmove(&array1[i+2], &array1[i+1], (*num-i-1)*sizeof(SkScalar));
+ array1[i+1] = higher;
+ memmove(&array2[i+2], &array2[i+1], (*num-i-1)*sizeof(SkScalar));
+ array2[i+1] = interp(array1[i], higher, array1[i+2], array2[i], array2[i+2]);
+ (*num)++;
+ }
+ break;
+ }
+ }
+
+ return skipMask;
+}
+
+bool SkBlurMaskFilter::ComputeBlurredRRectParams(const SkRRect& srcRRect, const SkRRect& devRRect,
+ const SkRect& occluder,
+ SkScalar sigma, SkScalar xformedSigma,
SkRRect* rrectToDraw,
SkISize* widthHeight,
- SkScalar xs[4],
- int* numXs,
- SkScalar ys[4],
- int* numYs) {
- unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f);
-
- const SkRect& orig = rrect.getBounds();
- const SkVector& radiiUL = rrect.radii(SkRRect::kUpperLeft_Corner);
- const SkVector& radiiUR = rrect.radii(SkRRect::kUpperRight_Corner);
- const SkVector& radiiLR = rrect.radii(SkRRect::kLowerRight_Corner);
- const SkVector& radiiLL = rrect.radii(SkRRect::kLowerLeft_Corner);
-
- const int left = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUL.fX, radiiLL.fX));
- const int top = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUL.fY, radiiUR.fY));
- const int right = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUR.fX, radiiLR.fX));
- const int bot = SkScalarCeilToInt(SkTMax<SkScalar>(radiiLL.fY, radiiLR.fY));
+ SkScalar rectXs[kMaxDivisions],
+ SkScalar rectYs[kMaxDivisions],
+ SkScalar texXs[kMaxDivisions],
+ SkScalar texYs[kMaxDivisions],
+ int* numXs, int* numYs, uint32_t* skipMask) {
+ unsigned int devBlurRadius = 3*SkScalarCeilToInt(xformedSigma-1/6.0f);
+ SkScalar srcBlurRadius = 3.0f * sigma;
+
+ const SkRect& devOrig = devRRect.getBounds();
+ const SkVector& devRadiiUL = devRRect.radii(SkRRect::kUpperLeft_Corner);
+ const SkVector& devRadiiUR = devRRect.radii(SkRRect::kUpperRight_Corner);
+ const SkVector& devRadiiLR = devRRect.radii(SkRRect::kLowerRight_Corner);
+ const SkVector& devRadiiLL = devRRect.radii(SkRRect::kLowerLeft_Corner);
+
+ const int devLeft = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUL.fX, devRadiiLL.fX));
+ const int devTop = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUL.fY, devRadiiUR.fY));
+ const int devRight = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiUR.fX, devRadiiLR.fX));
+ const int devBot = SkScalarCeilToInt(SkTMax<SkScalar>(devRadiiLL.fY, devRadiiLR.fY));
// This is a conservative check for nine-patchability
- if (orig.fLeft + left + blurRadius >= orig.fRight - right - blurRadius ||
- orig.fTop + top + blurRadius >= orig.fBottom - bot - blurRadius) {
+ if (devOrig.fLeft + devLeft + devBlurRadius >= devOrig.fRight - devRight - devBlurRadius ||
+ devOrig.fTop + devTop + devBlurRadius >= devOrig.fBottom - devBot - devBlurRadius) {
return false;
}
- int newRRWidth, newRRHeight;
+ const SkVector& srcRadiiUL = srcRRect.radii(SkRRect::kUpperLeft_Corner);
+ const SkVector& srcRadiiUR = srcRRect.radii(SkRRect::kUpperRight_Corner);
+ const SkVector& srcRadiiLR = srcRRect.radii(SkRRect::kLowerRight_Corner);
+ const SkVector& srcRadiiLL = srcRRect.radii(SkRRect::kLowerLeft_Corner);
+
+ const SkScalar srcLeft = SkTMax<SkScalar>(srcRadiiUL.fX, srcRadiiLL.fX);
+ const SkScalar srcTop = SkTMax<SkScalar>(srcRadiiUL.fY, srcRadiiUR.fY);
+ const SkScalar srcRight = SkTMax<SkScalar>(srcRadiiUR.fX, srcRadiiLR.fX);
+ const SkScalar srcBot = SkTMax<SkScalar>(srcRadiiLL.fY, srcRadiiLR.fY);
+
+ int newRRWidth = 2*devBlurRadius + devLeft + devRight + 1;
+ int newRRHeight = 2*devBlurRadius + devTop + devBot + 1;
+ widthHeight->fWidth = newRRWidth + 2 * devBlurRadius;
+ widthHeight->fHeight = newRRHeight + 2 * devBlurRadius;
+
+ const SkRect srcProxyRect = srcRRect.getBounds().makeOutset(srcBlurRadius, srcBlurRadius);
+
+ rectXs[0] = srcProxyRect.fLeft;
+ rectXs[1] = srcProxyRect.fLeft + 2*srcBlurRadius + srcLeft;
+ rectXs[2] = srcProxyRect.fRight - 2*srcBlurRadius - srcRight;
+ rectXs[3] = srcProxyRect.fRight;
+
+ rectYs[0] = srcProxyRect.fTop;
+ rectYs[1] = srcProxyRect.fTop + 2*srcBlurRadius + srcTop;
+ rectYs[2] = srcProxyRect.fBottom - 2*srcBlurRadius - srcBot;
+ rectYs[3] = srcProxyRect.fBottom;
+
+ texXs[0] = 0.0f;
+ texXs[1] = 2.0f*devBlurRadius + devLeft;
+ texXs[2] = 2.0f*devBlurRadius + devLeft + 1;
+ texXs[3] = SkIntToScalar(widthHeight->fWidth);
+
+ texYs[0] = 0.0f;
+ texYs[1] = 2.0f*devBlurRadius + devTop;
+ texYs[2] = 2.0f*devBlurRadius + devTop + 1;
+ texYs[3] = SkIntToScalar(widthHeight->fHeight);
+
+ SkRect temp = occluder;
- // 3x3 case
- newRRWidth = 2*blurRadius + left + right + 1;
- newRRHeight = 2*blurRadius + top + bot + 1;
- widthHeight->fWidth = newRRWidth + 2 * blurRadius;
- widthHeight->fHeight = newRRHeight + 2 * blurRadius;
- // TODO: need to return non-normalized indices
- xs[0] = 0.0f;
- xs[1] = (blurRadius + left) / (float) widthHeight->fWidth;
- xs[2] = (blurRadius + left + 1.0f) / widthHeight->fWidth;
- xs[3] = 1.0f;
*numXs = 4;
- ys[0] = 0.0f;
- ys[1] = (blurRadius + top) / (float) widthHeight->fHeight;
- ys[2] = (blurRadius + top + 1.0f) / widthHeight->fHeight;
- ys[3] = 1.0f;
*numYs = 4;
+ *skipMask = 0;
+ if (!temp.isEmpty() && (srcProxyRect.contains(temp) || temp.intersect(srcProxyRect))) {
+ *skipMask = insert_into_arrays(rectXs, texXs, temp.fLeft, temp.fRight, numXs, 0x1, 1);
+ *skipMask = insert_into_arrays(rectYs, texYs, temp.fTop, temp.fBottom,
+ numYs, *skipMask, *numXs-1);
+ }
- const SkRect newRect = SkRect::MakeXYWH(SkIntToScalar(blurRadius), SkIntToScalar(blurRadius),
- SkIntToScalar(newRRWidth), SkIntToScalar(newRRHeight));
+ const SkRect newRect = SkRect::MakeXYWH(SkIntToScalar(devBlurRadius),
+ SkIntToScalar(devBlurRadius),
+ SkIntToScalar(newRRWidth),
+ SkIntToScalar(newRRHeight));
SkVector newRadii[4];
- newRadii[0] = { SkScalarCeilToScalar(radiiUL.fX), SkScalarCeilToScalar(radiiUL.fY) };
- newRadii[1] = { SkScalarCeilToScalar(radiiUR.fX), SkScalarCeilToScalar(radiiUR.fY) };
- newRadii[2] = { SkScalarCeilToScalar(radiiLR.fX), SkScalarCeilToScalar(radiiLR.fY) };
- newRadii[3] = { SkScalarCeilToScalar(radiiLL.fX), SkScalarCeilToScalar(radiiLL.fY) };
+ newRadii[0] = { SkScalarCeilToScalar(devRadiiUL.fX), SkScalarCeilToScalar(devRadiiUL.fY) };
+ newRadii[1] = { SkScalarCeilToScalar(devRadiiUR.fX), SkScalarCeilToScalar(devRadiiUR.fY) };
+ newRadii[2] = { SkScalarCeilToScalar(devRadiiLR.fX), SkScalarCeilToScalar(devRadiiLR.fY) };
+ newRadii[3] = { SkScalarCeilToScalar(devRadiiLL.fX), SkScalarCeilToScalar(devRadiiLL.fY) };
rrectToDraw->setRectRadii(newRect, newRadii);
return true;
@@ -983,7 +1068,9 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
class GrRRectBlurEffect : public GrFragmentProcessor {
public:
- static sk_sp<GrFragmentProcessor> Make(GrContext*, float sigma, const SkRRect&);
+ static sk_sp<GrFragmentProcessor> Make(GrContext*,
+ float sigma, float xformedSigma,
+ const SkRRect& srcRRect, const SkRRect& devRRect);
virtual ~GrRRectBlurEffect() {};
const char* name() const override { return "GrRRectBlur"; }
@@ -1069,8 +1156,8 @@ static sk_sp<GrTexture> find_or_create_rrect_blur_mask(GrContext* context,
}
sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrContext* context,
- float xformedSigma,
- const SkRRect& devRRect) {
+ float sigma, float xformedSigma,
+ const SkRRect& srcRRect, const SkRRect& devRRect) {
SkASSERT(!devRRect.isCircle()); // Should've been caught up-stream
// TODO: loosen this up
@@ -1083,13 +1170,18 @@ sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrContext* context,
// width (and height) of the rrect.
SkRRect rrectToDraw;
SkISize size;
- SkScalar ignored[4];
+ SkScalar ignored[SkBlurMaskFilter::kMaxDivisions];
int ignoredSize;
+ uint32_t ignored32;
- bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(devRRect, xformedSigma,
+ bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(srcRRect, devRRect,
+ SkRect::MakeEmpty(),
+ sigma, xformedSigma,
&rrectToDraw, &size,
- ignored, &ignoredSize,
- ignored, &ignoredSize);
+ ignored, ignored,
+ ignored, ignored,
+ &ignoredSize, &ignoredSize,
+ &ignored32);
if (!ninePatchable) {
return nullptr;
}
@@ -1136,7 +1228,7 @@ sk_sp<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d)
SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f);
SkRRect rrect;
rrect.setRectXY(SkRect::MakeWH(w, h), r, r);
- return GrRRectBlurEffect::Make(d->fContext, sigma, rrect);
+ return GrRRectBlurEffect::Make(d->fContext, sigma, sigma, rrect, rrect);
}
//////////////////////////////////////////////////////////////////////////////
@@ -1279,7 +1371,8 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context,
return true;
}
- sk_sp<GrFragmentProcessor> fp(GrRRectBlurEffect::Make(context, xformedSigma, devRRect));
+ sk_sp<GrFragmentProcessor> fp(GrRRectBlurEffect::Make(context, fSigma, xformedSigma,
+ srcRRect, devRRect));
if (!fp) {
return false;
}