40#define STROKE_WIDTH SkIntToScalar(10)
102 center0, (pts[1].fX - pts[0].fX) / 2,
103 colors,
pos, std::size(colors), tm,
132 SkRect r = { 0, 0, 100, 50 };
135 for (
size_t s = 0;
s < std::size(scales); ++
s) {
137 for (
size_t f = 0; f < std::size(fMaskFilters); ++f) {
139 paint.setMaskFilter(fMaskFilters[f]);
140 paint.setAlpha(fAlpha);
145 constexpr Proc procs[] = {
150 canvas->
scale(scales[
s], scales[
s]);
151 this->drawProcs(canvas, r,
paint,
false, procs, std::size(procs));
153 this->drawProcs(canvas, r, paintWithRadial,
false, procs, std::size(procs));
155 this->drawProcs(canvas, r,
paint,
true, procs, std::size(procs));
157 this->drawProcs(canvas, r, paintWithRadial,
true, procs, std::size(procs));
168 bool doClip,
const Proc procs[],
size_t procsCount) {
170 for (
size_t i = 0; i < procsCount; ++i) {
177 procs[i](canvas, r,
paint);
181 canvas->translate(0, r.height() * 4/3);
187 const int fGMWidth = 1200;
188 const int fPadding = 10;
189 const int fMargin = 100;
191 const int widths[] = {25, 5, 5, 100, 150, 25};
192 const int heights[] = {100, 100, 5, 25, 150, 25};
194 const float radii[] = {20, 5, 10};
196 canvas->translate(50,20);
203 for (
size_t i = 0 ; i < std::size(
widths) ; i++) {
210 for (
size_t j = 0 ; j < std::size(radii) ; j++) {
211 float radius = radii[j];
212 for (
size_t k = 0 ; k < std::size(styles) ; k++) {
226 if (cur_x + bm.
width() >= fGMWidth - fMargin) {
228 cur_y += max_height + fPadding;
235 canvas->drawImage(bm.
asImage(), 0.f, 0.f);
238 cur_x += bm.
width() + fPadding;
239 if (bm.
height() > max_height)
249class BlurRectCompareGM :
public GM {
253 SkISize getISize()
override {
return {900, 1220}; }
255 void onOnceBeforeDraw()
override { this->prepareReferenceMasks(); }
260 *errorMsg =
"Not supported when recording, relies on canvas->makeSurface()";
265 if (fRecalcMasksForAnimation || !fActualMasks[0][0][0] || ctxID != fLastContextUniqueID) {
266 if (fRecalcMasksForAnimation) {
268 this->prepareReferenceMasks();
270 this->prepareActualMasks(canvas);
271 this->prepareMaskDifferences(canvas);
272 fLastContextUniqueID = ctxID;
273 fRecalcMasksForAnimation =
false;
276 static constexpr float kMargin = 30;
278 for (
auto w : kSizes) {
282 for (
int mode = 0;
mode < 3; ++
mode) {
284 for (
size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
285 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
286 for (
size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
287 auto h = kSizes[heightIdx];
289 for (
size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
290 auto w = kSizes[widthIdx];
296 img = fReferenceMasks[sigmaIdx][heightIdx][widthIdx].get();
299 img = fActualMasks[sigmaIdx][heightIdx][widthIdx].get();
302 img = fMaskDifferences[sigmaIdx][heightIdx][widthIdx].get();
308 auto pad = PadForSigma(sigma);
330 bool onAnimate(
double nanos)
override {
332 fRecalcMasksForAnimation =
true;
337 void prepareReferenceMasks() {
338 auto create_reference_mask = [](
int w,
int h,
float sigma,
int numSubpixels) {
339 int pad = PadForSigma(sigma);
340 int maskW =
w + 2 * pad;
341 int maskH =
h + 2 * pad;
345 sigma *= numSubpixels;
347 auto def_integral_approx = [
scale](
float a,
float b) {
348 return 0.5f * (std::erf(
b *
scale) - std::erf(
a *
scale));
353 std::unique_ptr<float[]> row(
new float[maskW * numSubpixels]);
354 for (
int col = 0; col < maskW * numSubpixels; ++col) {
356 float ldiff = numSubpixels * pad - (col + 0.5f);
357 float rdiff = ldiff +
w;
358 row[col] = def_integral_approx(ldiff, rdiff);
363 std::unique_ptr<float[]> accums(
new float[maskW]);
364 const float accumScale = 1.f / (numSubpixels * numSubpixels);
365 for (
int y = 0;
y < maskH; ++
y) {
367 std::fill_n(accums.get(), maskW, 0);
368 for (
int ys = 0; ys < numSubpixels; ++ys) {
374 float tdiff = numSubpixels * pad - (
y * numSubpixels + ys + 0.5f);
375 float bdiff = tdiff +
h;
376 auto integral = def_integral_approx(tdiff, bdiff);
377 for (
int x = 0;
x < maskW; ++
x) {
378 for (
int xs = 0; xs < numSubpixels; ++xs) {
379 int rowIdx =
x * numSubpixels + xs;
380 accums[
x] += integral * row[rowIdx];
384 for (
int x = 0;
x < maskW; ++
x) {
385 auto result = accums[
x] * accumScale;
394 const int numSubpixels = fRecalcMasksForAnimation ? 2 : 8;
396 for (
size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
397 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
398 for (
size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
399 auto h = kSizes[heightIdx];
400 for (
size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
401 auto w = kSizes[widthIdx];
402 fReferenceMasks[sigmaIdx][heightIdx][widthIdx] =
403 create_reference_mask(
w,
h, sigma, numSubpixels);
409 void prepareActualMasks(
SkCanvas* canvas) {
410 for (
size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
411 auto sigma = kSigmas[sigmaIdx] + fSigmaAnimationBoost;
412 for (
size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
413 auto h = kSizes[heightIdx];
414 for (
size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
415 auto w = kSizes[widthIdx];
416 auto pad = PadForSigma(sigma);
432 surf->getCanvas()->drawRect(rect,
paint);
433 fActualMasks[sigmaIdx][heightIdx][widthIdx] = surf->makeImageSnapshot();
439 void prepareMaskDifferences(
SkCanvas* canvas) {
440 for (
size_t sigmaIdx = 0; sigmaIdx < kNumSigmas; ++sigmaIdx) {
441 for (
size_t heightIdx = 0; heightIdx < kNumSizes; ++heightIdx) {
442 for (
size_t widthIdx = 0; widthIdx < kNumSizes; ++widthIdx) {
443 const auto& r = fReferenceMasks[sigmaIdx][heightIdx][widthIdx];
444 const auto&
a = fActualMasks[sigmaIdx][heightIdx][widthIdx];
445 auto&
d = fMaskDifferences[sigmaIdx][heightIdx][widthIdx];
465 static constexpr float kGreenifyM[] = {0, 0, 0, 0, 0,
472 paint.setColorFilter(std::move(greenifyCF));
476 d = surf->makeImageSnapshot();
486 inline static constexpr int kSizes[] = {1, 2, 4, 8, 16, 32};
487 inline static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
488 inline static constexpr size_t kNumSizes = std::size(kSizes);
489 inline static constexpr size_t kNumSigmas = std::size(kSigmas);
493 sk_sp<SkImage> fMaskDifferences[kNumSigmas][kNumSizes][kNumSizes];
494 int32_t fLastContextUniqueID;
496 float fSigmaAnimationBoost = 0;
497 bool fRecalcMasksForAnimation =
false;
505DEF_GM(
return new skiagm::BlurRectCompareGM();)
511 static constexpr float kSigmas[] = {0.5f, 1.2f, 2.3f, 3.9f, 7.4f};
512 static constexpr size_t kNumSigmas = std::size(kSigmas);
516 std::vector<SkMatrix> matrices;
523 matrices.back().preScale(1.1f, .5f);
526 matrices.back().preScale(3.f, .1f);
535 matrices.back().
preSkew(.3f, -.5f);
538 for (
const auto& m : matrices) {
540 m.mapRect(&mapped,
kRect);
543 float blurPad = 2.f*kSigmas[kNumSigmas - 1];
544 bounds.outset(blurPad, blurPad);
545 canvas->
translate(-bounds.left(), -bounds.top());
546 for (
auto sigma : kSigmas) {
550 for (
const auto& m : matrices) {
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
static unsigned mirror(SkFixed fx, int max)
@ kDifference
rc = s + d - 2*(min(s*da, d*sa)), ra = kSrcOver
@ kOuter_SkBlurStyle
nothing inside, fuzzy outside
@ kInner_SkBlurStyle
fuzzy inside, nothing outside
@ kNormal_SkBlurStyle
fuzzy inside and outside
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
@ kUnknown_SkColorType
uninitialized
constexpr SkColor SK_ColorRED
constexpr SkColor SK_ColorBLACK
constexpr SkColor SK_ColorGREEN
constexpr SkColor SK_ColorWHITE
#define sk_float_ceil2int(x)
#define sk_float_round2int(x)
std::unique_ptr< uint8_t, SkFunctionObject< SkMaskBuilder::FreeImage > > SkAutoMaskFreeImage
#define SkScalarAve(a, b)
static SkScalar SkScalarInterp(SkScalar A, SkScalar B, SkScalar t)
#define SK_ScalarRoot2Over2
constexpr uint8_t SkToU8(S x)
static void draw_donut(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
static void draw_donut_skewed(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
static void fill_rect(SkCanvas *canvas, const SkRect &r, const SkPaint &p)
void(* PaintProc)(SkPaint *, SkScalar width)
static sk_sp< SkShader > make_radial()
void(* Proc)(SkCanvas *, const SkRect &, const SkPaint &)
BlurRectGM(const char name[], U8CPU alpha)
void onDraw(SkCanvas *canvas) override
SkString getName() const override
void onOnceBeforeDraw() override
SkISize getISize() override
uint32_t contextID() const
virtual GrDirectContext * asDirectContext()
GrRecordingContextPriv priv()
bool installMaskPixels(SkMaskBuilder &mask)
void allocPixels(const SkImageInfo &info, size_t rowBytes)
sk_sp< SkImage > asImage() const
uint8_t * getAddr8(int x, int y) const
static bool BlurRect(SkScalar sigma, SkMaskBuilder *dst, const SkRect &src, SkBlurStyle, SkIPoint *margin=nullptr, SkMaskBuilder::CreateMode createMode=SkMaskBuilder::kComputeBoundsAndRenderImage_CreateMode)
static SkScalar SK_SPI ConvertRadiusToSigma(SkScalar radius)
void drawRect(const SkRect &rect, const SkPaint &paint)
void clipRect(const SkRect &rect, SkClipOp op, bool doAntiAlias)
void translate(SkScalar dx, SkScalar dy)
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
virtual GrRecordingContext * recordingContext() const
void clear(SkColor color)
void drawPath(const SkPath &path, const SkPaint &paint)
void scale(SkScalar sx, SkScalar sy)
void concat(const SkMatrix &matrix)
SkImageInfo imageInfo() const
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
static sk_sp< SkColorFilter > Matrix(const SkColorMatrix &)
static sk_sp< SkShader > MakeTwoPointConical(const SkPoint &start, SkScalar startRadius, const SkPoint &end, SkScalar endRadius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkMaskFilter > MakeBlur(SkBlurStyle style, SkScalar sigma, bool respectCTM=true)
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
SkMatrix & preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py)
static SkMatrix RotateDeg(SkScalar deg)
SkMatrix & setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar persp0, SkScalar persp1, SkScalar persp2)
static SkMatrix Concat(const SkMatrix &a, const SkMatrix &b)
SkMatrix & setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py)
void setStyle(Style style)
void setColor(SkColor color)
@ kStroke_Style
set to stroke geometry
void setShader(sk_sp< SkShader > shader)
void setStrokeWidth(SkScalar width)
skiagm::DrawResult DrawResult
virtual void onDraw(SkCanvas *)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
#define DEF_SIMPLE_GM(NAME, CANVAS, W, H)
sk_sp< SkBlender > blender SkRect rect
static float SineWave(double time, float periodInSecs, float phaseInSecs, float min, float max)
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive mode
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
static SkImageInfo MakeA8(int width, int height)
void set(float x, float y)
SkRect makeSorted() const
static constexpr SkRect MakeEmpty()
void setWH(float width, float height)
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
constexpr float centerX() const
constexpr float height() const
constexpr float centerY() const
constexpr float width() const
static constexpr SkRect MakeWH(float w, float h)