48 *
table.getAddr8(0, 0) = 255;
49 const float invWidth = 1.f /
width;
50 for (
int i = 1;
i <
width - 1; ++
i) {
51 float x = (
i + 0.5f) * invWidth;
53 float integral = 0.5f * (std::erf(
x) + 1.f);
88 const float invSigma = 1.0f / sigma;
89 const float b = -0.5f * invSigma * invSigma;
93 for (
int i = 0;
i < halfKernelSize; ++
i) {
94 float value = expf(t * t *
b);
105 float* summedHalfKernel,
111 for (
int i = 0;
i < halfKernelSize; ++
i) {
112 halfKernel[
i] /= tot;
113 sum += halfKernel[
i];
114 summedHalfKernel[
i] = sum;
125 const float* summedHalfKernelTable) {
127 for (
int i = 0;
i < numSteps; ++
i,
x += 1.0f) {
128 if (x < -circleR || x > circleR) {
132 float y = sqrtf(circleR * circleR -
x *
x);
139 results[
i] = (
y + 0.5f) * summedHalfKernelTable[0];
140 }
else if (yInt >= halfKernelSize - 1) {
143 float yFrac =
y - yInt;
144 results[
i] = (1.0f - yFrac) * summedHalfKernelTable[yInt] +
145 yFrac * summedHalfKernelTable[yInt + 1];
156 const float* halfKernel,
158 const float* yKernelEvaluations) {
161 float x = evalX - halfKernelSize;
162 for (
int i = 0;
i < halfKernelSize; ++
i,
x += 1.0f) {
163 if (x < -circleR || x > circleR) {
166 float verticalEval = yKernelEvaluations[
i];
167 acc += verticalEval * halfKernel[halfKernelSize -
i - 1];
169 for (
int i = 0;
i < halfKernelSize; ++
i,
x += 1.0f) {
170 if (x < -circleR || x > circleR) {
173 float verticalEval = yKernelEvaluations[
i + halfKernelSize];
174 acc += verticalEval * halfKernel[
i];
196 const int numSteps = profileWidth;
201 halfKernelSize = ((halfKernelSize + 1) & ~1) >> 1;
204 const int numYSteps = numSteps + 2 * halfKernelSize;
207 float* halfKernel = bulkAlloc.
get();
208 float* summedKernel = bulkAlloc.
get() + halfKernelSize;
209 float* yEvals = bulkAlloc.
get() + 2 * halfKernelSize;
212 float firstX = -halfKernelSize + 0.5f;
213 apply_kernel_in_y(yEvals, numYSteps, firstX, radius, halfKernelSize, summedKernel);
215 for (
int i = 0;
i < numSteps - 1; ++
i) {
216 float evalX =
i + 0.5f;
217 profile[
i] =
eval_at(evalX, radius, halfKernel, halfKernelSize, yEvals +
i);
237 const float sigma = profileWidth / 6.0f;
238 const int halfKernelSize = profileWidth / 2;
246 for (
int i = 0;
i < halfKernelSize; ++
i) {
247 halfKernel[halfKernelSize -
i - 1] /= tot;
248 sum += halfKernel[halfKernelSize -
i - 1];
253 for (
int i = 0;
i < halfKernelSize; ++
i) {
254 sum += halfKernel[
i];
270static uint8_t
eval_V(
float top,
int y,
const uint8_t* integral,
int integralSize,
float sixSigma) {
275 float fT = (top -
y - 0.5f) * (integralSize / sixSigma);
278 }
else if (fT >= integralSize - 1) {
283 float frac = fT -
lower;
287 return integral[
lower] * (1.0f - frac) + integral[
lower + 1] * frac;
293 const std::vector<float>& topVec,
296 const uint8_t* integral,
304 int xSampleLoc =
x - (kernelSize / 2);
305 for (
int i = 0;
i < kernelSize; ++
i, ++xSampleLoc) {
306 if (xSampleLoc < 0 || xSampleLoc >= (
int)topVec.size()) {
310 accum += kernel[
i] *
eval_V(topVec[xSampleLoc],
y, integral, integralSize, sixSigma);
328 const int halfWidthPlus1 = (dimensions.
width() / 2) + 1;
329 const int halfHeightPlus1 = (dimensions.
height() / 2) + 1;
331 std::unique_ptr<float[]> kernel(
new float[kernelSize]);
336 if (integral.
empty()) {
345 std::vector<float> topVec;
346 topVec.reserve(dimensions.
width());
347 for (
int x = 0;
x < dimensions.
width(); ++
x) {
349 topVec.push_back(-1);
352 float xDist = rrectToDraw.
rect().
fLeft + radii.
fX -
x - 0.5f;
353 float h = sqrtf(radii.
fX * radii.
fX - xDist * xDist);
355 topVec.push_back(rrectToDraw.
rect().
fTop + radii.
fX -
h + 3 * sigma);
357 topVec.push_back(rrectToDraw.
rect().
fTop + 3 * sigma);
362 for (
int y = 0;
y < halfHeightPlus1; ++
y) {
363 uint8_t* scanline =
result.getAddr8(0,
y);
365 for (
int x = 0;
x < halfWidthPlus1; ++
x) {
374 scanline[dimensions.
width() -
x - 1] = scanline[
x];
static U8CPU SkUnitScalarClampToByte(SkScalar x)
static bool SkIsFinite(T x, Pack... values)
#define sk_float_round2int(x)
static int SkNextPow2(int value)
static constexpr int32_t SK_MaxS32
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SkScalarCeilToInt(x)
#define SkScalarFloorToInt(x)
#define SK_ScalarRoot2Over2
constexpr uint8_t SkToU8(S x)
uint8_t * getAddr8(int x, int y) const
SkVector getSimpleRadii() const
const SkRect & rect() const
static float max(float r, float g, float b)
constexpr bool BlurIsEffectivelyIdentity(float sigma)
static uint8_t eval_H(int x, int y, const std::vector< float > &topVec, const float *kernel, int kernelSize, const uint8_t *integral, int integralSize, float sixSigma)
SkBitmap CreateRRectBlurMask(const SkRRect &rrectToDraw, const SkISize &dimensions, float sigma)
int ComputeIntegralTableWidth(float sixSigma)
void Compute1DBlurKernel(float sigma, int radius, SkSpan< float > kernel)
static uint8_t eval_at(float evalX, float circleR, const float *halfKernel, int halfKernelSize, const float *yKernelEvaluations)
SkBitmap CreateCircleProfile(float sigma, float radius, int profileWidth)
static void apply_kernel_in_y(float *results, int numSteps, float firstX, float circleR, int halfKernelSize, const float *summedHalfKernelTable)
int BlurSigmaRadius(float sigma)
static uint8_t eval_V(float top, int y, const uint8_t *integral, int integralSize, float sixSigma)
constexpr int BlurKernelWidth(int radius)
static void make_half_kernel_and_summed_table(float *halfKernel, float *summedHalfKernel, int halfKernelSize, float sigma)
SkBitmap CreateHalfPlaneProfile(int profileWidth)
static float make_unnormalized_half_kernel(float *halfKernel, int halfKernelSize, float sigma)
SkBitmap CreateIntegralTable(int width)
SIN Vec< N, float > ceil(const Vec< N, float > &x)
constexpr int32_t width() const
constexpr int32_t height() const
static SkImageInfo MakeA8(int width, int height)
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
SkScalar fTop
smaller y-axis bounds