Flutter Engine
The Flutter Engine
runtimeshader.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "gm/gm.h"
11#include "include/core/SkData.h"
14#include "include/core/SkSize.h"
21#include "src/base/SkRandom.h"
24#include "tools/DecodeUtils.h"
25#include "tools/Resources.h"
26#include "tools/ToolUtils.h"
27
32};
33
35public:
36 RuntimeShaderGM(const char* name, SkISize size, const char* sksl, uint32_t flags = 0)
37 : fName(name), fSize(size), fFlags(flags), fSkSL(sksl) {}
38
39 void onOnceBeforeDraw() override {
40 auto [effect, error] = (fFlags & kColorFilter_RTFlag)
43 if (!effect) {
44 SkDebugf("RuntimeShader error: %s\n", error.c_str());
45 }
46 fEffect = std::move(effect);
47 }
48
49 bool runAsBench() const override { return SkToBool(fFlags & kBench_RTFlag); }
50 SkString getName() const override { return fName; }
51 SkISize getISize() override { return fSize; }
52
53 bool onAnimate(double nanos) override {
54 fSecs = nanos / (1000 * 1000 * 1000);
56 }
57
58protected:
61 uint32_t fFlags;
62 float fSecs = 0.0f;
63
66};
67
68class SimpleRT : public RuntimeShaderGM {
69public:
70 SimpleRT() : RuntimeShaderGM("runtime_shader", {512, 256}, R"(
71 uniform half4 gColor;
72
73 half4 main(float2 p) {
74 return half4(p*(1.0/255), gColor.b, 1);
75 }
76 )", kBench_RTFlag) {}
77
78 void onDraw(SkCanvas* canvas) override {
80
81 SkMatrix localM;
82 localM.setRotate(90, 128, 128);
83 builder.uniform("gColor") = SkColor4f{1, 0, 0, 1};
84
85 SkPaint p;
86 p.setShader(builder.makeShader(&localM));
87 canvas->drawRect({0, 0, 256, 256}, p);
88 }
89};
90DEF_GM(return new SimpleRT;)
91
93 SkMatrix scale = SkMatrix::Scale(size.width() / (float)img->width(),
94 size.height() / (float)img->height());
95 return img->makeShader(SkSamplingOptions(), scale);
96}
97
99 auto info = SkImageInfo::Make(size.width(), size.height(), kAlpha_8_SkColorType,
101 auto surf = SkSurfaces::Raster(info);
102 auto canvas = surf->getCanvas();
103
104 const SkScalar rad = 50;
107 paint.setAntiAlias(true);
108 paint.setShader(SkGradientShader::MakeRadial({0,0}, rad, colors, nullptr, 2, SkTileMode::kClamp));
109
110 SkPaint layerPaint;
111 const SkScalar sigma = 16.0f;
112 layerPaint.setImageFilter(SkImageFilters::Blur(sigma, sigma, nullptr));
113 canvas->saveLayer(nullptr, &layerPaint);
114
115 SkRandom rand;
116 for (int i = 0; i < 25; ++i) {
117 SkScalar x = rand.nextF() * size.width();
118 SkScalar y = rand.nextF() * size.height();
119 canvas->save();
120 canvas->translate(x, y);
121 canvas->drawCircle(0, 0, rad, paint);
122 canvas->restore();
123 }
124
125 canvas->restore(); // apply the blur
126
127 return surf->makeImageSnapshot()->makeShader(SkSamplingOptions());
128}
129
131public:
132 ThresholdRT() : RuntimeShaderGM("threshold_rt", {256, 256}, R"(
133 uniform shader before_map;
134 uniform shader after_map;
135 uniform shader threshold_map;
136
137 uniform float cutoff;
138 uniform float slope;
139
140 float smooth_cutoff(float x) {
141 x = x * slope + (0.5 - slope * cutoff);
142 return clamp(x, 0, 1);
143 }
144
145 half4 main(float2 xy) {
146 half4 before = before_map.eval(xy);
147 half4 after = after_map.eval(xy);
148
149 float m = smooth_cutoff(threshold_map.eval(xy).a);
150 return mix(before, after, m);
151 }
153
155
156 void onOnceBeforeDraw() override {
157 const SkISize size = {256, 256};
159 fBefore = make_shader(ToolUtils::GetResourceAsImage("images/mandrill_256.png"), size);
161
163 }
164
165 void onDraw(SkCanvas* canvas) override {
167
168 builder.uniform("cutoff") = sinf(fSecs) * 0.55f + 0.5f;
169 builder.uniform("slope") = 10.0f;
170
171 builder.child("before_map") = fBefore;
172 builder.child("after_map") = fAfter;
173 builder.child("threshold_map") = fThreshold;
174
176 paint.setShader(builder.makeShader());
177 canvas->drawRect({0, 0, 256, 256}, paint);
178
179 auto draw = [&](SkScalar x, SkScalar y, sk_sp<SkShader> shader) {
180 paint.setShader(shader);
181 canvas->save();
182 canvas->translate(x, y);
183 canvas->drawRect({0, 0, 256, 256}, paint);
184 canvas->restore();
185 };
186 draw(256, 0, fThreshold);
187 draw( 0, 256, fBefore);
188 draw(256, 256, fAfter);
189 }
190};
191DEF_GM(return new ThresholdRT;)
192
193class SpiralRT : public RuntimeShaderGM {
194public:
195 SpiralRT() : RuntimeShaderGM("spiral_rt", {512, 512}, R"(
196 uniform float rad_scale;
197 uniform float2 in_center;
198 layout(color) uniform float4 in_colors0;
199 layout(color) uniform float4 in_colors1;
200
201 half4 main(float2 p) {
202 float2 pp = p - in_center;
203 float radius = length(pp);
204 radius = sqrt(radius);
205 float angle = atan(pp.y / pp.x);
206 float t = (angle + 3.1415926/2) / (3.1415926);
207 t += radius * rad_scale;
208 t = fract(t);
209 return in_colors0 * (1-t) + in_colors1 * t;
210 }
212
213 void onDraw(SkCanvas* canvas) override {
215
216 builder.uniform("rad_scale") = std::sin(fSecs * 0.5f + 2.0f) / 5;
217 builder.uniform("in_center") = SkV2{256, 256};
218 builder.uniform("in_colors0") = SkColors::kRed;
219 builder.uniform("in_colors1") = SkColors::kGreen;
220
222 paint.setShader(builder.makeShader());
223 canvas->drawRect({0, 0, 512, 512}, paint);
224 }
225};
226DEF_GM(return new SpiralRT;)
227
228// Test case for sampling with both unmodified input coordinates, and explicit coordinates.
229// The first version of skbug.com/11869 suffered a bug where all samples of a child were treated
230// as pass-through if *at least one* used the unmodified coordinates. This was detected & tracked
231// in b/181092919. This GM is similar, and demonstrates the bug before the fix was applied.
233public:
234 UnsharpRT() : RuntimeShaderGM("unsharp_rt", {512, 256}, R"(
235 uniform shader child;
236 half4 main(float2 xy) {
237 half4 c = child.eval(xy) * 5;
238 c -= child.eval(xy + float2( 1, 0));
239 c -= child.eval(xy + float2(-1, 0));
240 c -= child.eval(xy + float2( 0, 1));
241 c -= child.eval(xy + float2( 0, -1));
242 return c;
243 }
244 )") {}
245
247
248 void onOnceBeforeDraw() override {
249 fMandrill = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
251 }
252
253 void onDraw(SkCanvas* canvas) override {
254 // First we draw the unmodified image
255 canvas->drawImage(fMandrill, 0, 0);
256
257 // Now draw the image with our unsharp mask applied
260 builder.child("child") = fMandrill->makeShader(sampling);
261
263 paint.setShader(builder.makeShader());
264 canvas->translate(256, 0);
265 canvas->drawRect({ 0, 0, 256, 256 }, paint);
266 }
267};
268DEF_GM(return new UnsharpRT;)
269
271public:
272 ColorCubeRT() : RuntimeShaderGM("color_cube_rt", {512, 512}, R"(
273 uniform shader child;
274 uniform shader color_cube;
275
276 uniform float rg_scale;
277 uniform float rg_bias;
278 uniform float b_scale;
279 uniform float inv_size;
280
281 half4 main(float2 xy) {
282 float4 c = unpremul(child.eval(xy));
283
284 // Map to cube coords:
285 float3 cubeCoords = float3(c.rg * rg_scale + rg_bias, c.b * b_scale);
286
287 // Compute slice coordinate
288 float2 coords1 = float2((floor(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
289 float2 coords2 = float2(( ceil(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
290
291 // Two bilinear fetches, plus a manual lerp for the third axis:
292 half4 color = mix(color_cube.eval(coords1), color_cube.eval(coords2),
293 fract(cubeCoords.b));
294
295 // Premul again
296 color.rgb *= color.a;
297
298 return color;
299 }
300 )") {}
301
302 sk_sp<SkImage> fMandrill, fMandrillSepia, fIdentityCube, fSepiaCube;
303
304 void onOnceBeforeDraw() override {
305 fMandrill = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
306 fMandrillSepia = ToolUtils::GetResourceAsImage("images/mandrill_sepia.png");
307 fIdentityCube = ToolUtils::GetResourceAsImage("images/lut_identity.png");
308 fSepiaCube = ToolUtils::GetResourceAsImage("images/lut_sepia.png");
309
311 }
312
313 void onDraw(SkCanvas* canvas) override {
315
316 // First we draw the unmodified image, and a copy that was sepia-toned in Photoshop:
317 canvas->drawImage(fMandrill, 0, 0);
318 canvas->drawImage(fMandrillSepia, 0, 256);
319
320 // LUT dimensions should be (kSize^2, kSize)
321 constexpr float kSize = 16.0f;
322
324
325 builder.uniform("rg_scale") = (kSize - 1) / kSize;
326 builder.uniform("rg_bias") = 0.5f / kSize;
327 builder.uniform("b_scale") = kSize - 1;
328 builder.uniform("inv_size") = 1.0f / kSize;
329
330 builder.child("child") = fMandrill->makeShader(sampling);
331
333
334 // TODO: Should we add SkImage::makeNormalizedShader() to handle this automatically?
335 SkMatrix normalize = SkMatrix::Scale(1.0f / (kSize * kSize), 1.0f / kSize);
336
337 // Now draw the image with an identity color cube - it should look like the original
338 builder.child("color_cube") = fIdentityCube->makeShader(sampling, normalize);
339 paint.setShader(builder.makeShader());
340 canvas->translate(256, 0);
341 canvas->drawRect({ 0, 0, 256, 256 }, paint);
342
343 // ... and with a sepia-tone color cube. This should match the sepia-toned image.
344 builder.child("color_cube") = fSepiaCube->makeShader(sampling, normalize);
345 paint.setShader(builder.makeShader());
346 canvas->translate(0, 256);
347 canvas->drawRect({ 0, 0, 256, 256 }, paint);
348 }
349};
350DEF_GM(return new ColorCubeRT;)
351
352// Same as above, but demonstrating how to implement this as a runtime color filter (that samples
353// a shader child for the LUT).
355public:
356 ColorCubeColorFilterRT() : RuntimeShaderGM("color_cube_cf_rt", {512, 512}, R"(
357 uniform shader color_cube;
358
359 uniform float rg_scale;
360 uniform float rg_bias;
361 uniform float b_scale;
362 uniform float inv_size;
363
364 half4 main(half4 inColor) {
365 float4 c = unpremul(inColor);
366
367 // Map to cube coords:
368 float3 cubeCoords = float3(c.rg * rg_scale + rg_bias, c.b * b_scale);
369
370 // Compute slice coordinate
371 float2 coords1 = float2((floor(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
372 float2 coords2 = float2(( ceil(cubeCoords.b) + cubeCoords.r) * inv_size, cubeCoords.g);
373
374 // Two bilinear fetches, plus a manual lerp for the third axis:
375 half4 color = mix(color_cube.eval(coords1), color_cube.eval(coords2),
376 fract(cubeCoords.b));
377
378 // Premul again
379 color.rgb *= color.a;
380
381 return color;
382 }
383 )", kColorFilter_RTFlag) {}
384
385 sk_sp<SkImage> fMandrill, fMandrillSepia, fIdentityCube, fSepiaCube;
386
387 void onOnceBeforeDraw() override {
388 fMandrill = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
389 fMandrillSepia = ToolUtils::GetResourceAsImage("images/mandrill_sepia.png");
390 fIdentityCube = ToolUtils::GetResourceAsImage("images/lut_identity.png");
391 fSepiaCube = ToolUtils::GetResourceAsImage("images/lut_sepia.png");
392
394 }
395
396 void onDraw(SkCanvas* canvas) override {
398
399 // First we draw the unmodified image, and a copy that was sepia-toned in Photoshop:
400 canvas->drawImage(fMandrill, 0, 0);
401 canvas->drawImage(fMandrillSepia, 0, 256);
402
403 // LUT dimensions should be (kSize^2, kSize)
404 constexpr float kSize = 16.0f;
405
407
408 builder.uniform("rg_scale") = (kSize - 1) / kSize;
409 builder.uniform("rg_bias") = 0.5f / kSize;
410 builder.uniform("b_scale") = kSize - 1;
411 builder.uniform("inv_size") = 1.0f / kSize;
412
414
415 // TODO: Should we add SkImage::makeNormalizedShader() to handle this automatically?
416 SkMatrix normalize = SkMatrix::Scale(1.0f / (kSize * kSize), 1.0f / kSize);
417
418 // Now draw the image with an identity color cube - it should look like the original
419 builder.child("color_cube") = fIdentityCube->makeShader(sampling, normalize);
420
421 paint.setColorFilter(builder.makeColorFilter());
422 canvas->drawImage(fMandrill, 256, 0, sampling, &paint);
423
424 // ... and with a sepia-tone color cube. This should match the sepia-toned image.
425 builder.child("color_cube") = fSepiaCube->makeShader(sampling, normalize);
426
427 paint.setColorFilter(builder.makeColorFilter());
428 canvas->drawImage(fMandrill, 256, 256, sampling, &paint);
429 }
430};
432
433// Emits coverage for a rounded rectangle whose corners are superellipses defined by the boundary:
434//
435// x^n + y^n == 1
436//
437// Where x and y are normalized, clamped coordinates ranging from 0..1 inside the nearest corner's
438// bounding box.
439//
440// See: https://en.wikipedia.org/wiki/Superellipse
442public:
443 ClipSuperRRect(const char* name, float power) : RuntimeShaderGM(name, {500, 500}, R"(
444 uniform float power_minus1;
445 uniform float2 stretch_factor;
446 uniform float2x2 derivatives;
447 half4 main(float2 xy) {
448 xy = max(abs(xy) + stretch_factor, 0);
449 float2 exp_minus1 = pow(xy, power_minus1.xx); // If power == 3.5: xy * xy * sqrt(xy)
450 float f = dot(exp_minus1, xy) - 1; // f = x^n + y^n - 1
451 float2 grad = exp_minus1 * derivatives;
452 float fwidth = abs(grad.x) + abs(grad.y) + 1e-12; // 1e-12 to avoid a divide by zero.
453 return half4(saturate(.5 - f/fwidth)); // Approx coverage by riding the gradient to f=0.
454 }
455 )"), fPower(power) {}
456
457 void drawSuperRRect(SkCanvas* canvas, const SkRect& superRRect, float radX, float radY,
458 SkColor color) {
460 paint.setColor(color);
461
462 if (fPower == 2) {
463 // Draw a normal round rect for the sake of testing.
464 SkRRect rrect = SkRRect::MakeRectXY(superRRect, radX, radY);
465 paint.setAntiAlias(true);
466 canvas->drawRRect(rrect, paint);
467 return;
468 }
469
471 builder.uniform("power_minus1") = fPower - 1;
472
473 // Size the corners such that the "apex" of our "super" rounded corner is in the same
474 // location that the apex of a circular rounded corner would be with the given radii. We
475 // define the apex as the point on the rounded corner that is 45 degrees between the
476 // horizontal and vertical edges.
477 float scale = (1 - SK_ScalarRoot2Over2) / (1 - exp2f(-1/fPower));
478 float cornerWidth = radX * scale;
479 float cornerHeight = radY * scale;
480 cornerWidth = std::min(cornerWidth, superRRect.width() * .5f);
481 cornerHeight = std::min(cornerHeight, superRRect.height() * .5f);
482 // The stretch factor controls how long the flat edge should be between rounded corners.
483 builder.uniform("stretch_factor") = SkV2{1 - superRRect.width()*.5f / cornerWidth,
484 1 - superRRect.height()*.5f / cornerHeight};
485
486 // Calculate a 2x2 "derivatives" matrix that the shader will use to find the gradient.
487 //
488 // f = s^n + t^n - 1 [s,t are "super" rounded corner coords in normalized 0..1 space]
489 //
490 // gradient = [df/dx df/dy] = [ns^(n-1) nt^(n-1)] * |ds/dx ds/dy|
491 // |dt/dx dt/dy|
492 //
493 // = [s^(n-1) t^(n-1)] * |n 0| * |ds/dx ds/dy|
494 // |0 n| |dt/dx dt/dy|
495 //
496 // = [s^(n-1) t^(n-1)] * |2n/cornerWidth 0| * mat2x2(canvasMatrix)^-1
497 // |0 2n/cornerHeight|
498 //
499 // = [s^(n-1) t^(n-1)] * "derivatives"
500 //
501 const SkMatrix& M = canvas->getTotalMatrix();
502 float a=M.getScaleX(), b=M.getSkewX(), c=M.getSkewY(), d=M.getScaleY();
503 float determinant = a*d - b*c;
504 float dx = fPower / (cornerWidth * determinant);
505 float dy = fPower / (cornerHeight * determinant);
506 builder.uniform("derivatives") = SkV4{d*dx, -c*dy, -b*dx, a*dy};
507
508 // This matrix will be inverted by the effect system, giving a matrix that converts local
509 // coordinates to (almost) coner coordinates. To get the rest of the way to the nearest
510 // corner's space, the shader will have to take the absolute value, add the stretch_factor,
511 // then clamp above zero.
512 SkMatrix cornerToLocal;
513 cornerToLocal.setScaleTranslate(cornerWidth, cornerHeight, superRRect.centerX(),
514 superRRect.centerY());
515 canvas->clipShader(builder.makeShader(&cornerToLocal));
516
517 // Bloat the outer edges of the rect we will draw so it contains all the antialiased pixels.
518 // Bloat by a full pixel instead of half in case Skia is in a mode that draws this rect with
519 // unexpected AA of its own.
520 float inverseDet = 1 / fabsf(determinant);
521 float bloatX = (fabsf(d) + fabsf(c)) * inverseDet;
522 float bloatY = (fabsf(b) + fabsf(a)) * inverseDet;
523 canvas->drawRect(superRRect.makeOutset(bloatX, bloatY), paint);
524 }
525
526 void onDraw(SkCanvas* canvas) override {
527 SkRandom rand(2);
528
529 canvas->save();
530 canvas->translate(canvas->imageInfo().width() / 2.f, canvas->imageInfo().height() / 2.f);
531
532 canvas->save();
533 canvas->rotate(21);
534 this->drawSuperRRect(canvas, SkRect::MakeXYWH(-5, 25, 175, 100), 50, 30,
535 rand.nextU() | 0xff808080);
536 canvas->restore();
537
538 canvas->save();
539 canvas->rotate(94);
540 this->drawSuperRRect(canvas, SkRect::MakeXYWH(95, 75, 125, 100), 30, 30,
541 rand.nextU() | 0xff808080);
542 canvas->restore();
543
544 canvas->save();
545 canvas->rotate(132);
546 this->drawSuperRRect(canvas, SkRect::MakeXYWH(0, 75, 150, 100), 40, 30,
547 rand.nextU() | 0xff808080);
548 canvas->restore();
549
550 canvas->save();
551 canvas->rotate(282);
552 this->drawSuperRRect(canvas, SkRect::MakeXYWH(15, -20, 100, 100), 20, 20,
553 rand.nextU() | 0xff808080);
554 canvas->restore();
555
556 canvas->save();
557 canvas->rotate(0);
558 this->drawSuperRRect(canvas, SkRect::MakeXYWH(140, -50, 90, 110), 25, 25,
559 rand.nextU() | 0xff808080);
560 canvas->restore();
561
562 canvas->save();
563 canvas->rotate(-35);
564 this->drawSuperRRect(canvas, SkRect::MakeXYWH(160, -60, 60, 90), 18, 18,
565 rand.nextU() | 0xff808080);
566 canvas->restore();
567
568 canvas->save();
569 canvas->rotate(65);
570 this->drawSuperRRect(canvas, SkRect::MakeXYWH(220, -120, 60, 90), 18, 18,
571 rand.nextU() | 0xff808080);
572 canvas->restore();
573
574 canvas->save();
575 canvas->rotate(265);
576 this->drawSuperRRect(canvas, SkRect::MakeXYWH(150, -129, 80, 160), 24, 39,
577 rand.nextU() | 0xff808080);
578 canvas->restore();
579
580 canvas->restore();
581 }
582
583private:
584 const float fPower;
585};
586DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow2", 2);)
587// DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow3", 3);)
588DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow3.5", 3.5);)
589// DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow4", 4);)
590// DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow4.5", 4.5);)
591// DEF_GM(return new ClipSuperRRect("clip_super_rrect_pow5", 5);)
592
594public:
595 LinearGradientRT() : RuntimeShaderGM("linear_gradient_rt", {256 + 10, 128 + 15}, R"(
596 layout(color) uniform vec4 in_colors0;
597 layout(color) uniform vec4 in_colors1;
598
599 vec4 main(vec2 p) {
600 float t = p.x / 256;
601 if (p.y < 32) {
602 return mix(in_colors0, in_colors1, t);
603 } else {
604 vec3 linColor0 = toLinearSrgb(in_colors0.rgb);
605 vec3 linColor1 = toLinearSrgb(in_colors1.rgb);
606 vec3 linColor = mix(linColor0, linColor1, t);
607 return fromLinearSrgb(linColor).rgb1;
608 }
609 }
610 )") {}
611
612 void onDraw(SkCanvas* canvas) override {
613 // Colors chosen to use values other than 0 and 1 - so that it's obvious if the conversion
614 // intrinsics are doing anything. (Most transfer functions map 0 -> 0 and 1 -> 1).
616 builder.uniform("in_colors0") = SkColor4f{0.75f, 0.25f, 0.0f, 1.0f};
617 builder.uniform("in_colors1") = SkColor4f{0.0f, 0.75f, 0.25f, 1.0f};
619 paint.setShader(builder.makeShader());
620
621 canvas->save();
622 canvas->clear(SK_ColorWHITE);
623 canvas->translate(5, 5);
624
625 // We draw everything twice. First to a surface with no color management, where the
626 // intrinsics should do nothing (eg, the top bar should look the same in the top and bottom
627 // halves). Then to an sRGB surface, where they should produce linearly interpolated
628 // gradients (the bottom half of the second bar should be brighter than the top half).
629 for (auto cs : {static_cast<SkColorSpace*>(nullptr), sk_srgb_singleton()}) {
631 256, 64, kN32_SkColorType, kPremul_SkAlphaType, sk_ref_sp(cs));
632 auto surface = canvas->makeSurface(info);
633 if (!surface) {
635 }
636
637 surface->getCanvas()->drawRect({0, 0, 256, 64}, paint);
638 canvas->drawImage(surface->makeImageSnapshot(), 0, 0);
639 canvas->translate(0, 64 + 5);
640 }
641
642 canvas->restore();
643 }
644};
645DEF_GM(return new LinearGradientRT;)
646
647DEF_SIMPLE_GM(child_sampling_rt, canvas, 256,256) {
648 static constexpr char scale[] =
649 "uniform shader child;"
650 "half4 main(float2 xy) {"
651 " return child.eval(xy*0.1);"
652 "}";
653
654 SkPaint p;
655 p.setColor(SK_ColorRED);
656 p.setAntiAlias(true);
657 p.setStyle(SkPaint::kStroke_Style);
658 p.setStrokeWidth(1);
659
660 auto surf = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
661 surf->getCanvas()->drawLine(0, 0, 100, 100, p);
662 auto shader = surf->makeImageSnapshot()->makeShader(SkSamplingOptions(SkFilterMode::kLinear));
663
665 builder.child("child") = shader;
666 p.setShader(builder.makeShader());
667
668 canvas->drawPaint(p);
669}
670
672 // Produces a hemispherical normal:
673 static const char* kSrc = R"(
674 half4 main(vec2 p) {
675 p = (p / 256) * 2 - 1;
676 float p2 = dot(p, p);
677 vec3 v = (p2 > 1) ? vec3(0, 0, 1) : vec3(p, sqrt(1 - p2));
678 return (v * 0.5 + 0.5).xyz1;
679 }
680 )";
682 return effect->makeShader(nullptr, {});
683}
684
686 // Above, baked into an image:
687 auto info = SkImageInfo::Make(256, 256, kN32_SkColorType, kPremul_SkAlphaType);
689 SkPaint p;
690 p.setShader(normal_map_shader());
691 surface->getCanvas()->drawPaint(p);
692 return surface->makeImageSnapshot();
693}
694
697}
698
701}
702
704 auto image = normal_map_image();
705 SkPixmap pm;
707 SkBitmap bmp;
709 // Copy all pixels over, but set alpha to 0
710 for (int y = 0; y < pm.height(); y++) {
711 for (int x = 0; x < pm.width(); x++) {
712 *bmp.getAddr32(x, y) = *pm.addr32(x, y) & 0x00FFFFFF;
713 }
714 }
715 return bmp.asImage();
716}
717
720}
721
724}
725
727 // Simple N-dot-L against a fixed, directional light:
728 static const char* kSrc = R"(
729 uniform shader normals;
730 half4 main(vec2 p) {
731 vec3 n = normalize(normals.eval(p).xyz * 2 - 1);
732 vec3 l = normalize(vec3(1, -1, 1));
733 return saturate(dot(n, l)).xxx1;
734 }
735 )";
737 return effect->makeShader(/* uniforms= */ nullptr, &normals, /* childCount= */ 1);
738}
739
741 // Simple N-dot-L against a fixed, directional light, done in linear space:
742 static const char* kSrc = R"(
743 uniform shader normals;
744 half4 main(vec2 p) {
745 vec3 n = normalize(normals.eval(p).xyz * 2 - 1);
746 vec3 l = normalize(vec3(1, -1, 1));
747 return fromLinearSrgb(saturate(dot(n, l)).xxx).xxx1;
748 }
749 )";
751 return effect->makeShader(/* uniforms= */ nullptr, &normals, /* childCount= */ 1);
752}
753
754DEF_SIMPLE_GM(paint_alpha_normals_rt, canvas, 512,512) {
755 // Various draws, with non-opaque paint alpha. This demonstrates several issues around how
756 // paint alpha is applied differently on CPU (globally, after all shaders) and GPU (per shader,
757 // inconsistently). See: skbug.com/11942
758 //
759 // When this works, it will be a demo of applying paint alpha to fade out a complex effect.
760 auto draw_shader = [=](int x, int y, sk_sp<SkShader> shader) {
761 SkPaint p;
762 p.setAlpha(164);
763 p.setShader(shader);
764
765 canvas->save();
766 canvas->translate(x, y);
767 canvas->clipRect({0, 0, 256, 256});
768 canvas->drawPaint(p);
769 canvas->restore();
770 };
771
774
777}
778
779DEF_SIMPLE_GM(raw_image_shader_normals_rt, canvas, 768, 512) {
780 // Demonstrates the utility of SkImage::makeRawShader, for non-color child shaders.
781
782 // First, make an offscreen surface, so we can control the destination color space:
783 auto surfInfo = SkImageInfo::Make(512, 512,
784 kN32_SkColorType,
786 SkColorSpace::MakeSRGB()->makeColorSpin());
787 auto surface = canvas->makeSurface(surfInfo);
788 if (!surface) {
789 surface = SkSurfaces::Raster(surfInfo);
790 }
791
792 auto draw_shader = [](int x, int y, sk_sp<SkShader> shader, SkCanvas* canvas) {
793 SkPaint p;
794 p.setShader(shader);
795
796 canvas->save();
797 canvas->translate(x, y);
798 canvas->clipRect({0, 0, 256, 256});
799 canvas->drawPaint(p);
800 canvas->restore();
801 };
802
804 rawNormals = normal_map_raw_image_shader();
805
806 // Draw our normal map as colors (will be color-rotated), and raw (untransformed)
807 draw_shader(0, 0, colorNormals, surface->getCanvas());
808 draw_shader(0, 256, rawNormals, surface->getCanvas());
809
810 // Now draw our lighting shader using the normal and raw versions of the normals as children.
811 // The top image will have the normals rotated (incorrectly), so the lighting is very dark.
812 draw_shader(256, 0, lit_shader(colorNormals), surface->getCanvas());
813 draw_shader(256, 256, lit_shader(rawNormals), surface->getCanvas());
814
815 // Now draw the offscreen surface back to our original canvas. If we do this naively, the image
816 // will be un-transformed back to the canvas' color space. That will have the effect of undoing
817 // the color spin on the upper-left, and APPLYING a color-spin on the bottom left. To preserve
818 // the intent of this GM (and make it draw consistently whether or not the original surface has
819 // a color space attached), we reinterpret the offscreen image as being in sRGB:
820 canvas->drawImage(
821 surface->makeImageSnapshot()->reinterpretColorSpace(SkColorSpace::MakeSRGB()), 0, 0);
822
823 // Finally, to demonstrate that raw unpremul image shaders don't premul, draw lighting two more
824 // times, with an unpremul normal map (containing ZERO in the alpha channel). THe top will
825 // premultiply the normals, resulting in totally dark lighting. The bottom will retain the RGB
826 // encoded normals, even with zero alpha:
829}
830
831DEF_SIMPLE_GM(lit_shader_linear_rt, canvas, 512, 256) {
832 // First, make an offscreen surface, so we can control the destination color space:
833 auto surfInfo = SkImageInfo::Make(512, 256,
834 kN32_SkColorType,
837 auto surface = canvas->makeSurface(surfInfo);
838 if (!surface) {
839 surface = SkSurfaces::Raster(surfInfo);
840 }
841
842 auto draw_shader = [](int x, int y, sk_sp<SkShader> shader, SkCanvas* canvas) {
843 SkPaint p;
844 p.setShader(shader);
845
846 canvas->save();
847 canvas->translate(x, y);
848 canvas->clipRect({0, 0, 256, 256});
849 canvas->drawPaint(p);
850 canvas->restore();
851 };
852
853 // We draw two lit spheres - one does math in the working space (so gamma-encoded). The second
854 // works in linear space, then converts to sRGB. This produces (more accurate) sharp falloff:
855 draw_shader(0, 0, lit_shader(normal_map_shader()), surface->getCanvas());
856 draw_shader(256, 0, lit_shader_linear(normal_map_shader()), surface->getCanvas());
857
858 // Now draw the offscreen surface back to our original canvas:
859 canvas->drawImage(surface->makeImageSnapshot(), 0, 0);
860}
861
862// skbug.com/13598 GPU was double applying the local matrix.
863DEF_SIMPLE_GM(local_matrix_shader_rt, canvas, 256, 256) {
864 SkString passthrough(R"(
865 uniform shader s;
866 half4 main(float2 p) { return s.eval(p); }
867 )");
868 auto [rte, error] = SkRuntimeEffect::MakeForShader(passthrough, {});
869 if (!rte) {
870 SkDebugf("%s\n", error.c_str());
871 return;
872 }
873
874 auto image = ToolUtils::GetResourceAsImage("images/mandrill_128.png");
875 auto imgShader = image->makeShader(SkFilterMode::kNearest);
876
877 auto r = SkRect::MakeWH(image->width(), image->height());
878
879 auto lm = SkMatrix::RotateDeg(90.f, {image->width()/2.f, image->height()/2.f});
880
882
883 // image
884 paint.setShader(imgShader);
885 canvas->drawRect(r, paint);
886
887 // passthrough(image)
888 canvas->save();
889 canvas->translate(image->width(), 0);
890 paint.setShader(rte->makeShader(/* uniforms= */ nullptr, &imgShader, /* childCount= */ 1));
891 canvas->drawRect(r, paint);
892 canvas->restore();
893
894 // localmatrix(image)
895 canvas->save();
896 canvas->translate(0, image->height());
897 paint.setShader(imgShader->makeWithLocalMatrix(lm));
898 canvas->drawRect(r, paint);
899 canvas->restore();
900
901 // localmatrix(passthrough(image)) This was the bug.
902 canvas->save();
903 canvas->translate(image->width(), image->height());
904 paint.setShader(rte->makeShader(/* uniforms= */ nullptr, &imgShader, /* childCount= */ 1)
905 ->makeWithLocalMatrix(lm));
906 canvas->drawRect(r, paint);
907 canvas->restore();
908}
909
910DEF_SIMPLE_GM(null_child_rt, canvas, 150, 100) {
911 using ChildPtr = SkRuntimeEffect::ChildPtr;
912
913 // Every swatch should evaluate to the same shade of purple.
914 // Paint with a shader evaluating a null shader.
915 // Point passed to eval() is ignored; transparent black is returned.
916 {
917 const SkString kEvalShader{R"(
918 uniform shader s;
919 half4 main(float2 p) { return s.eval(p) + half4(0.5, 0, 0.5, 1); }
920 )"};
921 auto [rtShader, error] = SkRuntimeEffect::MakeForShader(kEvalShader);
922 SkASSERT(rtShader);
923
925 ChildPtr children[1] = {ChildPtr{sk_sp<SkShader>{nullptr}}};
926 paint.setShader(rtShader->makeShader(/*uniforms=*/nullptr, children));
927 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00)); // green (ignored)
928 canvas->drawRect({0, 0, 48, 48}, paint);
929 canvas->translate(50, 0);
930 }
931 // Paint with a shader evaluating a null color filter.
932 // Color passed to eval() is returned; paint color is ignored.
933 {
934 const SkString kEvalColorFilter{R"(
935 uniform colorFilter cf;
936 half4 main(float2 p) { return cf.eval(half4(0.5, 0, 0.5, 1)); }
937 )"};
938 auto [rtShader, error] = SkRuntimeEffect::MakeForShader(kEvalColorFilter);
939 SkASSERT(rtShader);
940
942 ChildPtr children[1] = {ChildPtr{sk_sp<SkColorFilter>{nullptr}}};
943 paint.setShader(rtShader->makeShader(/*uniforms=*/nullptr, children));
944 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF)); // green (does not contribute)
945 canvas->drawRect({0, 0, 48, 48}, paint);
946 canvas->translate(50, 0);
947 }
948 // Paint with a shader evaluating a null blender.
949 // Colors passed to eval() are blended via src-over; paint color is ignored.
950 {
951 const SkString kEvalBlender{R"(
952 uniform blender b;
953 half4 main(float2 p) { return b.eval(half4(0.5, 0, 0, 0.5), half4(0, 0, 1, 1)); }
954 )"};
955 auto [rtShader, error] = SkRuntimeEffect::MakeForShader(kEvalBlender);
956 SkASSERT(rtShader);
957
959 ChildPtr children[1] = {ChildPtr{sk_sp<SkBlender>{nullptr}}};
960 paint.setShader(rtShader->makeShader(/*uniforms=*/nullptr, children));
961 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF)); // green (does not contribute)
962 canvas->drawRect({0, 0, 48, 48}, paint);
963 canvas->translate(50, 0);
964 }
965
966 canvas->translate(-150, 50);
967
968 // Paint with a color filter evaluating a null shader.
969 // Point passed to eval() is ignored; transparent black is returned.
970 {
971 const SkString kEvalShader{R"(
972 uniform shader s;
973 half4 main(half4 c) { return s.eval(float2(0)) + half4(0.5, 0, 0.5, 1); }
974 )"};
975 auto [rtFilter, error] = SkRuntimeEffect::MakeForColorFilter(kEvalShader);
976 SkASSERT(rtFilter);
977
979 ChildPtr children[1] = {ChildPtr{sk_sp<SkShader>{nullptr}}};
980 paint.setColorFilter(rtFilter->makeColorFilter(/*uniforms=*/nullptr, children));
981 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00)); // green (ignored)
982 canvas->drawRect({0, 0, 48, 48}, paint);
983 canvas->translate(50, 0);
984 }
985 // Paint with a color filter evaluating a null color filter.
986 // Color passed to eval() is returned; paint color is ignored.
987 {
988 const SkString kEvalColorFilter{R"(
989 uniform colorFilter cf;
990 half4 main(half4 c) { return cf.eval(half4(0.5, 0, 0.5, 1)); }
991 )"};
992 auto [rtFilter, error] = SkRuntimeEffect::MakeForColorFilter(kEvalColorFilter);
993 SkASSERT(rtFilter);
994
996 ChildPtr children[1] = {ChildPtr{sk_sp<SkColorFilter>{nullptr}}};
997 paint.setColorFilter(rtFilter->makeColorFilter(/*uniforms=*/nullptr, children));
998 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF)); // green (does not contribute)
999 canvas->drawRect({0, 0, 48, 48}, paint);
1000 canvas->translate(50, 0);
1001 }
1002 // Paint with a color filter evaluating a null blender.
1003 // Colors passed to eval() are blended via src-over; paint color is ignored.
1004 {
1005 const SkString kEvalBlender{R"(
1006 uniform blender b;
1007 half4 main(half4 c) { return b.eval(half4(0.5, 0, 0, 0.5), half4(0, 0, 1, 1)); }
1008 )"};
1009 auto [rtFilter, error] = SkRuntimeEffect::MakeForColorFilter(kEvalBlender);
1010 SkASSERT(rtFilter);
1011
1012 SkPaint paint;
1013 ChildPtr children[1] = {ChildPtr{sk_sp<SkBlender>{nullptr}}};
1014 paint.setColorFilter(rtFilter->makeColorFilter(/*uniforms=*/nullptr, children));
1015 paint.setColor(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF)); // green (does not contribute)
1016 canvas->drawRect({0, 0, 48, 48}, paint);
1017 canvas->translate(50, 0);
1018 }
1019}
1020
1021DEF_SIMPLE_GM_CAN_FAIL(deferred_shader_rt, canvas, errorMsg, 150, 50) {
1022 // Skip this GM on recording devices. It actually works okay on serialize-8888, but pic-8888
1023 // does not. Ultimately, behavior on CPU is potentially strange (especially with SkRP), because
1024 // SkRP will build the shader more than once per draw.
1025 if (canvas->imageInfo().colorType() == kUnknown_SkColorType) {
1027 }
1028
1029 const SkString kShader{R"(
1030 uniform half4 color;
1031 half4 main(float2 p) { return color; }
1032 )"};
1033 auto [effect, error] = SkRuntimeEffect::MakeForShader(kShader);
1034 SkASSERT(effect);
1035
1037 auto makeUniforms = [color](const SkRuntimeEffectPriv::UniformsCallbackContext&) mutable {
1038 auto result = SkData::MakeWithCopy(&color, sizeof(color));
1039 color = {color.fB, color.fR, color.fG, color.fA};
1040 return result;
1041 };
1042
1043 auto shader =
1044 SkRuntimeEffectPriv::MakeDeferredShader(effect.get(), makeUniforms, /*children=*/{});
1045 SkASSERT(shader);
1046
1047 SkPaint paint;
1048 paint.setShader(shader);
1049
1050 for (int i = 0; i < 3; ++i) {
1051 canvas->drawRect({0, 0, 50, 50}, paint);
1052 canvas->translate(50, 0);
1053 }
1054
1056}
1057
1059 SkBitmap bmp;
1063}
1064
1065DEF_SIMPLE_GM_CAN_FAIL(alpha_image_shader_rt, canvas, errorMsg, 350, 50) {
1066 if (!canvas->getSurface()) {
1067 // The only backend that really fails is DDL (because the color filter fails to evaluate on
1068 // the CPU when we do paint optimization). We can't identify DDL separate from other
1069 // recording backends, so skip this GM for all of them:
1070 *errorMsg = "Not supported in recording/DDL mode";
1072 }
1073
1074 // Skia typically applies the paint color (or input color, for more complex GPU-FP trees)
1075 // to alpha-only images. This is useful in trivial cases, but surprising and inconsistent in
1076 // more complex situations, especially when using SkSL.
1077 //
1078 // This GM checks that we suppress the paint-color tinting from SkSL, and always get {0,0,0,a}.
1080 auto paint_shader = paint_color_shader();
1081 SkRuntimeEffect::ChildPtr children[1] = { paint_shader };
1082
1083 SkPaint paint;
1084 paint.setColor({0.5f, 0, 0.5f, 1.0f});
1085
1086 auto rect = [&]() {
1087 canvas->drawRect({0, 0, 48, 48}, paint);
1088 canvas->translate(50, 0);
1089 };
1090
1091 // Two simple cases: just paint color, then the "paint color" shader.
1092 // These should both be PURPLE
1093 rect();
1094
1095 paint.setShader(paint_shader);
1096 rect();
1097
1098 // All remaining cases should be BLACK
1099
1100 // Shader that evaluates the "paint color" shader.
1101 // For color-filter and blender, we test them with and without an actual SkShader on the paint.
1102 // These should all be BLACK
1103 paint.setShader(
1104 SkRuntimeEffect::MakeForShader(SkString("uniform shader s;"
1105 "half4 main(float2 p) { return s.eval(p); }"))
1106 .effect->makeShader(/* uniforms= */ nullptr, children));
1107 rect();
1108
1109 // Color-filter that evaluates the "paint color" shader, with and without a shader on the paint
1110 paint.setShader(nullptr);
1112 SkString("uniform shader s;"
1113 "half4 main(half4 color) { return s.eval(float2(0)); }"))
1114 .effect->makeColorFilter(nullptr, children));
1115 rect();
1116
1117 paint.setShader(checkerboard);
1118 rect();
1119
1120 // Blender that evaluates the "paint color" shader, with and without a shader on the paint
1121 paint.setShader(nullptr);
1122 paint.setColorFilter(nullptr);
1123 paint.setBlender(
1125 SkString("uniform shader s;"
1126 "half4 main(half4 src, half4 dst) { return s.eval(float2(0)); }"))
1127 .effect->makeBlender(nullptr, children));
1128 rect();
1129
1130 paint.setShader(checkerboard);
1131 rect();
1132
1134}
static SkM44 normals(SkM44 m)
Definition: 3DSlide.cpp:78
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
SkAssertResult(font.textToGlyphs("Hello", 5, SkTextEncoding::kUTF8, glyphs, std::size(glyphs))==count)
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkColorSpace * sk_srgb_singleton()
@ kAlpha_8_SkColorType
pixel with alpha in 8-bit byte
Definition: SkColorType.h:21
@ kUnknown_SkColorType
uninitialized
Definition: SkColorType.h:20
uint32_t SkColor
Definition: SkColor.h:37
constexpr SkColor SK_ColorRED
Definition: SkColor.h:126
static constexpr SkColor SkColorSetARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
Definition: SkColor.h:49
constexpr SkColor SK_ColorBLACK
Definition: SkColor.h:103
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SK_ScalarRoot2Over2
Definition: SkScalar.h:23
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
void drawSuperRRect(SkCanvas *canvas, const SkRect &superRRect, float radX, float radY, SkColor color)
ClipSuperRRect(const char *name, float power)
void onDraw(SkCanvas *canvas) override
void onOnceBeforeDraw() override
sk_sp< SkImage > fIdentityCube
void onDraw(SkCanvas *canvas) override
void onDraw(SkCanvas *canvas) override
void onOnceBeforeDraw() override
sk_sp< SkImage > fIdentityCube
void onDraw(SkCanvas *canvas) override
SkISize getISize() override
RuntimeShaderGM(const char *name, SkISize size, const char *sksl, uint32_t flags=0)
void onOnceBeforeDraw() override
bool runAsBench() const override
sk_sp< SkRuntimeEffect > fEffect
bool onAnimate(double nanos) override
SkString getName() const override
void onDraw(SkCanvas *canvas) override
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkBitmap.cpp:669
uint32_t * getAddr32(int x, int y) const
Definition: SkBitmap.h:1260
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
void drawRect(const SkRect &rect, const SkPaint &paint)
Definition: SkCanvas.cpp:1673
void restore()
Definition: SkCanvas.cpp:461
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
sk_sp< SkSurface > makeSurface(const SkImageInfo &info, const SkSurfaceProps *props=nullptr)
Definition: SkCanvas.cpp:1195
void clear(SkColor color)
Definition: SkCanvas.h:1199
void rotate(SkScalar degrees)
Definition: SkCanvas.cpp:1300
void drawRRect(const SkRRect &rrect, const SkPaint &paint)
Definition: SkCanvas.cpp:1705
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
int save()
Definition: SkCanvas.cpp:447
void clipShader(sk_sp< SkShader >, SkClipOp=SkClipOp::kIntersect)
Definition: SkCanvas.cpp:1488
SkImageInfo imageInfo() const
Definition: SkCanvas.cpp:1206
void drawImage(const SkImage *image, SkScalar left, SkScalar top)
Definition: SkCanvas.h:1528
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
static sk_sp< SkShader > MakeRadial(const SkPoint &center, SkScalar radius, const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
static sk_sp< SkImageFilter > Blur(SkScalar sigmaX, SkScalar sigmaY, SkTileMode tileMode, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
const SkImageInfo & imageInfo() const
Definition: SkImage.h:279
bool peekPixels(SkPixmap *pixmap) const
Definition: SkImage.cpp:34
int width() const
Definition: SkImage.h:285
sk_sp< SkShader > makeRawShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:207
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkImage.cpp:179
int height() const
Definition: SkImage.h:291
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix RotateDeg(SkScalar deg)
Definition: SkMatrix.h:104
void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty)
Definition: SkMatrix.h:1803
SkMatrix & setRotate(SkScalar degrees, SkScalar px, SkScalar py)
Definition: SkMatrix.cpp:452
void setImageFilter(sk_sp< SkImageFilter > imageFilter)
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
const uint32_t * addr32() const
Definition: SkPixmap.h:352
int width() const
Definition: SkPixmap.h:160
int height() const
Definition: SkPixmap.h:166
static SkRRect MakeRectXY(const SkRect &rect, SkScalar xRad, SkScalar yRad)
Definition: SkRRect.h:180
uint32_t nextU()
Definition: SkRandom.h:42
float nextF()
Definition: SkRandom.h:55
static sk_sp< SkShader > MakeDeferredShader(const SkRuntimeEffect *effect, UniformsCallback uniformsCallback, SkSpan< const SkRuntimeEffect::ChildPtr > children, const SkMatrix *localMatrix=nullptr)
sk_sp< SkShader > makeShader(sk_sp< const SkData > uniforms, sk_sp< SkShader > children[], size_t childCount, const SkMatrix *localMatrix=nullptr) const
static Result MakeForColorFilter(SkString sksl, const Options &)
static Result MakeForBlender(SkString sksl, const Options &)
static Result MakeForShader(SkString sksl, const Options &)
void onDraw(SkCanvas *canvas) override
void onDraw(SkCanvas *canvas) override
void onOnceBeforeDraw() override
sk_sp< SkShader > fAfter
sk_sp< SkShader > fBefore
sk_sp< SkShader > fThreshold
void onDraw(SkCanvas *canvas) override
void onOnceBeforeDraw() override
sk_sp< SkImage > fMandrill
Definition: gm.h:110
DrawResult draw(SkCanvas *canvas)
Definition: gm.h:140
const Paint & paint
Definition: color_source.cc:38
DlColor color
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
VkSurfaceKHR surface
Definition: main.cc:49
float SkScalar
Definition: extension.cpp:12
static bool b
struct MyStruct a[10]
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
#define DEF_GM(CODE)
Definition: gm.h:40
static float min(float r, float g, float b)
Definition: hsl.cpp:48
constexpr int kSize
double y
double x
constexpr SkColor4f kGreen
Definition: SkColor.h:441
constexpr SkColor4f kRed
Definition: SkColor.h:440
sk_sp< const SkImage > image
Definition: SkRecords.h:269
SkRRect rrect
Definition: SkRecords.h:232
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
Definition: SkRecords.h:208
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
sk_sp< SkShader > create_checkerboard_shader(SkColor c1, SkColor c2, int size)
Definition: ToolUtils.cpp:150
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
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 keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SkSamplingOptions(SkFilterMode::kLinear))
SIN Vec< N, float > normalize(const Vec< N, float > &v)
Definition: SkVx.h:995
static SkBitmap draw_shader(SkCanvas *canvas, sk_sp< SkShader > shader, bool allowRasterFallback=true)
static sk_sp< SkShader > make_shader(sk_sp< SkImage > img, SkISize size)
DEF_SIMPLE_GM_CAN_FAIL(deferred_shader_rt, canvas, errorMsg, 150, 50)
static sk_sp< SkShader > lit_shader(sk_sp< SkShader > normals)
RT_Flags
@ kAnimate_RTFlag
@ kColorFilter_RTFlag
@ kBench_RTFlag
static sk_sp< SkShader > normal_map_shader()
sk_sp< SkShader > paint_color_shader()
static sk_sp< SkShader > normal_map_raw_unpremul_image_shader()
static sk_sp< SkShader > normal_map_image_shader()
static sk_sp< SkShader > lit_shader_linear(sk_sp< SkShader > normals)
static sk_sp< SkShader > make_threshold(SkISize size)
static sk_sp< SkImage > normal_map_unpremul_image()
static sk_sp< SkShader > normal_map_unpremul_image_shader()
static sk_sp< SkShader > normal_map_raw_image_shader()
static sk_sp< SkImage > normal_map_image()
DEF_SIMPLE_GM(child_sampling_rt, canvas, 256, 256)
#define M(PROC, DITHER)
const Scalar scale
Definition: SkSize.h:16
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466
static SkImageInfo MakeN32Premul(int width, int height)
int width() const
Definition: SkImageInfo.h:365
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
int height() const
Definition: SkImageInfo.h:371
SkRect makeOutset(float dx, float dy) const
Definition: SkRect.h:1002
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
constexpr float centerX() const
Definition: SkRect.h:776
constexpr float height() const
Definition: SkRect.h:769
constexpr float centerY() const
Definition: SkRect.h:785
constexpr float width() const
Definition: SkRect.h:762
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
sk_sp< SkRuntimeEffect > effect
Definition: SkM44.h:19
Definition: SkM44.h:98
static void checkerboard(SkCanvas *canvas, SkColor c1, SkColor c2, int size)