xref: /aosp_15_r20/external/skia/src/gpu/graphite/PaintParams.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParams.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlendModeBlender.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkBlenderBase.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkColorSpacePriv.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/effects/colorfilters/SkColorFilterBase.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/Blend.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/DitherUtils.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyContext.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/KeyHelpers.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Log.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PaintParamsKey.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PipelineData.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/RecorderPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/Uniform.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/shaders/SkShaderBase.h"
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker namespace {
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker // This should be kept in sync w/ SkPaintPriv::ShouldDither and PaintOption::shouldDither
should_dither(const PaintParams & p,SkColorType dstCT)32*c8dee2aaSAndroid Build Coastguard Worker bool should_dither(const PaintParams& p, SkColorType dstCT) {
33*c8dee2aaSAndroid Build Coastguard Worker     // The paint dither flag can veto.
34*c8dee2aaSAndroid Build Coastguard Worker     if (!p.dither()) {
35*c8dee2aaSAndroid Build Coastguard Worker         return false;
36*c8dee2aaSAndroid Build Coastguard Worker     }
37*c8dee2aaSAndroid Build Coastguard Worker 
38*c8dee2aaSAndroid Build Coastguard Worker     if (dstCT == kUnknown_SkColorType) {
39*c8dee2aaSAndroid Build Coastguard Worker         return false;
40*c8dee2aaSAndroid Build Coastguard Worker     }
41*c8dee2aaSAndroid Build Coastguard Worker 
42*c8dee2aaSAndroid Build Coastguard Worker     // We always dither 565 or 4444 when requested.
43*c8dee2aaSAndroid Build Coastguard Worker     if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
44*c8dee2aaSAndroid Build Coastguard Worker         return true;
45*c8dee2aaSAndroid Build Coastguard Worker     }
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker     // Otherwise, dither is only needed for non-const paints.
48*c8dee2aaSAndroid Build Coastguard Worker     return p.shader() && !as_SB(p.shader())->isConstant();
49*c8dee2aaSAndroid Build Coastguard Worker }
50*c8dee2aaSAndroid Build Coastguard Worker 
51*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
52*c8dee2aaSAndroid Build Coastguard Worker 
PaintParams(const SkPaint & paint,sk_sp<SkBlender> primitiveBlender,const CircularRRectClip & analyticClip,sk_sp<SkShader> clipShader,DstReadRequirement dstReadReq,bool skipColorXform)53*c8dee2aaSAndroid Build Coastguard Worker PaintParams::PaintParams(const SkPaint& paint,
54*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<SkBlender> primitiveBlender,
55*c8dee2aaSAndroid Build Coastguard Worker                          const CircularRRectClip& analyticClip,
56*c8dee2aaSAndroid Build Coastguard Worker                          sk_sp<SkShader> clipShader,
57*c8dee2aaSAndroid Build Coastguard Worker                          DstReadRequirement dstReadReq,
58*c8dee2aaSAndroid Build Coastguard Worker                          bool skipColorXform)
59*c8dee2aaSAndroid Build Coastguard Worker         : fColor(paint.getColor4f())
60*c8dee2aaSAndroid Build Coastguard Worker         , fFinalBlender(paint.refBlender())
61*c8dee2aaSAndroid Build Coastguard Worker         , fShader(paint.refShader())
62*c8dee2aaSAndroid Build Coastguard Worker         , fColorFilter(paint.refColorFilter())
63*c8dee2aaSAndroid Build Coastguard Worker         , fPrimitiveBlender(std::move(primitiveBlender))
64*c8dee2aaSAndroid Build Coastguard Worker         , fAnalyticClip(analyticClip)
65*c8dee2aaSAndroid Build Coastguard Worker         , fClipShader(std::move(clipShader))
66*c8dee2aaSAndroid Build Coastguard Worker         , fDstReadReq(dstReadReq)
67*c8dee2aaSAndroid Build Coastguard Worker         , fSkipColorXform(skipColorXform)
68*c8dee2aaSAndroid Build Coastguard Worker         , fDither(paint.isDither()) {}
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker PaintParams::PaintParams(const PaintParams& other) = default;
71*c8dee2aaSAndroid Build Coastguard Worker PaintParams::~PaintParams() = default;
72*c8dee2aaSAndroid Build Coastguard Worker PaintParams& PaintParams::operator=(const PaintParams& other) = default;
73*c8dee2aaSAndroid Build Coastguard Worker 
asFinalBlendMode() const74*c8dee2aaSAndroid Build Coastguard Worker std::optional<SkBlendMode> PaintParams::asFinalBlendMode() const {
75*c8dee2aaSAndroid Build Coastguard Worker     return fFinalBlender ? as_BB(fFinalBlender)->asBlendMode()
76*c8dee2aaSAndroid Build Coastguard Worker                          : SkBlendMode::kSrcOver;
77*c8dee2aaSAndroid Build Coastguard Worker }
78*c8dee2aaSAndroid Build Coastguard Worker 
refFinalBlender() const79*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkBlender> PaintParams::refFinalBlender() const { return fFinalBlender; }
80*c8dee2aaSAndroid Build Coastguard Worker 
refShader() const81*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkShader> PaintParams::refShader() const { return fShader; }
82*c8dee2aaSAndroid Build Coastguard Worker 
refColorFilter() const83*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkColorFilter> PaintParams::refColorFilter() const { return fColorFilter; }
84*c8dee2aaSAndroid Build Coastguard Worker 
refPrimitiveBlender() const85*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkBlender> PaintParams::refPrimitiveBlender() const { return fPrimitiveBlender; }
86*c8dee2aaSAndroid Build Coastguard Worker 
Color4fPrepForDst(SkColor4f srcColor,const SkColorInfo & dstColorInfo)87*c8dee2aaSAndroid Build Coastguard Worker SkColor4f PaintParams::Color4fPrepForDst(SkColor4f srcColor, const SkColorInfo& dstColorInfo) {
88*c8dee2aaSAndroid Build Coastguard Worker     // xform from sRGB to the destination colorspace
89*c8dee2aaSAndroid Build Coastguard Worker     SkColorSpaceXformSteps steps(sk_srgb_singleton(),       kUnpremul_SkAlphaType,
90*c8dee2aaSAndroid Build Coastguard Worker                                  dstColorInfo.colorSpace(), kUnpremul_SkAlphaType);
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker     SkColor4f result = srcColor;
93*c8dee2aaSAndroid Build Coastguard Worker     steps.apply(result.vec());
94*c8dee2aaSAndroid Build Coastguard Worker     return result;
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker 
Blend(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer,AddToKeyFn addBlendToKey,AddToKeyFn addSrcToKey,AddToKeyFn addDstToKey)97*c8dee2aaSAndroid Build Coastguard Worker void Blend(const KeyContext& keyContext,
98*c8dee2aaSAndroid Build Coastguard Worker            PaintParamsKeyBuilder* keyBuilder,
99*c8dee2aaSAndroid Build Coastguard Worker            PipelineDataGatherer* gatherer,
100*c8dee2aaSAndroid Build Coastguard Worker            AddToKeyFn addBlendToKey,
101*c8dee2aaSAndroid Build Coastguard Worker            AddToKeyFn addSrcToKey,
102*c8dee2aaSAndroid Build Coastguard Worker            AddToKeyFn addDstToKey) {
103*c8dee2aaSAndroid Build Coastguard Worker     BlendComposeBlock::BeginBlock(keyContext, keyBuilder, gatherer);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker         addSrcToKey();
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker         addDstToKey();
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker         addBlendToKey();
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker     keyBuilder->endBlock();  // BlendComposeBlock
112*c8dee2aaSAndroid Build Coastguard Worker }
113*c8dee2aaSAndroid Build Coastguard Worker 
Compose(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer,AddToKeyFn addInnerToKey,AddToKeyFn addOuterToKey)114*c8dee2aaSAndroid Build Coastguard Worker void Compose(const KeyContext& keyContext,
115*c8dee2aaSAndroid Build Coastguard Worker              PaintParamsKeyBuilder* keyBuilder,
116*c8dee2aaSAndroid Build Coastguard Worker              PipelineDataGatherer* gatherer,
117*c8dee2aaSAndroid Build Coastguard Worker              AddToKeyFn addInnerToKey,
118*c8dee2aaSAndroid Build Coastguard Worker              AddToKeyFn addOuterToKey) {
119*c8dee2aaSAndroid Build Coastguard Worker     ComposeBlock::BeginBlock(keyContext, keyBuilder, gatherer);
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker         addInnerToKey();
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker         addOuterToKey();
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker     keyBuilder->endBlock();  // ComposeBlock
126*c8dee2aaSAndroid Build Coastguard Worker }
127*c8dee2aaSAndroid Build Coastguard Worker 
AddFixedBlendMode(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,SkBlendMode bm)128*c8dee2aaSAndroid Build Coastguard Worker void AddFixedBlendMode(const KeyContext& keyContext,
129*c8dee2aaSAndroid Build Coastguard Worker                        PaintParamsKeyBuilder* builder,
130*c8dee2aaSAndroid Build Coastguard Worker                        PipelineDataGatherer* gatherer,
131*c8dee2aaSAndroid Build Coastguard Worker                        SkBlendMode bm) {
132*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(bm <= SkBlendMode::kLastMode);
133*c8dee2aaSAndroid Build Coastguard Worker     BuiltInCodeSnippetID id = static_cast<BuiltInCodeSnippetID>(kFixedBlendIDOffset +
134*c8dee2aaSAndroid Build Coastguard Worker                                                                 static_cast<int>(bm));
135*c8dee2aaSAndroid Build Coastguard Worker     builder->addBlock(id);
136*c8dee2aaSAndroid Build Coastguard Worker }
137*c8dee2aaSAndroid Build Coastguard Worker 
AddBlendMode(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,SkBlendMode bm)138*c8dee2aaSAndroid Build Coastguard Worker void AddBlendMode(const KeyContext& keyContext,
139*c8dee2aaSAndroid Build Coastguard Worker                   PaintParamsKeyBuilder* builder,
140*c8dee2aaSAndroid Build Coastguard Worker                   PipelineDataGatherer* gatherer,
141*c8dee2aaSAndroid Build Coastguard Worker                   SkBlendMode bm) {
142*c8dee2aaSAndroid Build Coastguard Worker     // For non-fixed blends, coefficient blend modes are combined into the same shader snippet.
143*c8dee2aaSAndroid Build Coastguard Worker     // The same goes for the HSLC advanced blends. The remaining advanced blends are fairly unique
144*c8dee2aaSAndroid Build Coastguard Worker     // in their implementations. To avoid having to compile all of their SkSL, they are treated as
145*c8dee2aaSAndroid Build Coastguard Worker     // fixed blend modes.
146*c8dee2aaSAndroid Build Coastguard Worker     SkSpan<const float> coeffs = skgpu::GetPorterDuffBlendConstants(bm);
147*c8dee2aaSAndroid Build Coastguard Worker     if (!coeffs.empty()) {
148*c8dee2aaSAndroid Build Coastguard Worker         PorterDuffBlenderBlock::AddBlock(keyContext, builder, gatherer, coeffs);
149*c8dee2aaSAndroid Build Coastguard Worker     } else if (bm >= SkBlendMode::kHue) {
150*c8dee2aaSAndroid Build Coastguard Worker         ReducedBlendModeInfo blendInfo = GetReducedBlendModeInfo(bm);
151*c8dee2aaSAndroid Build Coastguard Worker         HSLCBlenderBlock::AddBlock(keyContext, builder, gatherer, blendInfo.fUniformData);
152*c8dee2aaSAndroid Build Coastguard Worker     } else {
153*c8dee2aaSAndroid Build Coastguard Worker         AddFixedBlendMode(keyContext, builder, gatherer, bm);
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
AddDitherBlock(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer,SkColorType ct)157*c8dee2aaSAndroid Build Coastguard Worker void AddDitherBlock(const KeyContext& keyContext,
158*c8dee2aaSAndroid Build Coastguard Worker                     PaintParamsKeyBuilder* builder,
159*c8dee2aaSAndroid Build Coastguard Worker                     PipelineDataGatherer* gatherer,
160*c8dee2aaSAndroid Build Coastguard Worker                     SkColorType ct) {
161*c8dee2aaSAndroid Build Coastguard Worker     static const SkBitmap gLUT = skgpu::MakeDitherLUT();
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<TextureProxy> proxy = RecorderPriv::CreateCachedProxy(keyContext.recorder(), gLUT,
164*c8dee2aaSAndroid Build Coastguard Worker                                                                 "DitherLUT");
165*c8dee2aaSAndroid Build Coastguard Worker     if (keyContext.recorder() && !proxy) {
166*c8dee2aaSAndroid Build Coastguard Worker         SKGPU_LOG_W("Couldn't create dither shader's LUT");
167*c8dee2aaSAndroid Build Coastguard Worker         builder->addBlock(BuiltInCodeSnippetID::kPriorOutput);
168*c8dee2aaSAndroid Build Coastguard Worker         return;
169*c8dee2aaSAndroid Build Coastguard Worker     }
170*c8dee2aaSAndroid Build Coastguard Worker 
171*c8dee2aaSAndroid Build Coastguard Worker     DitherShaderBlock::DitherData data(skgpu::DitherRangeForConfig(ct), std::move(proxy));
172*c8dee2aaSAndroid Build Coastguard Worker 
173*c8dee2aaSAndroid Build Coastguard Worker     DitherShaderBlock::AddBlock(keyContext, builder, gatherer, data);
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker 
addPaintColorToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const176*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::addPaintColorToKey(const KeyContext& keyContext,
177*c8dee2aaSAndroid Build Coastguard Worker                                      PaintParamsKeyBuilder* keyBuilder,
178*c8dee2aaSAndroid Build Coastguard Worker                                      PipelineDataGatherer* gatherer) const {
179*c8dee2aaSAndroid Build Coastguard Worker     if (fShader) {
180*c8dee2aaSAndroid Build Coastguard Worker         AddToKey(keyContext, keyBuilder, gatherer, fShader.get());
181*c8dee2aaSAndroid Build Coastguard Worker     } else {
182*c8dee2aaSAndroid Build Coastguard Worker         RGBPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
183*c8dee2aaSAndroid Build Coastguard Worker     }
184*c8dee2aaSAndroid Build Coastguard Worker }
185*c8dee2aaSAndroid Build Coastguard Worker 
186*c8dee2aaSAndroid Build Coastguard Worker /**
187*c8dee2aaSAndroid Build Coastguard Worker  * Primitive blend blocks are used to blend either the paint color or the output of another shader
188*c8dee2aaSAndroid Build Coastguard Worker  * with a primitive color emitted by certain draw geometry calls (drawVertices, drawAtlas, etc.).
189*c8dee2aaSAndroid Build Coastguard Worker  * Dst: primitiveColor Src: Paint color/shader output
190*c8dee2aaSAndroid Build Coastguard Worker  */
handlePrimitiveColor(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const191*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::handlePrimitiveColor(const KeyContext& keyContext,
192*c8dee2aaSAndroid Build Coastguard Worker                                        PaintParamsKeyBuilder* keyBuilder,
193*c8dee2aaSAndroid Build Coastguard Worker                                        PipelineDataGatherer* gatherer) const {
194*c8dee2aaSAndroid Build Coastguard Worker     if (fPrimitiveBlender) {
195*c8dee2aaSAndroid Build Coastguard Worker         Blend(keyContext, keyBuilder, gatherer,
196*c8dee2aaSAndroid Build Coastguard Worker               /* addBlendToKey= */ [&] () -> void {
197*c8dee2aaSAndroid Build Coastguard Worker                   AddToKey(keyContext, keyBuilder, gatherer, fPrimitiveBlender.get());
198*c8dee2aaSAndroid Build Coastguard Worker               },
199*c8dee2aaSAndroid Build Coastguard Worker               /* addSrcToKey= */ [&]() -> void {
200*c8dee2aaSAndroid Build Coastguard Worker                   this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
201*c8dee2aaSAndroid Build Coastguard Worker               },
202*c8dee2aaSAndroid Build Coastguard Worker               /* addDstToKey= */ [&]() -> void {
203*c8dee2aaSAndroid Build Coastguard Worker                   PrimitiveColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
204*c8dee2aaSAndroid Build Coastguard Worker               });
205*c8dee2aaSAndroid Build Coastguard Worker     } else {
206*c8dee2aaSAndroid Build Coastguard Worker         this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
207*c8dee2aaSAndroid Build Coastguard Worker     }
208*c8dee2aaSAndroid Build Coastguard Worker }
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker // Apply the paint's alpha value.
handlePaintAlpha(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const211*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::handlePaintAlpha(const KeyContext& keyContext,
212*c8dee2aaSAndroid Build Coastguard Worker                                    PaintParamsKeyBuilder* keyBuilder,
213*c8dee2aaSAndroid Build Coastguard Worker                                    PipelineDataGatherer* gatherer) const {
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker     if (!fShader && !fPrimitiveBlender) {
216*c8dee2aaSAndroid Build Coastguard Worker         // If there is no shader and no primitive blending the input to the colorFilter stage
217*c8dee2aaSAndroid Build Coastguard Worker         // is just the premultiplied paint color.
218*c8dee2aaSAndroid Build Coastguard Worker         SkPMColor4f paintColor = PaintParams::Color4fPrepForDst(fColor,
219*c8dee2aaSAndroid Build Coastguard Worker                                                                 keyContext.dstColorInfo()).premul();
220*c8dee2aaSAndroid Build Coastguard Worker         SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, paintColor);
221*c8dee2aaSAndroid Build Coastguard Worker         return;
222*c8dee2aaSAndroid Build Coastguard Worker     }
223*c8dee2aaSAndroid Build Coastguard Worker 
224*c8dee2aaSAndroid Build Coastguard Worker     if (fColor.fA != 1.0f) {
225*c8dee2aaSAndroid Build Coastguard Worker         Blend(keyContext, keyBuilder, gatherer,
226*c8dee2aaSAndroid Build Coastguard Worker               /* addBlendToKey= */ [&] () -> void {
227*c8dee2aaSAndroid Build Coastguard Worker                   AddFixedBlendMode(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
228*c8dee2aaSAndroid Build Coastguard Worker               },
229*c8dee2aaSAndroid Build Coastguard Worker               /* addSrcToKey= */ [&]() -> void {
230*c8dee2aaSAndroid Build Coastguard Worker                   this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
231*c8dee2aaSAndroid Build Coastguard Worker               },
232*c8dee2aaSAndroid Build Coastguard Worker               /* addDstToKey= */ [&]() -> void {
233*c8dee2aaSAndroid Build Coastguard Worker                   AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
234*c8dee2aaSAndroid Build Coastguard Worker               });
235*c8dee2aaSAndroid Build Coastguard Worker     } else {
236*c8dee2aaSAndroid Build Coastguard Worker         this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
237*c8dee2aaSAndroid Build Coastguard Worker     }
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker 
handleColorFilter(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const240*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::handleColorFilter(const KeyContext& keyContext,
241*c8dee2aaSAndroid Build Coastguard Worker                                     PaintParamsKeyBuilder* builder,
242*c8dee2aaSAndroid Build Coastguard Worker                                     PipelineDataGatherer* gatherer) const {
243*c8dee2aaSAndroid Build Coastguard Worker     if (fColorFilter) {
244*c8dee2aaSAndroid Build Coastguard Worker         Compose(keyContext, builder, gatherer,
245*c8dee2aaSAndroid Build Coastguard Worker                 /* addInnerToKey= */ [&]() -> void {
246*c8dee2aaSAndroid Build Coastguard Worker                     this->handlePaintAlpha(keyContext, builder, gatherer);
247*c8dee2aaSAndroid Build Coastguard Worker                 },
248*c8dee2aaSAndroid Build Coastguard Worker                 /* addOuterToKey= */ [&]() -> void {
249*c8dee2aaSAndroid Build Coastguard Worker                     AddToKey(keyContext, builder, gatherer, fColorFilter.get());
250*c8dee2aaSAndroid Build Coastguard Worker                 });
251*c8dee2aaSAndroid Build Coastguard Worker     } else {
252*c8dee2aaSAndroid Build Coastguard Worker         this->handlePaintAlpha(keyContext, builder, gatherer);
253*c8dee2aaSAndroid Build Coastguard Worker     }
254*c8dee2aaSAndroid Build Coastguard Worker }
255*c8dee2aaSAndroid Build Coastguard Worker 
handleDithering(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const256*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::handleDithering(const KeyContext& keyContext,
257*c8dee2aaSAndroid Build Coastguard Worker                                   PaintParamsKeyBuilder* builder,
258*c8dee2aaSAndroid Build Coastguard Worker                                   PipelineDataGatherer* gatherer) const {
259*c8dee2aaSAndroid Build Coastguard Worker 
260*c8dee2aaSAndroid Build Coastguard Worker #ifndef SK_IGNORE_GPU_DITHER
261*c8dee2aaSAndroid Build Coastguard Worker     SkColorType ct = keyContext.dstColorInfo().colorType();
262*c8dee2aaSAndroid Build Coastguard Worker     if (should_dither(*this, ct)) {
263*c8dee2aaSAndroid Build Coastguard Worker         Compose(keyContext, builder, gatherer,
264*c8dee2aaSAndroid Build Coastguard Worker                 /* addInnerToKey= */ [&]() -> void {
265*c8dee2aaSAndroid Build Coastguard Worker                     this->handleColorFilter(keyContext, builder, gatherer);
266*c8dee2aaSAndroid Build Coastguard Worker                 },
267*c8dee2aaSAndroid Build Coastguard Worker                 /* addOuterToKey= */ [&]() -> void {
268*c8dee2aaSAndroid Build Coastguard Worker                     AddDitherBlock(keyContext, builder, gatherer, ct);
269*c8dee2aaSAndroid Build Coastguard Worker                 });
270*c8dee2aaSAndroid Build Coastguard Worker     } else
271*c8dee2aaSAndroid Build Coastguard Worker #endif
272*c8dee2aaSAndroid Build Coastguard Worker     {
273*c8dee2aaSAndroid Build Coastguard Worker         this->handleColorFilter(keyContext, builder, gatherer);
274*c8dee2aaSAndroid Build Coastguard Worker     }
275*c8dee2aaSAndroid Build Coastguard Worker }
276*c8dee2aaSAndroid Build Coastguard Worker 
handleClipping(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const277*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::handleClipping(const KeyContext& keyContext,
278*c8dee2aaSAndroid Build Coastguard Worker                                  PaintParamsKeyBuilder* builder,
279*c8dee2aaSAndroid Build Coastguard Worker                                  PipelineDataGatherer* gatherer) const {
280*c8dee2aaSAndroid Build Coastguard Worker     if (!fAnalyticClip.isEmpty()) {
281*c8dee2aaSAndroid Build Coastguard Worker         float radius = fAnalyticClip.fRadius + 0.5f;
282*c8dee2aaSAndroid Build Coastguard Worker         // N.B.: Because the clip data is normally used with depth-based clipping,
283*c8dee2aaSAndroid Build Coastguard Worker         // the shape is inverted from its usual state. We re-invert here to
284*c8dee2aaSAndroid Build Coastguard Worker         // match what the shader snippet expects.
285*c8dee2aaSAndroid Build Coastguard Worker         SkPoint radiusPair = {(fAnalyticClip.fInverted) ? radius : -radius, 1.0f/radius};
286*c8dee2aaSAndroid Build Coastguard Worker         CircularRRectClipBlock::CircularRRectClipData data(
287*c8dee2aaSAndroid Build Coastguard Worker                 fAnalyticClip.fBounds.makeOutset(0.5f).asSkRect(),
288*c8dee2aaSAndroid Build Coastguard Worker                 radiusPair,
289*c8dee2aaSAndroid Build Coastguard Worker                 fAnalyticClip.edgeSelectRect());
290*c8dee2aaSAndroid Build Coastguard Worker         if (fClipShader) {
291*c8dee2aaSAndroid Build Coastguard Worker             // For both an analytic clip and clip shader, we need to compose them together into
292*c8dee2aaSAndroid Build Coastguard Worker             // a single clipping root node.
293*c8dee2aaSAndroid Build Coastguard Worker             Blend(keyContext, builder, gatherer,
294*c8dee2aaSAndroid Build Coastguard Worker                   /* addBlendToKey= */ [&]() -> void {
295*c8dee2aaSAndroid Build Coastguard Worker                       AddFixedBlendMode(keyContext, builder, gatherer, SkBlendMode::kModulate);
296*c8dee2aaSAndroid Build Coastguard Worker                   },
297*c8dee2aaSAndroid Build Coastguard Worker                   /* addSrcToKey= */ [&]() -> void {
298*c8dee2aaSAndroid Build Coastguard Worker                       CircularRRectClipBlock::AddBlock(keyContext, builder, gatherer, data);
299*c8dee2aaSAndroid Build Coastguard Worker                   },
300*c8dee2aaSAndroid Build Coastguard Worker                   /* addDstToKey= */ [&]() -> void {
301*c8dee2aaSAndroid Build Coastguard Worker                       AddToKey(keyContext, builder, gatherer, fClipShader.get());
302*c8dee2aaSAndroid Build Coastguard Worker                   });
303*c8dee2aaSAndroid Build Coastguard Worker         } else {
304*c8dee2aaSAndroid Build Coastguard Worker             // Without a clip shader, the analytic clip can be the clipping root node.
305*c8dee2aaSAndroid Build Coastguard Worker             CircularRRectClipBlock::AddBlock(keyContext, builder, gatherer, data);
306*c8dee2aaSAndroid Build Coastguard Worker         }
307*c8dee2aaSAndroid Build Coastguard Worker     } else if (fClipShader) {
308*c8dee2aaSAndroid Build Coastguard Worker         // Since there's no analytic clip, the clipping root node can be fClipShader directly.
309*c8dee2aaSAndroid Build Coastguard Worker         AddToKey(keyContext, builder, gatherer, fClipShader.get());
310*c8dee2aaSAndroid Build Coastguard Worker     }
311*c8dee2aaSAndroid Build Coastguard Worker }
312*c8dee2aaSAndroid Build Coastguard Worker 
toKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const313*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::toKey(const KeyContext& keyContext,
314*c8dee2aaSAndroid Build Coastguard Worker                         PaintParamsKeyBuilder* builder,
315*c8dee2aaSAndroid Build Coastguard Worker                         PipelineDataGatherer* gatherer) const {
316*c8dee2aaSAndroid Build Coastguard Worker     // Root Node 0 is the source color, which is the output of all effects post dithering
317*c8dee2aaSAndroid Build Coastguard Worker     this->handleDithering(keyContext, builder, gatherer);
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker     // Root Node 1 is the final blender
320*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkBlendMode> finalBlendMode = this->asFinalBlendMode();
321*c8dee2aaSAndroid Build Coastguard Worker     if (finalBlendMode) {
322*c8dee2aaSAndroid Build Coastguard Worker         if (fDstReadReq == DstReadRequirement::kNone) {
323*c8dee2aaSAndroid Build Coastguard Worker             // With no shader blending, be as explicit as possible about the final blend
324*c8dee2aaSAndroid Build Coastguard Worker             AddFixedBlendMode(keyContext, builder, gatherer, *finalBlendMode);
325*c8dee2aaSAndroid Build Coastguard Worker         } else {
326*c8dee2aaSAndroid Build Coastguard Worker             // With shader blending, use AddBlendMode() to select the more universal blend functions
327*c8dee2aaSAndroid Build Coastguard Worker             // when possible. Technically we could always use a fixed blend mode but would then
328*c8dee2aaSAndroid Build Coastguard Worker             // over-generate when encountering certain classes of blends. This is most problematic
329*c8dee2aaSAndroid Build Coastguard Worker             // on devices that wouldn't support dual-source blending, so help them out by at least
330*c8dee2aaSAndroid Build Coastguard Worker             // not requiring lots of pipelines.
331*c8dee2aaSAndroid Build Coastguard Worker             AddBlendMode(keyContext, builder, gatherer, *finalBlendMode);
332*c8dee2aaSAndroid Build Coastguard Worker         }
333*c8dee2aaSAndroid Build Coastguard Worker     } else {
334*c8dee2aaSAndroid Build Coastguard Worker         AddToKey(keyContext, builder, gatherer, fFinalBlender.get());
335*c8dee2aaSAndroid Build Coastguard Worker     }
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker     // Optional Root Node 2 is the clip
338*c8dee2aaSAndroid Build Coastguard Worker     this->handleClipping(keyContext, builder, gatherer);
339*c8dee2aaSAndroid Build Coastguard Worker }
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker // TODO(b/330864257): Can be deleted once keys are determined by the Device draw.
notifyImagesInUse(Recorder * recorder,DrawContext * drawContext) const342*c8dee2aaSAndroid Build Coastguard Worker void PaintParams::notifyImagesInUse(Recorder* recorder,
343*c8dee2aaSAndroid Build Coastguard Worker                                     DrawContext* drawContext) const {
344*c8dee2aaSAndroid Build Coastguard Worker     if (fShader) {
345*c8dee2aaSAndroid Build Coastguard Worker         NotifyImagesInUse(recorder, drawContext, fShader.get());
346*c8dee2aaSAndroid Build Coastguard Worker     }
347*c8dee2aaSAndroid Build Coastguard Worker     if (fPrimitiveBlender) {
348*c8dee2aaSAndroid Build Coastguard Worker         NotifyImagesInUse(recorder, drawContext, fPrimitiveBlender.get());
349*c8dee2aaSAndroid Build Coastguard Worker     }
350*c8dee2aaSAndroid Build Coastguard Worker     if (fColorFilter) {
351*c8dee2aaSAndroid Build Coastguard Worker         NotifyImagesInUse(recorder, drawContext, fColorFilter.get());
352*c8dee2aaSAndroid Build Coastguard Worker     }
353*c8dee2aaSAndroid Build Coastguard Worker     if (fFinalBlender) {
354*c8dee2aaSAndroid Build Coastguard Worker         NotifyImagesInUse(recorder, drawContext, fFinalBlender.get());
355*c8dee2aaSAndroid Build Coastguard Worker     }
356*c8dee2aaSAndroid Build Coastguard Worker     if (fClipShader) {
357*c8dee2aaSAndroid Build Coastguard Worker         NotifyImagesInUse(recorder, drawContext, fClipShader.get());
358*c8dee2aaSAndroid Build Coastguard Worker     }
359*c8dee2aaSAndroid Build Coastguard Worker }
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
362