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