59 auto f16Format =
args.fContext->priv().caps()->getDefaultBackendFormat(
61 if (f16Format.isValid()) {
74 intermediateColorSpace,
83 args.fContext,
bitmap,
"MakeTexturedColorizer", skgpu::Mipmapped::kNo));
85 SkDebugf(
"Gradient won't draw. Could not create texture.");
96 "uniform half4 start;"
98 "half4 main(float2 coord) {"
101 "return mix(start, end, half(coord.x));"
116 "uniform float4 scale[2];"
117 "uniform float4 bias[2];"
118 "uniform half threshold;"
120 "half4 main(float2 coord) {"
121 "half t = half(coord.x);"
124 "if (t < threshold) {"
132 "return half4(t * s + b);"
142 const Vec4 scale[2] = {(vc1 - vc0) / threshold,
143 (vc3 - vc2) / (1 - threshold)};
144 const Vec4 bias[2] = {vc0,
145 vc2 - threshold *
scale[1]};
150 "threshold", threshold);
164 SkASSERT(intervalCount >= 1 && intervalCount <= 8);
169 once[intervalCount - 1]([intervalCount] {
185 sksl.
append(
"uniform half4 thresholds1_7, thresholds9_13;");
190 sksl.
appendf(
"uniform float4 scale[%d];", intervalCount);
191 sksl.
appendf(
"uniform float4 bias[%d];", intervalCount);
197 "half4 main(float2 coord) {"
198 "half t = half(coord.x);"
201 "if (%d <= 4 || t < thresholds1_7.w) {"
203 "if (%d <= 2 || t < thresholds1_7.y) {"
205 "if (%d <= 1 || t < thresholds1_7.x) {"
212 "if (%d <= 3 || t < thresholds1_7.z) {"
220 "if (%d <= 6 || t < thresholds9_13.y) {"
222 "if (%d <= 5 || t < thresholds9_13.x) {"
229 "if (%d <= 7 || t < thresholds9_13.z) {"
241 (intervalCount <= 0) ?
"" :
"s = scale[0]; b = bias[0];",
242 (intervalCount <= 1) ?
"" :
"s = scale[1]; b = bias[1];",
244 (intervalCount <= 2) ?
"" :
"s = scale[2]; b = bias[2];",
245 (intervalCount <= 3) ?
"" :
"s = scale[3]; b = bias[3];",
248 (intervalCount <= 4) ?
"" :
"s = scale[4]; b = bias[4];",
249 (intervalCount <= 5) ?
"" :
"s = scale[5]; b = bias[5];",
251 (intervalCount <= 6) ?
"" :
"s = scale[6]; b = bias[6];",
252 (intervalCount <= 7) ?
"" :
"s = scale[7]; b = bias[7];");
256 effects[intervalCount - 1] =
result.effect.release();
259 return GrSkSLFP::Make(effects[intervalCount - 1],
"UnrolledBinaryColorizer",
261 "thresholds1_7", thresholds1_7,
262 "thresholds9_13", thresholds9_13,
264 "bias",
SkSpan(bias, intervalCount));
277 int intervalChunks = intervalCount / 4;
278 int cacheIndex = (size_t)intervalChunks - 1;
280 struct EffectCacheEntry {
286 SkASSERT(cacheIndex >= 0 && cacheIndex < (
int)std::size(effectCache));
287 EffectCacheEntry* cacheEntry = &effectCache[cacheIndex];
289 cacheEntry->once([intervalCount, intervalChunks, cacheEntry] {
306 "uniform half4 thresholds[%d];"
307 "uniform float4 scale[%d];"
308 "uniform float4 bias[%d];"
310 "half4 main(float2 coord) {"
311 "half t = half(coord.x);"
317 "for (int loop = 0; loop < %d; ++loop) {"
318 "if (t < thresholds[chunk].w) {"
323 "chunk = (low + high) / 2;"
328 "if (t < thresholds[chunk].y) {"
329 "pos = (t < thresholds[chunk].x) ? 0 : 1;"
331 "pos = (t < thresholds[chunk].z) ? 2 : 3;"
336 "return t * scale[pos] + bias[pos];"
342 (intervalChunks - 1) / 2,
348 cacheEntry->effect =
result.effect.release();
351 return GrSkSLFP::Make(cacheEntry->effect,
"LoopingBinaryColorizer",
353 "thresholds",
SkSpan((
const SkV4*)thresholds, intervalChunks),
355 "bias",
SkSpan(bias, intervalCount));
372 int intervalCount = 0;
373 for (
int i = 0; i < inputLength - 1; i++) {
374 if (intervalCount >= outputLength) {
396 bias.
store(outBiases + intervalCount);
397 outThresholds[intervalCount] = t1;
400 return intervalCount;
415 if (intervalCount <= 0) {
419 SkRect thresholds1_7 = {thresholds[0], thresholds[1], thresholds[2], thresholds[3]},
420 thresholds9_13 = {thresholds[4], thresholds[5], thresholds[6], 0.0};
438 if (intervalCount <= 0) {
445 int roundedSize = std::max(4,
SkNextPow2(intervalCount));
447 for (; intervalCount < roundedSize; ++intervalCount) {
448 thresholds[intervalCount] = thresholds[intervalCount - 1];
449 scales[intervalCount] = scales[intervalCount - 1];
450 biases[intervalCount] = biases[intervalCount - 1];
473 if (bottomHardStop) {
489 auto intervalsExceedPrecisionLimit = [&]() ->
bool {
499 for (
int i = 0; i <
count - 1; i++) {
509 auto makeDualIntervalColorizer = [&]() -> std::unique_ptr<GrFragmentProcessor> {
516 colors[1], colors[2],
522 colors[2], colors[3],
531 if ((
count <= binaryColorizerLimit) && !intervalsExceedPrecisionLimit()) {
534 std::unique_ptr<GrFragmentProcessor> colorizer = makeDualIntervalColorizer();
561 std::unique_ptr<GrFragmentProcessor> colorizer,
562 std::unique_ptr<GrFragmentProcessor> gradLayout,
565 bool colorsAreOpaque) {
567 "uniform shader colorizer;"
568 "uniform shader gradLayout;"
570 "uniform half4 leftBorderColor;"
571 "uniform half4 rightBorderColor;"
573 "uniform int layoutPreservesOpacity;"
575 "half4 main(float2 coord) {"
576 "half4 t = gradLayout.eval(coord);"
582 "if (!bool(layoutPreservesOpacity) && t.y < 0) {"
585 "outColor = half4(0);"
586 "} else if (t.x < 0) {"
587 "outColor = leftBorderColor;"
588 "} else if (t.x > 1.0) {"
589 "outColor = rightBorderColor;"
593 "outColor = colorizer.eval(t.x0);"
602 bool layoutPreservesOpacity = gradLayout->preservesOpaqueInput();
604 if (colorsAreOpaque && layoutPreservesOpacity) {
608 return GrSkSLFP::Make(effect,
"ClampedGradient",
nullptr, optFlags,
611 "leftBorderColor", leftBorderColor,
612 "rightBorderColor", rightBorderColor,
613 "layoutPreservesOpacity",
614 GrSkSLFP::Specialize<int>(layoutPreservesOpacity));
619 std::unique_ptr<GrFragmentProcessor> colorizer,
620 std::unique_ptr<GrFragmentProcessor> gradLayout,
622 bool colorsAreOpaque) {
624 "uniform shader colorizer;"
625 "uniform shader gradLayout;"
627 "uniform int mirror;"
628 "uniform int layoutPreservesOpacity;"
629 "uniform int useFloorAbsWorkaround;"
631 "half4 main(float2 coord) {"
632 "half4 t = gradLayout.eval(coord);"
634 "if (!bool(layoutPreservesOpacity) && t.y < 0) {"
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)) {"
646 "tiled_t = clamp(tiled_t, -1, 1);"
648 "t.x = abs(tiled_t);"
656 "half4 outColor = colorizer.eval(t.x0);"
665 bool layoutPreservesOpacity = gradLayout->preservesOpaqueInput();
667 if (colorsAreOpaque && layoutPreservesOpacity) {
670 const bool useFloorAbsWorkaround =
671 args.fContext->priv().caps()->shaderCaps()->fMustDoOpBetweenFloorAndAbs;
676 "mirror", GrSkSLFP::Specialize<int>(
mirror),
677 "layoutPreservesOpacity",
678 GrSkSLFP::Specialize<int>(layoutPreservesOpacity),
679 "useFloorAbsWorkaround",
680 GrSkSLFP::Specialize<int>(useFloorAbsWorkaround));
684 std::unique_ptr<GrFragmentProcessor> gradient,
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);
705 "uniform int colorSpace;"
706 "uniform int do_unpremul;"
708 "half4 main(half4 color) {"
709 "return $interpolated_to_rgb_unpremul(color, colorSpace, do_unpremul);"
715 bool inputPremul =
static_cast<bool>(interpolation.
fInPremul);
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:
728 gradient =
GrSkSLFP::Make(effect,
"GradientCS", std::move(gradient),
730 "colorSpace", GrSkSLFP::Specialize<int>(
732 "do_unpremul", GrSkSLFP::Specialize<int>(
733 inputPremul && !allOpaque));
768 intermediateColorSpace, intermediateAlphaType,
769 dstColorSpace, dstAlphaType);
786 return {
false, std::move(fp)};
797 std::unique_ptr<GrFragmentProcessor> layout,
801 if (layout ==
nullptr) {
807 if (!overrideMatrix) {
811 std::tie(success, layout) =
apply_matrix(std::move(layout), mRec, *overrideMatrix);
824 &shader,
args.fDstColorInfo->colorSpace(),
true);
827 const int colorCount = xformedColors.
fColors.
size();
829 bool allOpaque =
true;
830 for (
int i = 0; i < colorCount; i++) {
861 args.fDstColorInfo->colorSpace(),
865 if (colorizer ==
nullptr) {
873 std::unique_ptr<GrFragmentProcessor> gradient;
891 SkPMColor4f borderColors[2] = { colors[0], colors[colorCount - 1] };
896 p.append(SkRasterPipelineOp::load_f32, &ctx);
903 args.fDstColorInfo->colorSpace());
904 p.append(SkRasterPipelineOp::store_f32, &ctx);
908 borderColors[0], borderColors[1], allOpaque);
934 "half4 main(float2 coord) {"
935 "return half4(half(coord.x) + 0.00001, 1, 0, 0);"
944#if defined(GR_TEST_UTILS)
945RandomParams::RandomParams(
SkRandom* random) {
948 fColorCount = random->
nextRangeU(2, kMaxRandomGradientColors);
952 if (fColorCount == 1 || (fColorCount >= 2 && random->
nextBool())) {
955 fStops = fStopStorage;
960 fColorSpace = GrTest::TestColorSpace(random);
964 for (
int i = 0; i < fColorCount; ++i) {
971 fColors[i] = random->
nextU();
975 stop = i < fColorCount - 1 ? stop + random->
nextUScalar1() * (1.f - stop) : 1.f;
std::tuple< bool, std::unique_ptr< GrFragmentProcessor > > GrFPResult
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 std::unique_ptr< GrFragmentProcessor > make_looping_binary_colorizer(const SkPMColor4f *colors, const SkScalar *positions, int count)
static std::unique_ptr< GrFragmentProcessor > make_uniform_colorizer(const SkPMColor4f *colors, const SkScalar *positions, int count, bool premul, const GrFPArgs &args)
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 std::unique_ptr< GrFragmentProcessor > make_dual_interval_colorizer(const SkPMColor4f &c0, const SkPMColor4f &c1, const SkPMColor4f &c2, const SkPMColor4f &c3, float threshold)
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 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 const int kMaxNumCachedGradientBitmaps
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_unrolled_colorizer(int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, SkRect thresholds1_7, SkRect thresholds9_13)
static constexpr int kMaxUnrolledColorCount
static constexpr int kMaxUnrolledIntervalCount
static const SkScalar kLowPrecisionIntervalLimit
static std::unique_ptr< GrFragmentProcessor > make_unrolled_binary_colorizer(const SkPMColor4f *colors, const SkScalar *positions, int count)
static const int kGradientTextureSize
static std::unique_ptr< GrFragmentProcessor > make_looping_colorizer(int intervalCount, const SkPMColor4f *scale, const SkPMColor4f *bias, const SkScalar *thresholds)
static std::unique_ptr< GrFragmentProcessor > make_single_interval_colorizer(const SkPMColor4f &start, const SkPMColor4f &end)
static constexpr bool GrColorTypeIsWiderThan(GrColorType colorType, int n)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
#define SkASSERTF(cond, fmt,...)
static unsigned mirror(SkFixed fx, int max)
constexpr SkPMColor4f SK_PMColor4fTRANSPARENT
SkColorSpace * sk_srgb_singleton()
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
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)
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static bool ok(int result)
static int SkNextPow2(int value)
static int SkNextLog2(uint32_t value)
constexpr bool SkIsPow2(T value)
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
static bool SkScalarNearlyZero(SkScalar x, SkScalar tolerance=SK_ScalarNearlyZero)
static bool SkScalarNearlyEqual(SkScalar x, SkScalar y, SkScalar tolerance=SK_ScalarNearlyZero)
#define SK_ScalarNearlyZero
static constexpr int kSkTileModeCount
static uint32_t premul(uint32_t color)
SkColorSpace * colorSpace() const
void getGradient(const SkPMColor4f *colors, const SkScalar *positions, int count, bool colorsAreOpaque, const SkGradientShader::Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace, SkColorType colorType, SkAlphaType alphaType, SkBitmap *bitmap)
static std::unique_ptr< GrFragmentProcessor > Make(const SkMatrix &matrix, std::unique_ptr< GrFragmentProcessor > child)
@ kCompatibleWithCoverageAsAlpha
static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr< GrFragmentProcessor > child)
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
static std::unique_ptr< GrFragmentProcessor > Make(GrSurfaceProxyView, SkAlphaType, const SkMatrix &=SkMatrix::I(), GrSamplerState::Filter=GrSamplerState::Filter::kNearest, GrSamplerState::MipmapMode mipmapMode=GrSamplerState::MipmapMode::kNone)
Interpolation fInterpolation
bool interpolateInPremul() const
static void AppendInterpolatedToDstStages(SkRasterPipeline *p, SkArenaAlloc *alloc, bool colorsAreOpaque, const Interpolation &interpolation, const SkColorSpace *intermediateColorSpace, const SkColorSpace *dstColorSpace)
const SkMatrix & getGradientMatrix() const
SkTileMode getTileMode() const
static SkMatrix Scale(SkScalar sx, SkScalar sy)
uint32_t nextULessThan(uint32_t count)
uint32_t nextRangeU(uint32_t min, uint32_t max)
static Result MakeForColorFilter(SkString sksl, const Options &)
static Result MakeForShader(SkString sksl, const Options &)
std::tuple< SkMatrix, bool > applyForFragmentProcessor(const SkMatrix &postInv) const
void append(const char text[])
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
static sk_sp< SkShader > MakeLinear()
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
std::unique_ptr< GrFragmentProcessor > MakeGradientFP(const SkGradientBaseShader &shader, const GrFPArgs &args, const SkShaders::MatrixRec &mRec, std::unique_ptr< GrFragmentProcessor > layout, const SkMatrix *overrideMatrix)
static GrFPResult apply_matrix(std::unique_ptr< GrFragmentProcessor > fp, const SkShaders::MatrixRec &rec, const SkMatrix &postInv)
bool fNonconstantArrayIndexSupport
const float * vec() const
static SKVX_ALWAYS_INLINE Vec Load(const void *ptr)
SKVX_ALWAYS_INLINE void store(void *ptr) const