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