• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 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 "src/gpu/graphite/precompile/PaintOption.h"
9 
10 #include "include/core/SkBlender.h"
11 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
12 #include "include/gpu/graphite/precompile/PrecompileShader.h"
13 #include "src/gpu/graphite/KeyContext.h"
14 #include "src/gpu/graphite/KeyHelpers.h"
15 #include "src/gpu/graphite/PaintParams.h"
16 #include "src/gpu/graphite/PaintParamsKey.h"
17 #include "src/gpu/graphite/PrecompileInternal.h"
18 #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
19 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
20 #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
21 
22 namespace skgpu::graphite {
23 
toKey(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const24 void PaintOption::toKey(const KeyContext& keyContext,
25                         PaintParamsKeyBuilder* keyBuilder,
26                         PipelineDataGatherer* gatherer) const {
27     this->handleDstRead(keyContext, keyBuilder, gatherer);
28 
29     std::optional<SkBlendMode> finalBlendMode = this->finalBlender()
30                                                         ? this->finalBlender()->priv().asBlendMode()
31                                                         : SkBlendMode::kSrcOver;
32     if (fDstReadReq != DstReadRequirement::kNone) {
33         // In this case the blend will have been handled by shader-based blending with the dstRead.
34         finalBlendMode = SkBlendMode::kSrc;
35     }
36 
37     if (fClipShader.first) {
38         ClipShaderBlock::BeginBlock(keyContext, keyBuilder, gatherer);
39             fClipShader.first->priv().addToKey(keyContext, keyBuilder, gatherer,
40                                                fClipShader.second);
41         keyBuilder->endBlock();
42     }
43 
44     // Set the hardware blend mode.
45     SkASSERT(finalBlendMode);
46     BuiltInCodeSnippetID fixedFuncBlendModeID = static_cast<BuiltInCodeSnippetID>(
47             kFixedFunctionBlendModeIDOffset + static_cast<int>(*finalBlendMode));
48 
49     keyBuilder->addBlock(fixedFuncBlendModeID);
50 }
51 
addPaintColorToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const52 void PaintOption::addPaintColorToKey(const KeyContext& keyContext,
53                                      PaintParamsKeyBuilder* builder,
54                                      PipelineDataGatherer* gatherer) const {
55     if (fShader.first) {
56         fShader.first->priv().addToKey(keyContext, builder, gatherer, fShader.second);
57     } else {
58         RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
59     }
60 }
61 
handlePrimitiveColor(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const62 void PaintOption::handlePrimitiveColor(const KeyContext& keyContext,
63                                        PaintParamsKeyBuilder* keyBuilder,
64                                        PipelineDataGatherer* gatherer) const {
65     if (fHasPrimitiveBlender) {
66         Blend(keyContext, keyBuilder, gatherer,
67               /* addBlendToKey= */ [&] () -> void {
68                   // TODO: Support runtime blenders for primitive blending in the precompile API.
69                   // In the meantime, assume for now that we're using kSrcOver here.
70                   AddToKey(keyContext, keyBuilder, gatherer,
71                            SkBlender::Mode(SkBlendMode::kSrcOver).get());
72               },
73               /* addSrcToKey= */ [&]() -> void {
74                   this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
75               },
76               /* addDstToKey= */ [&]() -> void {
77                   keyBuilder->addBlock(BuiltInCodeSnippetID::kPrimitiveColor);
78               });
79     } else {
80         this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
81     }
82 }
83 
handlePaintAlpha(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const84 void PaintOption::handlePaintAlpha(const KeyContext& keyContext,
85                                    PaintParamsKeyBuilder* keyBuilder,
86                                    PipelineDataGatherer* gatherer) const {
87 
88     if (!fShader.first && !fHasPrimitiveBlender) {
89         // If there is no shader and no primitive blending the input to the colorFilter stage
90         // is just the premultiplied paint color.
91         SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, SK_PMColor4fWHITE);
92         return;
93     }
94 
95     if (!fOpaquePaintColor) {
96         Blend(keyContext, keyBuilder, gatherer,
97               /* addBlendToKey= */ [&] () -> void {
98                   AddKnownModeBlend(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
99               },
100               /* addSrcToKey= */ [&]() -> void {
101                   this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
102               },
103               /* addDstToKey= */ [&]() -> void {
104                   AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
105               });
106     } else {
107         this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
108     }
109 }
110 
handleColorFilter(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const111 void PaintOption::handleColorFilter(const KeyContext& keyContext,
112                                     PaintParamsKeyBuilder* builder,
113                                     PipelineDataGatherer* gatherer) const {
114     if (fColorFilter.first) {
115         Compose(keyContext, builder, gatherer,
116                 /* addInnerToKey= */ [&]() -> void {
117                     this->handlePaintAlpha(keyContext, builder, gatherer);
118                 },
119                 /* addOuterToKey= */ [&]() -> void {
120                     fColorFilter.first->priv().addToKey(keyContext, builder, gatherer,
121                                                         fColorFilter.second);
122                 });
123     } else {
124         this->handlePaintAlpha(keyContext, builder, gatherer);
125     }
126 }
127 
128 // This should be kept in sync w/ SkPaintPriv::ShouldDither and PaintParams::should_dither
shouldDither(SkColorType dstCT) const129 bool PaintOption::shouldDither(SkColorType dstCT) const {
130     // The paint dither flag can veto.
131     if (!fDither) {
132         return false;
133     }
134 
135     if (dstCT == kUnknown_SkColorType) {
136         return false;
137     }
138 
139     // We always dither 565 or 4444 when requested.
140     if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
141         return true;
142     }
143 
144     // Otherwise, dither is only needed for non-const paints.
145     return fShader.first && !fShader.first->priv().isConstant(fShader.second);
146 }
147 
handleDithering(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const148 void PaintOption::handleDithering(const KeyContext& keyContext,
149                                   PaintParamsKeyBuilder* builder,
150                                   PipelineDataGatherer* gatherer) const {
151 
152 #ifndef SK_IGNORE_GPU_DITHER
153     SkColorType ct = keyContext.dstColorInfo().colorType();
154     if (this->shouldDither(ct)) {
155         Compose(keyContext, builder, gatherer,
156                 /* addInnerToKey= */ [&]() -> void {
157                     this->handleColorFilter(keyContext, builder, gatherer);
158                 },
159                 /* addOuterToKey= */ [&]() -> void {
160                     AddDitherBlock(keyContext, builder, gatherer, ct);
161                 });
162     } else
163 #endif
164     {
165         this->handleColorFilter(keyContext, builder, gatherer);
166     }
167 }
168 
handleDstRead(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const169 void PaintOption::handleDstRead(const KeyContext& keyContext,
170                                 PaintParamsKeyBuilder* builder,
171                                 PipelineDataGatherer* gatherer) const {
172     if (fDstReadReq != DstReadRequirement::kNone) {
173         Blend(keyContext, builder, gatherer,
174                 /* addBlendToKey= */ [&] () -> void {
175                     if (fFinalBlender.first) {
176                         fFinalBlender.first->priv().addToKey(keyContext, builder, gatherer,
177                                                              fFinalBlender.second);
178                     } else {
179                         AddKnownModeBlend(keyContext, builder, gatherer, SkBlendMode::kSrcOver);
180                     }
181                 },
182                 /* addSrcToKey= */ [&]() -> void {
183                     this->handleDithering(keyContext, builder, gatherer);
184                 },
185                 /* addDstToKey= */ [&]() -> void {
186                     AddDstReadBlock(keyContext, builder, gatherer, fDstReadReq);
187                 });
188     } else {
189         this->handleDithering(keyContext, builder, gatherer);
190     }
191 }
192 
193 } // namespace skgpu::graphite
194