aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects/GrCircleBlurFragmentProcessor.cpp
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2017-09-11 16:33:48 +0000
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-09-11 16:34:02 +0000
commit358515491a0d6891e6a709688a30ad087df1beb1 (patch)
treece64223230053df7db85c94b848ad526e64269cd /src/effects/GrCircleBlurFragmentProcessor.cpp
parentc576e93d174f3106e072a2f506bca3990b541265 (diff)
Revert "Switch to the new SkSL lexer."
This reverts commit c576e93d174f3106e072a2f506bca3990b541265. Reason for revert: ASAN failures Original change's description: > Switch to the new SkSL lexer. > > This completely replaces flex with a new in-house lexical analyzer generator, > which we have done for performance and memory usage reasons. Flex requires us > to copy strings every time we need the text of a token, whereas this new lexer > allows us to handle strings as a (non-null-terminated) pointer and length > everywhere, eliminating most string copies. > > Bug: skia: > Change-Id: I2add26efc9e20cb699520e82abcf713af3968aca > Reviewed-on: https://skia-review.googlesource.com/39780 > Reviewed-by: Brian Salomon <bsalomon@google.com> > Commit-Queue: Ethan Nicholas <ethannicholas@google.com> TBR=bsalomon@google.com,ethannicholas@google.com Change-Id: If27b750a5f696d06a6bcffed12fe9f0598e084a6 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/44881 Reviewed-by: Ethan Nicholas <ethannicholas@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
Diffstat (limited to 'src/effects/GrCircleBlurFragmentProcessor.cpp')
-rw-r--r--src/effects/GrCircleBlurFragmentProcessor.cpp55
1 files changed, 12 insertions, 43 deletions
diff --git a/src/effects/GrCircleBlurFragmentProcessor.cpp b/src/effects/GrCircleBlurFragmentProcessor.cpp
index 75d73bdbd0..7cec3cc431 100644
--- a/src/effects/GrCircleBlurFragmentProcessor.cpp
+++ b/src/effects/GrCircleBlurFragmentProcessor.cpp
@@ -13,13 +13,11 @@
#include "GrResourceProvider.h"
-// Computes an unnormalized half kernel (right side). Returns the summation of all the half
-// kernel values.
static float make_unnormalized_half_kernel(float* halfKernel, int halfKernelSize, float sigma) {
const float invSigma = 1.f / sigma;
const float b = -0.5f * invSigma * invSigma;
float tot = 0.0f;
- // Compute half kernel values at half pixel steps out from the center.
+
float t = 0.5f;
for (int i = 0; i < halfKernelSize; ++i) {
float value = expf(t * t * b);
@@ -30,11 +28,8 @@ static float make_unnormalized_half_kernel(float* halfKernel, int halfKernelSize
return tot;
}
-// Create a Gaussian half-kernel (right side) and a summed area table given a sigma and number
-// of discrete steps. The half kernel is normalized to sum to 0.5.
static void make_half_kernel_and_summed_table(float* halfKernel, float* summedHalfKernel,
int halfKernelSize, float sigma) {
- // The half kernel should sum to 0.5 not 1.0.
const float tot = 2.f * make_unnormalized_half_kernel(halfKernel, halfKernelSize, sigma);
float sum = 0.f;
for (int i = 0; i < halfKernelSize; ++i) {
@@ -44,8 +39,6 @@ static void make_half_kernel_and_summed_table(float* halfKernel, float* summedHa
}
}
-// Applies the 1D half kernel vertically at points along the x axis to a circle centered at the
-// origin with radius circleR.
void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR,
int halfKernelSize, const float* summedHalfKernelTable) {
float x = firstX;
@@ -55,8 +48,7 @@ void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR
continue;
}
float y = sqrtf(circleR * circleR - x * x);
- // In the column at x we exit the circle at +y and -y
- // The summed table entry j is actually reflects an offset of j + 0.5.
+
y -= 0.5f;
int yInt = SkScalarFloorToInt(y);
SkASSERT(yInt >= -1);
@@ -72,10 +64,6 @@ void apply_kernel_in_y(float* results, int numSteps, float firstX, float circleR
}
}
-// Apply a Gaussian at point (evalX, 0) to a circle centered at the origin with radius circleR.
-// This relies on having a half kernel computed for the Gaussian and a table of applications of
-// the half kernel in y to columns at (evalX - halfKernel, evalX - halfKernel + 1, ..., evalX +
-// halfKernel) passed in as yKernelEvaluations.
static uint8_t eval_at(float evalX, float circleR, const float* halfKernel, int halfKernelSize,
const float* yKernelEvaluations) {
float acc = 0;
@@ -95,28 +83,18 @@ static uint8_t eval_at(float evalX, float circleR, const float* halfKernel, int
float verticalEval = yKernelEvaluations[i + halfKernelSize];
acc += verticalEval * halfKernel[i];
}
- // Since we applied a half kernel in y we multiply acc by 2 (the circle is symmetric about
- // the x axis).
+
return SkUnitScalarClampToByte(2.f * acc);
}
-// This function creates a profile of a blurred circle. It does this by computing a kernel for
-// half the Gaussian and a matching summed area table. The summed area table is used to compute
-// an array of vertical applications of the half kernel to the circle along the x axis. The
-// table of y evaluations has 2 * k + n entries where k is the size of the half kernel and n is
-// the size of the profile being computed. Then for each of the n profile entries we walk out k
-// steps in each horizontal direction multiplying the corresponding y evaluation by the half
-// kernel entry and sum these values to compute the profile entry.
static uint8_t* create_circle_profile(float sigma, float circleR, int profileTextureWidth) {
const int numSteps = profileTextureWidth;
uint8_t* weights = new uint8_t[numSteps];
- // The full kernel is 6 sigmas wide.
int halfKernelSize = SkScalarCeilToInt(6.0f * sigma);
- // round up to next multiple of 2 and then divide by 2
+
halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1;
- // Number of x steps at which to apply kernel in y to cover all the profile samples in x.
int numYSteps = numSteps + 2 * halfKernelSize;
SkAutoTArray<float> bulkAlloc(halfKernelSize + halfKernelSize + numYSteps);
@@ -132,36 +110,34 @@ static uint8_t* create_circle_profile(float sigma, float circleR, int profileTex
float evalX = i + 0.5f;
weights[i] = eval_at(evalX, circleR, halfKernel, halfKernelSize, yEvals + i);
}
- // Ensure the tail of the Gaussian goes to zero.
+
weights[numSteps - 1] = 0;
return weights;
}
static uint8_t* create_half_plane_profile(int profileWidth) {
SkASSERT(!(profileWidth & 0x1));
- // The full kernel is 6 sigmas wide.
+
float sigma = profileWidth / 6.f;
int halfKernelSize = profileWidth / 2;
SkAutoTArray<float> halfKernel(halfKernelSize);
uint8_t* profile = new uint8_t[profileWidth];
- // The half kernel should sum to 0.5.
const float tot = 2.f * make_unnormalized_half_kernel(halfKernel.get(), halfKernelSize, sigma);
float sum = 0.f;
- // Populate the profile from the right edge to the middle.
+
for (int i = 0; i < halfKernelSize; ++i) {
halfKernel[halfKernelSize - i - 1] /= tot;
sum += halfKernel[halfKernelSize - i - 1];
profile[profileWidth - i - 1] = SkUnitScalarClampToByte(sum);
}
- // Populate the profile from the middle to the left edge (by flipping the half kernel and
- // continuing the summation).
+
for (int i = 0; i < halfKernelSize; ++i) {
sum += halfKernel[i];
profile[halfKernelSize - i - 1] = SkUnitScalarClampToByte(sum);
}
- // Ensure tail goes to 0.
+
profile[profileWidth - 1] = 0;
return profile;
}
@@ -170,13 +146,9 @@ static sk_sp<GrTextureProxy> create_profile_texture(GrResourceProvider* resource
const SkRect& circle, float sigma,
float* solidRadius, float* textureRadius) {
float circleR = circle.width() / 2.0f;
- // Profile textures are cached by the ratio of sigma to circle radius and by the size of the
- // profile texture (binned by powers of 2).
+
SkScalar sigmaToCircleRRatio = sigma / circleR;
- // When sigma is really small this becomes a equivalent to convolving a Gaussian with a
- // half-plane. Similarly, in the extreme high ratio cases circle becomes a point WRT to the
- // Guassian and the profile texture is a just a Gaussian evaluation. However, we haven't yet
- // implemented this latter optimization.
+
sigmaToCircleRRatio = SkTMin(sigmaToCircleRRatio, 8.f);
SkFixed sigmaToCircleRRatioFixed;
static const SkScalar kHalfPlaneThreshold = 0.1f;
@@ -187,10 +159,8 @@ static sk_sp<GrTextureProxy> create_profile_texture(GrResourceProvider* resource
*solidRadius = circleR - 3 * sigma;
*textureRadius = 6 * sigma;
} else {
- // Convert to fixed point for the key.
sigmaToCircleRRatioFixed = SkScalarToFixed(sigmaToCircleRRatio);
- // We shave off some bits to reduce the number of unique entries. We could probably
- // shave off more than we do.
+
sigmaToCircleRRatioFixed &= ~0xff;
sigmaToCircleRRatio = SkFixedToScalar(sigmaToCircleRRatioFixed);
sigma = circleR * sigmaToCircleRRatio;
@@ -218,7 +188,6 @@ static sk_sp<GrTextureProxy> create_profile_texture(GrResourceProvider* resource
if (useHalfPlaneApprox) {
profile.reset(create_half_plane_profile(kProfileTextureWidth));
} else {
- // Rescale params to the size of the texture we're creating.
SkScalar scale = kProfileTextureWidth / *textureRadius;
profile.reset(
create_circle_profile(sigma * scale, circleR * scale, kProfileTextureWidth));