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