Flutter Engine
The Flutter Engine
Namespaces | Typedefs | Functions | Variables
GrGradientShader.cpp File Reference
#include "src/gpu/ganesh/gradients/GrGradientShader.h"
#include "include/core/SkColorSpace.h"
#include "include/gpu/GrRecordingContext.h"
#include "include/private/SkColorData.h"
#include "src/base/SkMathPriv.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkRasterPipeline.h"
#include "src/core/SkRasterPipelineOpList.h"
#include "src/core/SkRuntimeEffectPriv.h"
#include "src/gpu/ganesh/GrCaps.h"
#include "src/gpu/ganesh/GrColor.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrColorSpaceXform.h"
#include "src/gpu/ganesh/GrRecordingContextPriv.h"
#include "src/gpu/ganesh/SkGr.h"
#include "src/gpu/ganesh/effects/GrMatrixEffect.h"
#include "src/gpu/ganesh/effects/GrSkSLFP.h"
#include "src/gpu/ganesh/effects/GrTextureEffect.h"
#include "src/gpu/ganesh/gradients/GrGradientBitmapCache.h"
#include "src/shaders/gradients/SkGradientBaseShader.h"

Go to the source code of this file.

Namespaces

namespace  GrGradientShader
 

Typedefs

using Vec4 = skvx::Vec< 4, float >
 

Functions

static std::unique_ptr< GrFragmentProcessormake_textured_colorizer (const SkPMColor4f *colors, const SkScalar *positions, int count, bool colorsAreOpaque, const SkGradientShader::Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace, const GrFPArgs &args)
 
static std::unique_ptr< GrFragmentProcessormake_single_interval_colorizer (const SkPMColor4f &start, const SkPMColor4f &end)
 
static std::unique_ptr< GrFragmentProcessormake_dual_interval_colorizer (const SkPMColor4f &c0, const SkPMColor4f &c1, const SkPMColor4f &c2, const SkPMColor4f &c3, float threshold)
 
static std::unique_ptr< GrFragmentProcessormake_unrolled_colorizer (int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, SkRect thresholds1_7, SkRect thresholds9_13)
 
static std::unique_ptr< GrFragmentProcessormake_looping_colorizer (int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, const SkScalar *thresholds)
 
int build_intervals (int inputLength, const SkPMColor4f *inColors, const SkScalar *inPositions, int outputLength, SkPMColor4f *outScales, SkPMColor4f *outBiases, SkScalar *outThresholds)
 
static std::unique_ptr< GrFragmentProcessormake_unrolled_binary_colorizer (const SkPMColor4f *colors, const SkScalar *positions, int count)
 
static std::unique_ptr< GrFragmentProcessormake_looping_binary_colorizer (const SkPMColor4f *colors, const SkScalar *positions, int count)
 
static std::unique_ptr< GrFragmentProcessormake_uniform_colorizer (const SkPMColor4f *colors, const SkScalar *positions, int count, bool premul, const GrFPArgs &args)
 
static std::unique_ptr< GrFragmentProcessormake_clamped_gradient (std::unique_ptr< GrFragmentProcessor > colorizer, std::unique_ptr< GrFragmentProcessor > gradLayout, SkPMColor4f leftBorderColor, SkPMColor4f rightBorderColor, bool colorsAreOpaque)
 
static std::unique_ptr< GrFragmentProcessormake_tiled_gradient (const GrFPArgs &args, std::unique_ptr< GrFragmentProcessor > colorizer, std::unique_ptr< GrFragmentProcessor > gradLayout, bool mirror, bool colorsAreOpaque)
 
static std::unique_ptr< GrFragmentProcessormake_interpolated_to_dst (std::unique_ptr< GrFragmentProcessor > gradient, const SkGradientShader::Interpolation &interpolation, SkColorSpace *intermediateColorSpace, const GrColorInfo &dstInfo, bool allOpaque)
 
static GrFPResult GrGradientShader::apply_matrix (std::unique_ptr< GrFragmentProcessor > fp, const SkShaders::MatrixRec &rec, const SkMatrix &postInv)
 
std::unique_ptr< GrFragmentProcessorGrGradientShader::MakeGradientFP (const SkGradientBaseShader &shader, const GrFPArgs &args, const SkShaders::MatrixRec &mRec, std::unique_ptr< GrFragmentProcessor > layout, const SkMatrix *overrideMatrix)
 
std::unique_ptr< GrFragmentProcessorGrGradientShader::MakeLinear (const SkLinearGradient &shader, const GrFPArgs &args, const SkShaders::MatrixRec &mRec)
 

Variables

static const SkScalar kLowPrecisionIntervalLimit = 0.01f
 
static const int kMaxNumCachedGradientBitmaps = 32
 
static const int kGradientTextureSize = 256
 
static constexpr int kMaxUnrolledColorCount = 16
 
static constexpr int kMaxUnrolledIntervalCount = kMaxUnrolledColorCount / 2
 
static constexpr int kMaxLoopingColorCount = 128
 
static constexpr int kMaxLoopingIntervalCount = kMaxLoopingColorCount / 2
 

Typedef Documentation

◆ Vec4

using Vec4 = skvx::Vec<4, float>

Definition at line 32 of file GrGradientShader.cpp.

Function Documentation

◆ build_intervals()

int build_intervals ( int  inputLength,
const SkPMColor4f inColors,
const SkScalar inPositions,
int  outputLength,
SkPMColor4f outScales,
SkPMColor4f outBiases,
SkScalar outThresholds 
)

Definition at line 360 of file GrGradientShader.cpp.

366 {
367 // Depending on how the positions resolve into hard stops or regular stops, the number of
368 // intervals specified by the number of colors/positions can change. For instance, a plain
369 // 3 color gradient is two intervals, but a 4 color gradient with a hard stop is also
370 // two intervals. At the most extreme end, an 8 interval gradient made entirely of hard
371 // stops has 16 colors.
372 int intervalCount = 0;
373 for (int i = 0; i < inputLength - 1; i++) {
374 if (intervalCount >= outputLength) {
375 // Already reached our output limit, and haven't run out of color stops. This gradient
376 // cannot be represented without more intervals.
377 return 0;
378 }
379
380 SkScalar t0 = inPositions[i];
381 SkScalar t1 = inPositions[i + 1];
382 SkScalar dt = t1 - t0;
383 // If the interval is empty, skip to the next interval. This will automatically create
384 // distinct hard stop intervals as needed. It also protects against malformed gradients
385 // that have repeated hard stops at the very beginning that are effectively unreachable.
386 if (SkScalarNearlyZero(dt)) {
387 continue;
388 }
389
390 Vec4 c0 = Vec4::Load(inColors[i].vec());
391 Vec4 c1 = Vec4::Load(inColors[i + 1].vec());
392 Vec4 scale = (c1 - c0) / dt;
393 Vec4 bias = c0 - t0 * scale;
394
395 scale.store(outScales + intervalCount);
396 bias.store(outBiases + intervalCount);
397 outThresholds[intervalCount] = t1;
398 intervalCount++;
399 }
400 return intervalCount;
401}
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:101
float SkScalar
Definition: extension.cpp:12
const Scalar scale
Definition: SkVx.h:83
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
Definition: SkVx.h:109
SKVX_ALWAYS_INLINE void store(void *ptr) const
Definition: SkVx.h:112

◆ make_clamped_gradient()

static std::unique_ptr< GrFragmentProcessor > make_clamped_gradient ( std::unique_ptr< GrFragmentProcessor colorizer,
std::unique_ptr< GrFragmentProcessor gradLayout,
SkPMColor4f  leftBorderColor,
SkPMColor4f  rightBorderColor,
bool  colorsAreOpaque 
)
static

Definition at line 560 of file GrGradientShader.cpp.

565 {
567 "uniform shader colorizer;"
568 "uniform shader gradLayout;"
569
570 "uniform half4 leftBorderColor;" // t < 0.0
571 "uniform half4 rightBorderColor;" // t > 1.0
572
573 "uniform int layoutPreservesOpacity;" // specialized
574
575 "half4 main(float2 coord) {"
576 "half4 t = gradLayout.eval(coord);"
577 "half4 outColor;"
578
579 // If t.x is below 0, use the left border color without invoking the child processor.
580 // If any t.x is above 1, use the right border color. Otherwise, t is in the [0, 1]
581 // range assumed by the colorizer FP, so delegate to the child processor.
582 "if (!bool(layoutPreservesOpacity) && t.y < 0) {"
583 // layout has rejected this fragment (rely on sksl to remove this branch if the
584 // layout FP preserves opacity is false)
585 "outColor = half4(0);"
586 "} else if (t.x < 0) {"
587 "outColor = leftBorderColor;"
588 "} else if (t.x > 1.0) {"
589 "outColor = rightBorderColor;"
590 "} else {"
591 // Always sample from (x, 0), discarding y, since the layout FP can use y as a
592 // side-channel.
593 "outColor = colorizer.eval(t.x0);"
594 "}"
595 "return outColor;"
596 "}"
597 );
598
599 // If the layout does not preserve opacity, remove the opaque optimization,
600 // but otherwise respect the provided color opacity state (which should take
601 // into account the opacity of the border colors).
602 bool layoutPreservesOpacity = gradLayout->preservesOpaqueInput();
604 if (colorsAreOpaque && layoutPreservesOpacity) {
606 }
607
608 return GrSkSLFP::Make(effect, "ClampedGradient", /*inputFP=*/nullptr, optFlags,
609 "colorizer", GrSkSLFP::IgnoreOptFlags(std::move(colorizer)),
610 "gradLayout", GrSkSLFP::IgnoreOptFlags(std::move(gradLayout)),
611 "leftBorderColor", leftBorderColor,
612 "rightBorderColor", rightBorderColor,
613 "layoutPreservesOpacity",
614 GrSkSLFP::Specialize<int>(layoutPreservesOpacity));
615}
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr< GrFragmentProcessor > child)
Definition: GrSkSLFP.h:97
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
Definition: GrSkSLFP.h:159
static Result MakeForShader(SkString sksl, const Options &)

◆ make_dual_interval_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_dual_interval_colorizer ( const SkPMColor4f c0,
const SkPMColor4f c1,
const SkPMColor4f c2,
const SkPMColor4f c3,
float  threshold 
)
static

Definition at line 110 of file GrGradientShader.cpp.

114 {
116 "uniform float4 scale[2];"
117 "uniform float4 bias[2];"
118 "uniform half threshold;"
119
120 "half4 main(float2 coord) {"
121 "half t = half(coord.x);"
122
123 "float4 s, b;"
124 "if (t < threshold) {"
125 "s = scale[0];"
126 "b = bias[0];"
127 "} else {"
128 "s = scale[1];"
129 "b = bias[1];"
130 "}"
131
132 "return half4(t * s + b);"
133 "}"
134 );
135
136 // Derive scale and biases from the 4 colors and threshold
137 Vec4 vc0 = Vec4::Load(c0.vec());
138 Vec4 vc1 = Vec4::Load(c1.vec());
139 Vec4 vc2 = Vec4::Load(c2.vec());
140 Vec4 vc3 = Vec4::Load(c3.vec());
141
142 const Vec4 scale[2] = {(vc1 - vc0) / threshold,
143 (vc3 - vc2) / (1 - threshold)};
144 const Vec4 bias[2] = {vc0,
145 vc2 - threshold * scale[1]};
146 return GrSkSLFP::Make(effect, "DualIntervalColorizer", /*inputFP=*/nullptr,
148 "scale", SkSpan(scale),
149 "bias", SkSpan(bias),
150 "threshold", threshold);
151}
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
const float * vec() const
Definition: SkColor.h:308

◆ make_interpolated_to_dst()

static std::unique_ptr< GrFragmentProcessor > make_interpolated_to_dst ( std::unique_ptr< GrFragmentProcessor gradient,
const SkGradientShader::Interpolation interpolation,
SkColorSpace intermediateColorSpace,
const GrColorInfo dstInfo,
bool  allOpaque 
)
static

Definition at line 683 of file GrGradientShader.cpp.

688 {
690
691 // If these values change, you will need to edit sksl_shared
692 static_assert(static_cast<int>(ColorSpace::kDestination) == 0);
693 static_assert(static_cast<int>(ColorSpace::kSRGBLinear) == 1);
694 static_assert(static_cast<int>(ColorSpace::kLab) == 2);
695 static_assert(static_cast<int>(ColorSpace::kOKLab) == 3);
696 static_assert(static_cast<int>(ColorSpace::kOKLabGamutMap) == 4);
697 static_assert(static_cast<int>(ColorSpace::kLCH) == 5);
698 static_assert(static_cast<int>(ColorSpace::kOKLCH) == 6);
699 static_assert(static_cast<int>(ColorSpace::kOKLCHGamutMap) == 7);
700 static_assert(static_cast<int>(ColorSpace::kSRGB) == 8);
701 static_assert(static_cast<int>(ColorSpace::kHSL) == 9);
702 static_assert(static_cast<int>(ColorSpace::kHWB) == 10);
703
705 "uniform int colorSpace;" // specialized
706 "uniform int do_unpremul;" // specialized
707
708 "half4 main(half4 color) {"
709 "return $interpolated_to_rgb_unpremul(color, colorSpace, do_unpremul);"
710 "}"
711 );
712
713 // Are we interpreting premul colors? We use this later to decide if we need to inject a final
714 // premultiplication step.
715 bool inputPremul = static_cast<bool>(interpolation.fInPremul);
716
717 switch (interpolation.fColorSpace) {
718 case ColorSpace::kLab:
719 case ColorSpace::kOKLab:
720 case ColorSpace::kOKLabGamutMap:
721 case ColorSpace::kLCH:
722 case ColorSpace::kOKLCH:
723 case ColorSpace::kOKLCHGamutMap:
724 case ColorSpace::kHSL:
725 case ColorSpace::kHWB:
726 // In these exotic spaces, unpremul the colors if necessary (no need to do this if
727 // they're all opaque), and then convert them to the intermediate SkColorSpace
728 gradient = GrSkSLFP::Make(effect, "GradientCS", std::move(gradient),
730 "colorSpace", GrSkSLFP::Specialize<int>(
731 static_cast<int>(interpolation.fColorSpace)),
732 "do_unpremul", GrSkSLFP::Specialize<int>(
733 inputPremul && !allOpaque));
734 // We just forced the colors back to unpremul. Remember that for below
735 inputPremul = false;
736 break;
737 default:
738 break;
739 }
740
741 // Now transform from intermediate to destination color space. There are two tricky things here:
742 // 1) Normally, we'd pass dstInfo to the transform effect. However, if someone is rendering to
743 // a non-color managed surface (nullptr dst color space), and they chose to interpolate in
744 // any of the exotic spaces, that transform would do nothing, and leave the colors in
745 // whatever intermediate space we chose. That could even be something like XYZ, which will
746 // produce nonsense. So, in this particular case, we break Skia's rules, and treat a null
747 // destination as sRGB.
748 SkColorSpace* dstColorSpace = dstInfo.colorSpace() ? dstInfo.colorSpace() : sk_srgb_singleton();
749
750 // 2) Alpha type: We already tweaked our idea of "inputPremul" above -- if we interpolated in a
751 // non-RGB space, then we had to unpremul the colors to get proper conversion back to RGB.
752 // Our final goal is to emit premul colors, but under certain conditions we don't need to do
753 // anything to achieve that: i.e. its interpolating already premul colors (inputPremul) or
754 // all the colors have a = 1, in which case premul is a no op. Note that this allOpaque check
755 // is more permissive than SkGradientBaseShader's isOpaque(), since we can optimize away the
756 // make-premul op for two point conical gradients (which report false for isOpaque).
757 SkAlphaType intermediateAlphaType = inputPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
758 SkAlphaType dstAlphaType = kPremul_SkAlphaType;
759
760 // If all the colors were opaque, then we don't need to do any premultiplication. We describe
761 // all the colors as *unpremul*, though. That will eliminate any extra unpremul/premul pair
762 // that would be injected if we have to do a color-space conversion here.
763 if (allOpaque) {
764 intermediateAlphaType = dstAlphaType = kUnpremul_SkAlphaType;
765 }
766
767 return GrColorSpaceXformEffect::Make(std::move(gradient),
768 intermediateColorSpace, intermediateAlphaType,
769 dstColorSpace, dstAlphaType);
770}
kUnpremul_SkAlphaType
SkAlphaType
Definition: SkAlphaType.h:26
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
SkColorSpace * sk_srgb_singleton()
SkColorSpace * colorSpace() const
Definition: GrColorInfo.cpp:48
static std::unique_ptr< GrFragmentProcessor > Make(std::unique_ptr< GrFragmentProcessor > child, SkColorSpace *src, SkAlphaType srcAT, SkColorSpace *dst, SkAlphaType dstAT)
static Result MakeForColorFilter(SkString sksl, const Options &)
ColorSpace
Definition: image.h:16

◆ make_looping_binary_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_looping_binary_colorizer ( const SkPMColor4f colors,
const SkScalar positions,
int  count 
)
static

Definition at line 425 of file GrGradientShader.cpp.

427 {
429 // Definitely cannot represent this gradient configuration
430 return nullptr;
431 }
432
435 SkScalar thresholds[kMaxLoopingIntervalCount] = {};
436 int intervalCount = build_intervals(count, colors, positions,
437 kMaxLoopingIntervalCount, scales, biases, thresholds);
438 if (intervalCount <= 0) {
439 return nullptr;
440 }
441
442 // We round up the number of intervals to the next power of two. This reduces the number of
443 // unique shaders and doesn't require any additional GPU processing power, but this does waste a
444 // handful of uniforms.
445 int roundedSize = std::max(4, SkNextPow2(intervalCount));
446 SkASSERT(roundedSize <= kMaxLoopingIntervalCount);
447 for (; intervalCount < roundedSize; ++intervalCount) {
448 thresholds[intervalCount] = thresholds[intervalCount - 1];
449 scales[intervalCount] = scales[intervalCount - 1];
450 biases[intervalCount] = biases[intervalCount - 1];
451 }
452
453 return make_looping_colorizer(intervalCount, scales, biases, thresholds);
454}
int count
Definition: FontMgrTest.cpp:50
int build_intervals(int inputLength, const SkPMColor4f *inColors, const SkScalar *inPositions, int outputLength, SkPMColor4f *outScales, SkPMColor4f *outBiases, SkScalar *outThresholds)
static constexpr int kMaxLoopingIntervalCount
static constexpr int kMaxLoopingColorCount
static std::unique_ptr< GrFragmentProcessor > make_looping_colorizer(int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, const SkScalar *thresholds)
#define SkASSERT(cond)
Definition: SkAssert.h:116
static int SkNextPow2(int value)
Definition: SkMathPriv.h:272
static float max(float r, float g, float b)
Definition: hsl.cpp:49
PODArray< SkColor > colors
Definition: SkRecords.h:276

◆ make_looping_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_looping_colorizer ( int  intervalCount,
const SkPMColor4f scale,
const SkPMColor4f bias,
const SkScalar thresholds 
)
static

Definition at line 271 of file GrGradientShader.cpp.

274 {
275 SkASSERT(intervalCount >= 1 && intervalCount <= kMaxLoopingIntervalCount);
276 SkASSERT((intervalCount & 3) == 0); // intervals are required to come in groups of four
277 int intervalChunks = intervalCount / 4;
278 int cacheIndex = (size_t)intervalChunks - 1;
279
280 struct EffectCacheEntry {
281 SkOnce once;
282 const SkRuntimeEffect* effect;
283 };
284
285 static EffectCacheEntry effectCache[kMaxLoopingIntervalCount / 4];
286 SkASSERT(cacheIndex >= 0 && cacheIndex < (int)std::size(effectCache));
287 EffectCacheEntry* cacheEntry = &effectCache[cacheIndex];
288
289 cacheEntry->once([intervalCount, intervalChunks, cacheEntry] {
290 SkString sksl;
291
292 // Binary search for the interval that `t` falls within. We can precalculate the number of
293 // loop iterations we need, and we know `t` will always be in range, so we can just loop a
294 // fixed number of times and can be guaranteed to have found the proper element.
295 //
296 // Threshold values are stored in half4s to keep them compact, so the last two rounds of
297 // binary search are hand-unrolled to allow them to use swizzles.
298 //
299 // Note that this colorizer is also designed to handle the case of exactly 4 intervals (a
300 // single chunk). In this case, the binary search for-loop will optimize away entirely, as
301 // it can be proven to execute zero times. We also optimize away the calculation of `4 *
302 // chunk` near the end via an if statement, as the result will always be in chunk 0.
303 int loopCount = SkNextLog2(intervalChunks);
304 sksl.appendf(
305 "#version 300\n" // important space to separate token.
306 "uniform half4 thresholds[%d];"
307 "uniform float4 scale[%d];"
308 "uniform float4 bias[%d];"
309
310 "half4 main(float2 coord) {"
311 "half t = half(coord.x);"
312
313 // Choose a chunk from thresholds via binary search in a loop.
314 "int low = 0;"
315 "int high = %d;"
316 "int chunk = %d;"
317 "for (int loop = 0; loop < %d; ++loop) {"
318 "if (t < thresholds[chunk].w) {"
319 "high = chunk;"
320 "} else {"
321 "low = chunk + 1;"
322 "}"
323 "chunk = (low + high) / 2;"
324 "}"
325
326 // Choose the final position via explicit 4-way binary search.
327 "int pos;"
328 "if (t < thresholds[chunk].y) {"
329 "pos = (t < thresholds[chunk].x) ? 0 : 1;"
330 "} else {"
331 "pos = (t < thresholds[chunk].z) ? 2 : 3;"
332 "}"
333 "if (%d > 0) {"
334 "pos += 4 * chunk;"
335 "}"
336 "return t * scale[pos] + bias[pos];"
337 "}"
338 , /* thresholds: */ intervalChunks,
339 /* scale: */ intervalCount,
340 /* bias: */ intervalCount,
341 /* high: */ intervalChunks - 1,
342 /* chunk: */ (intervalChunks - 1) / 2,
343 /* loopCount: */ loopCount,
344 /* if (loopCount > 0): */ loopCount);
345
346 auto result = SkRuntimeEffect::MakeForShader(std::move(sksl));
347 SkASSERTF(result.effect, "%s", result.errorText.c_str());
348 cacheEntry->effect = result.effect.release();
349 });
350
351 return GrSkSLFP::Make(cacheEntry->effect, "LoopingBinaryColorizer",
352 /*inputFP=*/nullptr, GrSkSLFP::OptFlags::kNone,
353 "thresholds", SkSpan((const SkV4*)thresholds, intervalChunks),
354 "scale", SkSpan(scale, intervalCount),
355 "bias", SkSpan(bias, intervalCount));
356}
#define SkASSERTF(cond, fmt,...)
Definition: SkAssert.h:117
static int SkNextLog2(uint32_t value)
Definition: SkMathPriv.h:238
Definition: SkOnce.h:22
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
Definition: SkString.cpp:550
GAsyncResult * result
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
Definition: SkM44.h:98

◆ make_single_interval_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_single_interval_colorizer ( const SkPMColor4f start,
const SkPMColor4f end 
)
static

Definition at line 93 of file GrGradientShader.cpp.

94 {
96 "uniform half4 start;"
97 "uniform half4 end;"
98 "half4 main(float2 coord) {"
99 // Clamping and/or wrapping was already handled by the parent shader so the output
100 // color is a simple lerp.
101 "return mix(start, end, half(coord.x));"
102 "}"
103 );
104 return GrSkSLFP::Make(effect, "SingleIntervalColorizer", /*inputFP=*/nullptr,
106 "start", start,
107 "end", end);
108}
glong glong end

◆ make_textured_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_textured_colorizer ( const SkPMColor4f colors,
const SkScalar positions,
int  count,
bool  colorsAreOpaque,
const SkGradientShader::Interpolation interpolation,
const SkColorSpace intermediateColorSpace,
const SkColorSpace dstColorSpace,
const GrFPArgs args 
)
static

Definition at line 44 of file GrGradientShader.cpp.

52 {
54
55 // Use 8888 or F16, depending on the destination config.
56 // TODO: Use 1010102 for opaque gradients, at least if destination is 1010102?
58 if (GrColorTypeIsWiderThan(args.fDstColorInfo->colorType(), 8)) {
59 auto f16Format = args.fContext->priv().caps()->getDefaultBackendFormat(
61 if (f16Format.isValid()) {
63 }
64 }
65 SkAlphaType alphaType = static_cast<bool>(interpolation.fInPremul) ? kPremul_SkAlphaType
67
69 gCache.getGradient(colors,
70 positions,
71 count,
72 colorsAreOpaque,
73 interpolation,
74 intermediateColorSpace,
75 dstColorSpace,
77 alphaType,
78 &bitmap);
79 SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width()));
80 SkASSERT(bitmap.isImmutable());
81
83 args.fContext, bitmap, /*label=*/"MakeTexturedColorizer", skgpu::Mipmapped::kNo));
84 if (!view) {
85 SkDebugf("Gradient won't draw. Could not create texture.");
86 return nullptr;
87 }
88
89 auto m = SkMatrix::Scale(view.width(), 1.f);
90 return GrTextureEffect::Make(std::move(view), alphaType, m, GrSamplerState::Filter::kLinear);
91}
static const int kMaxNumCachedGradientBitmaps
static const int kGradientTextureSize
static constexpr bool GrColorTypeIsWiderThan(GrColorType colorType, int n)
Definition: GrTypesPriv.h:878
SkColorType
Definition: SkColorType.h:19
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition: SkColorType.h:24
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeCachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, std::string_view label, skgpu::Mipmapped mipmapped)
Definition: SkGr.cpp:188
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
constexpr bool SkIsPow2(T value)
Definition: SkMath.h:51
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Definition: bitmap.py:1
const myers::Point & get< 0 >(const myers::Segment &s)
Definition: Myers.h:80
static thread_local void * gCache
Definition: AtlasTextOp.cpp:62

◆ make_tiled_gradient()

static std::unique_ptr< GrFragmentProcessor > make_tiled_gradient ( const GrFPArgs args,
std::unique_ptr< GrFragmentProcessor colorizer,
std::unique_ptr< GrFragmentProcessor gradLayout,
bool  mirror,
bool  colorsAreOpaque 
)
static

Definition at line 617 of file GrGradientShader.cpp.

622 {
624 "uniform shader colorizer;"
625 "uniform shader gradLayout;"
626
627 "uniform int mirror;" // specialized
628 "uniform int layoutPreservesOpacity;" // specialized
629 "uniform int useFloorAbsWorkaround;" // specialized
630
631 "half4 main(float2 coord) {"
632 "half4 t = gradLayout.eval(coord);"
633
634 "if (!bool(layoutPreservesOpacity) && t.y < 0) {"
635 // layout has rejected this fragment (rely on sksl to remove this branch if the
636 // layout FP preserves opacity is false)
637 "return half4(0);"
638 "} else {"
639 "if (bool(mirror)) {"
640 "half t_1 = t.x - 1;"
641 "half tiled_t = t_1 - 2 * floor(t_1 * 0.5) - 1;"
642 "if (bool(useFloorAbsWorkaround)) {"
643 // At this point the expected value of tiled_t should between -1 and 1, so
644 // this clamp has no effect other than to break up the floor and abs calls
645 // and make sure the compiler doesn't merge them back together.
646 "tiled_t = clamp(tiled_t, -1, 1);"
647 "}"
648 "t.x = abs(tiled_t);"
649 "} else {"
650 // Simple repeat mode
651 "t.x = fract(t.x);"
652 "}"
653
654 // Always sample from (x, 0), discarding y, since the layout FP can use y as a
655 // side-channel.
656 "half4 outColor = colorizer.eval(t.x0);"
657 "return outColor;"
658 "}"
659 "}"
660 );
661
662 // If the layout does not preserve opacity, remove the opaque optimization,
663 // but otherwise respect the provided color opacity state (which should take
664 // into account the opacity of the border colors).
665 bool layoutPreservesOpacity = gradLayout->preservesOpaqueInput();
667 if (colorsAreOpaque && layoutPreservesOpacity) {
669 }
670 const bool useFloorAbsWorkaround =
671 args.fContext->priv().caps()->shaderCaps()->fMustDoOpBetweenFloorAndAbs;
672
673 return GrSkSLFP::Make(effect, "TiledGradient", /*inputFP=*/nullptr, optFlags,
674 "colorizer", GrSkSLFP::IgnoreOptFlags(std::move(colorizer)),
675 "gradLayout", GrSkSLFP::IgnoreOptFlags(std::move(gradLayout)),
676 "mirror", GrSkSLFP::Specialize<int>(mirror),
677 "layoutPreservesOpacity",
678 GrSkSLFP::Specialize<int>(layoutPreservesOpacity),
679 "useFloorAbsWorkaround",
680 GrSkSLFP::Specialize<int>(useFloorAbsWorkaround));
681}
static unsigned mirror(SkFixed fx, int max)

◆ make_uniform_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_uniform_colorizer ( const SkPMColor4f colors,
const SkScalar positions,
int  count,
bool  premul,
const GrFPArgs args 
)
static

Definition at line 458 of file GrGradientShader.cpp.

462 {
463 // If there are hard stops at the beginning or end, the first and/or last color should be
464 // ignored by the colorizer since it should only be used in a clamped border color. By detecting
465 // and removing these stops at the beginning, it makes optimizing the remaining color stops
466 // simpler.
467
468 // SkGradientBaseShader guarantees that pos[0] == 0 by adding a default value.
469 bool bottomHardStop = SkScalarNearlyEqual(positions[0], positions[1]);
470 // The same is true for pos[end] == 1
471 bool topHardStop = SkScalarNearlyEqual(positions[count - 2], positions[count - 1]);
472
473 if (bottomHardStop) {
474 colors++;
475 positions++;
476 count--;
477 }
478 if (topHardStop) {
479 count--;
480 }
481
482 // Two remaining colors means a single interval from 0 to 1
483 // (but it may have originally been a 3 or 4 color gradient with 1-2 hard stops at the ends)
484 if (count == 2) {
486 }
487
488 const GrShaderCaps* caps = args.fContext->priv().caps()->shaderCaps();
489 auto intervalsExceedPrecisionLimit = [&]() -> bool {
490 // The remaining analytic colorizers use scale*t+bias, and the scale/bias values can become
491 // quite large when thresholds are close (but still outside the hardstop limit). If float
492 // isn't 32-bit, output can be incorrect if the thresholds are too close together. However,
493 // the analytic shaders are higher quality, so they can be used with lower precision
494 // hardware when the thresholds are not ill-conditioned.
495 if (!caps->fFloatIs32Bits) {
496 // Could run into problems. Check if thresholds are close together (with a limit of .01,
497 // so that scales will be less than 100, which leaves 4 decimals of precision on
498 // 16-bit).
499 for (int i = 0; i < count - 1; i++) {
500 SkScalar dt = SkScalarAbs(positions[i] - positions[i + 1]);
501 if (dt <= kLowPrecisionIntervalLimit && dt > SK_ScalarNearlyZero) {
502 return true;
503 }
504 }
505 }
506 return false;
507 };
508
509 auto makeDualIntervalColorizer = [&]() -> std::unique_ptr<GrFragmentProcessor> {
510 // The dual-interval colorizer uses the same principles as the binary-search colorizer, but
511 // is limited to exactly 2 intervals.
512 if (count == 3) {
513 // Must be a dual interval gradient, where the middle point is at 1 and the
514 // two intervals share the middle color stop.
516 colors[1], colors[2],
517 positions[1]);
518 }
519 if (count == 4 && SkScalarNearlyEqual(positions[1], positions[2])) {
520 // Two separate intervals that join at the same threshold position
522 colors[2], colors[3],
523 positions[1]);
524 }
525 // The gradient can't be represented in only two intervals.
526 return nullptr;
527 };
528
529 int binaryColorizerLimit = caps->fNonconstantArrayIndexSupport ? kMaxLoopingColorCount
531 if ((count <= binaryColorizerLimit) && !intervalsExceedPrecisionLimit()) {
532 // The dual-interval colorizer uses the same principles as the binary-search colorizer, but
533 // is limited to exactly 2 intervals.
534 std::unique_ptr<GrFragmentProcessor> colorizer = makeDualIntervalColorizer();
535 if (colorizer) {
536 return colorizer;
537 }
538 // Attempt to create an analytic colorizer that uses a binary-search loop.
539 colorizer = caps->fNonconstantArrayIndexSupport
542 if (colorizer) {
543 return colorizer;
544 }
545 }
546
547 // This gradient is too complex for our uniform colorizers. The calling code will fall back to
548 // creating a textured colorizer, instead.
549 return nullptr;
550}
static std::unique_ptr< GrFragmentProcessor > make_looping_binary_colorizer(const SkPMColor4f *colors, const SkScalar *positions, int count)
static std::unique_ptr< GrFragmentProcessor > make_dual_interval_colorizer(const SkPMColor4f &c0, const SkPMColor4f &c1, const SkPMColor4f &c2, const SkPMColor4f &c3, float threshold)
static constexpr int kMaxUnrolledColorCount
static std::unique_ptr< GrFragmentProcessor > make_unrolled_binary_colorizer(const SkPMColor4f *colors, const SkScalar *positions, int count)
static std::unique_ptr< GrFragmentProcessor > make_single_interval_colorizer(const SkPMColor4f &start, const SkPMColor4f &end)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
Definition: SkScalar.h:107
#define SK_ScalarNearlyZero
Definition: SkScalar.h:99
#define SkScalarAbs(x)
Definition: SkScalar.h:39
bool fNonconstantArrayIndexSupport
Definition: GrShaderCaps.h:39
bool fFloatIs32Bits
Definition: SkSLUtil.h:100

◆ make_unrolled_binary_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_unrolled_binary_colorizer ( const SkPMColor4f colors,
const SkScalar positions,
int  count 
)
static

Definition at line 403 of file GrGradientShader.cpp.

404 {
406 // Definitely cannot represent this gradient configuration
407 return nullptr;
408 }
409
412 SkScalar thresholds[kMaxUnrolledIntervalCount] = {};
413 int intervalCount = build_intervals(count, colors, positions,
414 kMaxUnrolledIntervalCount, scales, biases, thresholds);
415 if (intervalCount <= 0) {
416 return nullptr;
417 }
418
419 SkRect thresholds1_7 = {thresholds[0], thresholds[1], thresholds[2], thresholds[3]},
420 thresholds9_13 = {thresholds[4], thresholds[5], thresholds[6], 0.0};
421
422 return make_unrolled_colorizer(intervalCount, scales, biases, thresholds1_7, thresholds9_13);
423}
static std::unique_ptr< GrFragmentProcessor > make_unrolled_colorizer(int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, SkRect thresholds1_7, SkRect thresholds9_13)
static constexpr int kMaxUnrolledIntervalCount

◆ make_unrolled_colorizer()

static std::unique_ptr< GrFragmentProcessor > make_unrolled_colorizer ( int  intervalCount,
const SkPMColor4f scale,
const SkPMColor4f bias,
SkRect  thresholds1_7,
SkRect  thresholds9_13 
)
static

Definition at line 159 of file GrGradientShader.cpp.

163 {
164 SkASSERT(intervalCount >= 1 && intervalCount <= 8);
165
167 static const SkRuntimeEffect* effects[kMaxUnrolledIntervalCount];
168
169 once[intervalCount - 1]([intervalCount] {
170 SkString sksl;
171
172 // The 7 threshold positions that define the boundaries of the 8 intervals (excluding t = 0,
173 // and t = 1) are packed into two half4s instead of having up to 7 separate scalar uniforms.
174 // For low interval counts, the extra components are ignored in the shader, but the uniform
175 // simplification is worth it. It is assumed thresholds are provided in increasing value,
176 // mapped as:
177 // - thresholds1_7.x = boundary between (0,1) and (2,3) -> 1_2
178 // - .y = boundary between (2,3) and (4,5) -> 3_4
179 // - .z = boundary between (4,5) and (6,7) -> 5_6
180 // - .w = boundary between (6,7) and (8,9) -> 7_8
181 // - thresholds9_13.x = boundary between (8,9) and (10,11) -> 9_10
182 // - .y = boundary between (10,11) and (12,13) -> 11_12
183 // - .z = boundary between (12,13) and (14,15) -> 13_14
184 // - .w = unused
185 sksl.append("uniform half4 thresholds1_7, thresholds9_13;");
186
187 // With the current hardstop detection threshold of 0.00024, the maximum scale and bias
188 // values will be on the order of 4k (since they divide by dt). That is well outside the
189 // precision capabilities of half floats, which can lead to inaccurate gradient calculations
190 sksl.appendf("uniform float4 scale[%d];", intervalCount);
191 sksl.appendf("uniform float4 bias[%d];", intervalCount);
192
193 // Explicit binary search for the proper interval that t falls within. The interval
194 // count checks are constant expressions, which are then optimized to the minimal number
195 // of branches for the specific interval count.
196 sksl.appendf(
197 "half4 main(float2 coord) {"
198 "half t = half(coord.x);"
199 "float4 s, b;"
200 // thresholds1_7.w is mid point for intervals (0,7) and (8,15)
201 "if (%d <= 4 || t < thresholds1_7.w) {"
202 // thresholds1_7.y is mid point for intervals (0,3) and (4,7)
203 "if (%d <= 2 || t < thresholds1_7.y) {"
204 // thresholds1_7.x is mid point for intervals (0,1) and (2,3)
205 "if (%d <= 1 || t < thresholds1_7.x) {"
206 "%s" // s = scale[0]; b = bias[0];
207 "} else {"
208 "%s" // s = scale[1]; b = bias[1];
209 "}"
210 "} else {"
211 // thresholds1_7.z is mid point for intervals (4,5) and (6,7)
212 "if (%d <= 3 || t < thresholds1_7.z) {"
213 "%s" // s = scale[2]; b = bias[2];
214 "} else {"
215 "%s" // s = scale[3]; b = bias[3];
216 "}"
217 "}"
218 "} else {"
219 // thresholds9_13.y is mid point for intervals (8,11) and (12,15)
220 "if (%d <= 6 || t < thresholds9_13.y) {"
221 // thresholds9_13.x is mid point for intervals (8,9) and (10,11)
222 "if (%d <= 5 || t < thresholds9_13.x) {"
223 "%s"
224 "} else {"
225 "%s" // s = scale[5]; b = bias[5];
226 "}"
227 "} else {"
228 // thresholds9_13.z is mid point for intervals (12,13) and (14,15)
229 "if (%d <= 7 || t < thresholds9_13.z) {"
230 "%s" // s = scale[6]; b = bias[6];
231 "} else {"
232 "%s" // s = scale[7]; b = bias[7];
233 "}"
234 "}"
235 "}"
236 "return t * s + b;"
237 "}"
238 , intervalCount,
239 intervalCount,
240 intervalCount,
241 (intervalCount <= 0) ? "" : "s = scale[0]; b = bias[0];",
242 (intervalCount <= 1) ? "" : "s = scale[1]; b = bias[1];",
243 intervalCount,
244 (intervalCount <= 2) ? "" : "s = scale[2]; b = bias[2];",
245 (intervalCount <= 3) ? "" : "s = scale[3]; b = bias[3];",
246 intervalCount,
247 intervalCount,
248 (intervalCount <= 4) ? "" : "s = scale[4]; b = bias[4];",
249 (intervalCount <= 5) ? "" : "s = scale[5]; b = bias[5];",
250 intervalCount,
251 (intervalCount <= 6) ? "" : "s = scale[6]; b = bias[6];",
252 (intervalCount <= 7) ? "" : "s = scale[7]; b = bias[7];");
253
254 auto result = SkRuntimeEffect::MakeForShader(std::move(sksl));
255 SkASSERTF(result.effect, "%s", result.errorText.c_str());
256 effects[intervalCount - 1] = result.effect.release();
257 });
258
259 return GrSkSLFP::Make(effects[intervalCount - 1], "UnrolledBinaryColorizer",
260 /*inputFP=*/nullptr, GrSkSLFP::OptFlags::kNone,
261 "thresholds1_7", thresholds1_7,
262 "thresholds9_13", thresholds9_13,
263 "scale", SkSpan(scale, intervalCount),
264 "bias", SkSpan(bias, intervalCount));
265}
void append(const char text[])
Definition: SkString.h:203

Variable Documentation

◆ kGradientTextureSize

const int kGradientTextureSize = 256
static

Definition at line 40 of file GrGradientShader.cpp.

◆ kLowPrecisionIntervalLimit

const SkScalar kLowPrecisionIntervalLimit = 0.01f
static

Definition at line 36 of file GrGradientShader.cpp.

◆ kMaxLoopingColorCount

constexpr int kMaxLoopingColorCount = 128
staticconstexpr

Definition at line 268 of file GrGradientShader.cpp.

◆ kMaxLoopingIntervalCount

constexpr int kMaxLoopingIntervalCount = kMaxLoopingColorCount / 2
staticconstexpr

Definition at line 269 of file GrGradientShader.cpp.

◆ kMaxNumCachedGradientBitmaps

const int kMaxNumCachedGradientBitmaps = 32
static

Definition at line 39 of file GrGradientShader.cpp.

◆ kMaxUnrolledColorCount

constexpr int kMaxUnrolledColorCount = 16
staticconstexpr

Definition at line 156 of file GrGradientShader.cpp.

◆ kMaxUnrolledIntervalCount

constexpr int kMaxUnrolledIntervalCount = kMaxUnrolledColorCount / 2
staticconstexpr

Definition at line 157 of file GrGradientShader.cpp.