xref: /aosp_15_r20/external/skia/src/gpu/graphite/precompile/PaintOption.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/PrecompileColorFilter.h"
13 #include "include/gpu/graphite/precompile/PrecompileShader.h"
14 #include "src/gpu/graphite/KeyContext.h"
15 #include "src/gpu/graphite/KeyHelpers.h"
16 #include "src/gpu/graphite/PaintParams.h"
17 #include "src/gpu/graphite/PaintParamsKey.h"
18 #include "src/gpu/graphite/PrecompileInternal.h"
19 #include "src/gpu/graphite/precompile/PrecompileBasePriv.h"
20 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
21 #include "src/gpu/graphite/precompile/PrecompileShaderPriv.h"
22 
23 namespace skgpu::graphite {
24 
toKey(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const25 void PaintOption::toKey(const KeyContext& keyContext,
26                         PaintParamsKeyBuilder* keyBuilder,
27                         PipelineDataGatherer* gatherer) const {
28     // Root Node 0 is the source color, which is the output of all effects post dithering
29     this->handleDithering(keyContext, keyBuilder, gatherer);
30 
31     // Root Node 1 is the final blender
32     std::optional<SkBlendMode> finalBlendMode = this->finalBlender()
33                                                         ? this->finalBlender()->priv().asBlendMode()
34                                                         : SkBlendMode::kSrcOver;
35     if (finalBlendMode) {
36         if (fDstReadReq == DstReadRequirement::kNone) {
37             AddFixedBlendMode(keyContext, keyBuilder, gatherer, *finalBlendMode);
38         } else {
39             AddBlendMode(keyContext, keyBuilder, gatherer, *finalBlendMode);
40         }
41     } else {
42         SkASSERT(this->finalBlender());
43         fFinalBlender.first->priv().addToKey(keyContext, keyBuilder, gatherer,
44                                              fFinalBlender.second);
45     }
46 
47     // Optional Root Node 2 is the clip
48     // TODO(b/372221436): Also include analytic clippiing in this node.
49     if (fClipShader.first) {
50         fClipShader.first->priv().addToKey(keyContext, keyBuilder, gatherer,
51                                            fClipShader.second);
52     }
53 }
54 
addPaintColorToKey(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const55 void PaintOption::addPaintColorToKey(const KeyContext& keyContext,
56                                      PaintParamsKeyBuilder* builder,
57                                      PipelineDataGatherer* gatherer) const {
58     if (fShader.first) {
59         fShader.first->priv().addToKey(keyContext, builder, gatherer, fShader.second);
60     } else {
61         RGBPaintColorBlock::AddBlock(keyContext, builder, gatherer);
62     }
63 }
64 
handlePrimitiveColor(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const65 void PaintOption::handlePrimitiveColor(const KeyContext& keyContext,
66                                        PaintParamsKeyBuilder* keyBuilder,
67                                        PipelineDataGatherer* gatherer) const {
68     if (fHasPrimitiveBlender) {
69         Blend(keyContext, keyBuilder, gatherer,
70               /* addBlendToKey= */ [&] () -> void {
71                   // TODO: Support runtime blenders for primitive blending in the precompile API.
72                   // In the meantime, assume for now that we're using kSrcOver here.
73                   AddToKey(keyContext, keyBuilder, gatherer,
74                            SkBlender::Mode(SkBlendMode::kSrcOver).get());
75               },
76               /* addSrcToKey= */ [&]() -> void {
77                   this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
78               },
79               /* addDstToKey= */ [&]() -> void {
80                   PrimitiveColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
81               });
82     } else {
83         this->addPaintColorToKey(keyContext, keyBuilder, gatherer);
84     }
85 }
86 
handlePaintAlpha(const KeyContext & keyContext,PaintParamsKeyBuilder * keyBuilder,PipelineDataGatherer * gatherer) const87 void PaintOption::handlePaintAlpha(const KeyContext& keyContext,
88                                    PaintParamsKeyBuilder* keyBuilder,
89                                    PipelineDataGatherer* gatherer) const {
90 
91     if (!fShader.first && !fHasPrimitiveBlender) {
92         // If there is no shader and no primitive blending the input to the colorFilter stage
93         // is just the premultiplied paint color.
94         SolidColorShaderBlock::AddBlock(keyContext, keyBuilder, gatherer, SK_PMColor4fWHITE);
95         return;
96     }
97 
98     if (!fOpaquePaintColor) {
99         Blend(keyContext, keyBuilder, gatherer,
100               /* addBlendToKey= */ [&] () -> void {
101                   AddFixedBlendMode(keyContext, keyBuilder, gatherer, SkBlendMode::kSrcIn);
102               },
103               /* addSrcToKey= */ [&]() -> void {
104                   this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
105               },
106               /* addDstToKey= */ [&]() -> void {
107                   AlphaOnlyPaintColorBlock::AddBlock(keyContext, keyBuilder, gatherer);
108               });
109     } else {
110         this->handlePrimitiveColor(keyContext, keyBuilder, gatherer);
111     }
112 }
113 
handleColorFilter(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const114 void PaintOption::handleColorFilter(const KeyContext& keyContext,
115                                     PaintParamsKeyBuilder* builder,
116                                     PipelineDataGatherer* gatherer) const {
117     if (fColorFilter.first) {
118         Compose(keyContext, builder, gatherer,
119                 /* addInnerToKey= */ [&]() -> void {
120                     this->handlePaintAlpha(keyContext, builder, gatherer);
121                 },
122                 /* addOuterToKey= */ [&]() -> void {
123                     fColorFilter.first->priv().addToKey(keyContext, builder, gatherer,
124                                                         fColorFilter.second);
125                 });
126     } else {
127         this->handlePaintAlpha(keyContext, builder, gatherer);
128     }
129 }
130 
131 // This should be kept in sync w/ SkPaintPriv::ShouldDither and PaintParams::should_dither
shouldDither(SkColorType dstCT) const132 bool PaintOption::shouldDither(SkColorType dstCT) const {
133     // The paint dither flag can veto.
134     if (!fDither) {
135         return false;
136     }
137 
138     if (dstCT == kUnknown_SkColorType) {
139         return false;
140     }
141 
142     // We always dither 565 or 4444 when requested.
143     if (dstCT == kRGB_565_SkColorType || dstCT == kARGB_4444_SkColorType) {
144         return true;
145     }
146 
147     // Otherwise, dither is only needed for non-const paints.
148     return fShader.first && !fShader.first->priv().isConstant(fShader.second);
149 }
150 
handleDithering(const KeyContext & keyContext,PaintParamsKeyBuilder * builder,PipelineDataGatherer * gatherer) const151 void PaintOption::handleDithering(const KeyContext& keyContext,
152                                   PaintParamsKeyBuilder* builder,
153                                   PipelineDataGatherer* gatherer) const {
154 
155 #ifndef SK_IGNORE_GPU_DITHER
156     SkColorType ct = keyContext.dstColorInfo().colorType();
157     if (this->shouldDither(ct)) {
158         Compose(keyContext, builder, gatherer,
159                 /* addInnerToKey= */ [&]() -> void {
160                     this->handleColorFilter(keyContext, builder, gatherer);
161                 },
162                 /* addOuterToKey= */ [&]() -> void {
163                     AddDitherBlock(keyContext, builder, gatherer, ct);
164                 });
165     } else
166 #endif
167     {
168         this->handleColorFilter(keyContext, builder, gatherer);
169     }
170 }
171 
172 } // namespace skgpu::graphite
173