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 "include/gpu/graphite/precompile/PrecompileImageFilter.h"
9
10 #include "include/gpu/graphite/precompile/PrecompileBlender.h"
11 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
12 #include "include/gpu/graphite/precompile/PrecompileShader.h"
13 #include "src/gpu/graphite/Renderer.h"
14 #include "src/gpu/graphite/precompile/PrecompileBlenderPriv.h"
15 #include "src/gpu/graphite/precompile/PrecompileImageFilterPriv.h"
16 #include "src/gpu/graphite/precompile/PrecompileImageFiltersPriv.h"
17 #include "src/gpu/graphite/precompile/PrecompileShadersPriv.h"
18
19 namespace skgpu::graphite {
20
21 //--------------------------------------------------------------------------------------------------
PrecompileImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)22 PrecompileImageFilter::PrecompileImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
23 : PrecompileBase(Type::kImageFilter) {
24 fInputs.reset(inputs.size());
25 for (size_t i = 0; i < inputs.size(); ++i) {
26 fInputs[i] = inputs[i];
27 }
28 }
29
30 PrecompileImageFilter::~PrecompileImageFilter() = default;
31
asAColorFilter() const32 sk_sp<PrecompileColorFilter> PrecompileImageFilter::asAColorFilter() const {
33 sk_sp<PrecompileColorFilter> tmp = this->isColorFilterNode();
34 if (!tmp) {
35 return nullptr;
36 }
37 SkASSERT(this->countInputs() == 1);
38 if (this->getInput(0)) {
39 return nullptr;
40 }
41 // TODO: as in SkImageFilter::asAColorFilter, handle the special case of
42 // affectsTransparentBlack. This is tricky for precompilation since we don't,
43 // necessarily, have all the parameters of the ColorFilter in order to evaluate
44 // filterColor4f(SkColors::kTransparent) - the normal API's implementation.
45 return tmp;
46 }
47
createPipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptions::ProcessCombination & processCombination)48 void PrecompileImageFilter::createPipelines(
49 const KeyContext& keyContext,
50 PipelineDataGatherer* gatherer,
51 const RenderPassDesc& renderPassDesc,
52 const PaintOptions::ProcessCombination& processCombination) {
53 // TODO: we will want to mark already visited nodes to prevent loops and track
54 // already created Pipelines so we don't over-generate too much (e.g., if a DAG
55 // has multiple blurs we don't want to keep trying to create all the blur pipelines).
56 this->onCreatePipelines(keyContext, gatherer, renderPassDesc, processCombination);
57
58 for (const sk_sp<PrecompileImageFilter>& input : fInputs) {
59 if (input) {
60 input->createPipelines(keyContext, gatherer, renderPassDesc, processCombination);
61 }
62 }
63 }
64
65 //--------------------------------------------------------------------------------------------------
66 namespace PrecompileImageFiltersPriv {
67
CreateBlurImageFilterPipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination)68 void CreateBlurImageFilterPipelines(
69 const KeyContext& keyContext,
70 PipelineDataGatherer* gatherer,
71 const RenderPassDesc& renderPassDesc,
72 const PaintOptionsPriv::ProcessCombination& processCombination) {
73
74 PaintOptions blurPaintOptions;
75
76 // For blur imagefilters we know we don't have alpha-only textures and don't need cubic
77 // filtering.
78 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
79 PrecompileImageShaderFlags::kExcludeAlpha | PrecompileImageShaderFlags::kExcludeCubic);
80
81 static const SkBlendMode kBlurBlendModes[] = { SkBlendMode::kSrc };
82 blurPaintOptions.setShaders({ PrecompileShadersPriv::Blur(imageShader) });
83 blurPaintOptions.setBlendModes(kBlurBlendModes);
84
85 blurPaintOptions.priv().buildCombinations(keyContext,
86 gatherer,
87 DrawTypeFlags::kSimpleShape,
88 /* withPrimitiveBlender= */ false,
89 Coverage::kSingleChannel,
90 renderPassDesc,
91 processCombination);
92 }
93
94 } // namespace PrecompileImageFiltersPriv
95
96 //--------------------------------------------------------------------------------------------------
97 class PrecompileBlendFilterImageFilter : public PrecompileImageFilter {
98 public:
PrecompileBlendFilterImageFilter(sk_sp<PrecompileBlender> blender,SkSpan<sk_sp<PrecompileImageFilter>> inputs)99 PrecompileBlendFilterImageFilter(sk_sp<PrecompileBlender> blender,
100 SkSpan<sk_sp<PrecompileImageFilter>> inputs)
101 : PrecompileImageFilter(std::move(inputs))
102 , fBlender(std::move(blender)) {
103 }
104
105 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const106 void onCreatePipelines(
107 const KeyContext& keyContext,
108 PipelineDataGatherer* gatherer,
109 const RenderPassDesc& renderPassDesc,
110 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
111
112 PaintOptions paintOptions;
113
114 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
115 PrecompileImageShaderFlags::kExcludeAlpha |
116 PrecompileImageShaderFlags::kExcludeCubic);
117
118 sk_sp<PrecompileShader> blendShader = PrecompileShaders::Blend(
119 SkSpan<const sk_sp<PrecompileBlender>>(&fBlender, 1),
120 { imageShader },
121 { imageShader });
122
123 paintOptions.setShaders({ std::move(blendShader) });
124
125 paintOptions.priv().buildCombinations(keyContext,
126 gatherer,
127 DrawTypeFlags::kSimpleShape,
128 /* withPrimitiveBlender= */ false,
129 Coverage::kSingleChannel,
130 renderPassDesc,
131 processCombination);
132 }
133
134 sk_sp<PrecompileBlender> fBlender;
135 };
136
Arithmetic(sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)137 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Arithmetic(
138 sk_sp<PrecompileImageFilter> background,
139 sk_sp<PrecompileImageFilter> foreground) {
140 return Blend(PrecompileBlenders::Arithmetic(), std::move(background), std::move(foreground));
141 }
142
Blend(SkBlendMode bm,sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)143 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blend(
144 SkBlendMode bm,
145 sk_sp<PrecompileImageFilter> background,
146 sk_sp<PrecompileImageFilter> foreground) {
147 return Blend(PrecompileBlenders::Mode(bm), std::move(background), std::move(foreground));
148 }
149
Blend(sk_sp<PrecompileBlender> blender,sk_sp<PrecompileImageFilter> background,sk_sp<PrecompileImageFilter> foreground)150 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blend(
151 sk_sp<PrecompileBlender> blender,
152 sk_sp<PrecompileImageFilter> background,
153 sk_sp<PrecompileImageFilter> foreground) {
154
155 if (!blender) {
156 blender = PrecompileBlenders::Mode(SkBlendMode::kSrcOver);
157 }
158
159 if (std::optional<SkBlendMode> bm = blender->priv().asBlendMode()) {
160 if (bm == SkBlendMode::kSrc) {
161 return foreground;
162 } else if (bm == SkBlendMode::kDst) {
163 return background;
164 } else if (bm == SkBlendMode::kClear) {
165 return nullptr; // TODO: actually return PrecompileImageFilters::Empty
166 }
167 }
168
169 sk_sp<PrecompileImageFilter> inputs[2] = { std::move(background), std::move(foreground) };
170 return sk_make_sp<PrecompileBlendFilterImageFilter>(std::move(blender), inputs);
171 }
172
173 //--------------------------------------------------------------------------------------------------
174 class PrecompileBlurImageFilter : public PrecompileImageFilter {
175 public:
PrecompileBlurImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)176 PrecompileBlurImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
177 : PrecompileImageFilter(std::move(inputs)) {
178 }
179
180 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const181 void onCreatePipelines(
182 const KeyContext& keyContext,
183 PipelineDataGatherer* gatherer,
184 const RenderPassDesc& renderPassDesc,
185 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
186
187 PrecompileImageFiltersPriv::CreateBlurImageFilterPipelines(keyContext, gatherer,
188 renderPassDesc,
189 processCombination);
190 }
191 };
192
Blur(sk_sp<PrecompileImageFilter> input)193 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Blur(
194 sk_sp<PrecompileImageFilter> input) {
195 return sk_make_sp<PrecompileBlurImageFilter>(SkSpan(&input, 1));
196 }
197
198 //--------------------------------------------------------------------------------------------------
199 class PrecompileColorFilterImageFilter : public PrecompileImageFilter {
200 public:
PrecompileColorFilterImageFilter(sk_sp<PrecompileColorFilter> colorFilter,sk_sp<PrecompileImageFilter> input)201 PrecompileColorFilterImageFilter(sk_sp<PrecompileColorFilter> colorFilter,
202 sk_sp<PrecompileImageFilter> input)
203 : PrecompileImageFilter(SkSpan(&input, 1))
204 , fColorFilter(std::move(colorFilter)) {
205 }
206
207 private:
isColorFilterNode() const208 sk_sp<PrecompileColorFilter> isColorFilterNode() const override {
209 return fColorFilter;
210 }
211
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const212 void onCreatePipelines(
213 const KeyContext& keyContext,
214 PipelineDataGatherer* gatherer,
215 const RenderPassDesc& renderPassDesc,
216 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
217 PaintOptions paintOptions;
218
219 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
220 PrecompileImageShaderFlags::kExcludeAlpha |
221 PrecompileImageShaderFlags::kExcludeCubic);
222
223 static const SkBlendMode kBlendModes[] = { SkBlendMode::kDstOut };
224 paintOptions.setShaders({ std::move(imageShader) });
225 paintOptions.setColorFilters({ fColorFilter });
226 paintOptions.setBlendModes(kBlendModes);
227
228 paintOptions.priv().buildCombinations(keyContext,
229 gatherer,
230 DrawTypeFlags::kSimpleShape,
231 /* withPrimitiveBlender= */ false,
232 Coverage::kSingleChannel,
233 renderPassDesc,
234 processCombination);
235 }
236
237 sk_sp<PrecompileColorFilter> fColorFilter;
238 };
239
ColorFilter(sk_sp<PrecompileColorFilter> colorFilter,sk_sp<PrecompileImageFilter> input)240 sk_sp<PrecompileImageFilter> PrecompileImageFilters::ColorFilter(
241 sk_sp<PrecompileColorFilter> colorFilter,
242 sk_sp<PrecompileImageFilter> input) {
243 if (colorFilter && input) {
244 sk_sp<PrecompileColorFilter> inputCF = input->priv().isColorFilterNode();
245 if (inputCF) {
246 colorFilter = colorFilter->makeComposed(std::move(inputCF));
247 input = sk_ref_sp(input->priv().getInput(0));
248 }
249 }
250
251 sk_sp<PrecompileImageFilter> filter = std::move(input);
252 if (colorFilter) {
253 filter = sk_make_sp<PrecompileColorFilterImageFilter>(std::move(colorFilter),
254 std::move(filter));
255 }
256 return filter;
257 }
258
259 //--------------------------------------------------------------------------------------------------
260 class PrecompileDisplacementMapImageFilter : public PrecompileImageFilter {
261 public:
PrecompileDisplacementMapImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)262 PrecompileDisplacementMapImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
263 : PrecompileImageFilter(std::move(inputs)) {
264 }
265
266 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const267 void onCreatePipelines(
268 const KeyContext& keyContext,
269 PipelineDataGatherer* gatherer,
270 const RenderPassDesc& renderPassDesc,
271 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
272
273 PaintOptions displacement;
274
275 // For displacement imagefilters we know we don't have alpha-only textures and don't need
276 // cubic filtering.
277 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
278 PrecompileImageShaderFlags::kExcludeAlpha |
279 PrecompileImageShaderFlags::kExcludeCubic);
280
281 displacement.setShaders({ PrecompileShadersPriv::Displacement(imageShader, imageShader) });
282
283 displacement.priv().buildCombinations(keyContext,
284 gatherer,
285 DrawTypeFlags::kSimpleShape,
286 /* withPrimitiveBlender= */ false,
287 Coverage::kSingleChannel,
288 renderPassDesc,
289 processCombination);
290 }
291 };
292
DisplacementMap(sk_sp<PrecompileImageFilter> input)293 sk_sp<PrecompileImageFilter> PrecompileImageFilters::DisplacementMap(
294 sk_sp<PrecompileImageFilter> input) {
295 return sk_make_sp<PrecompileDisplacementMapImageFilter>(SkSpan(&input, 1));
296 }
297
298 //--------------------------------------------------------------------------------------------------
299 class PrecompileLightingImageFilter : public PrecompileImageFilter {
300 public:
PrecompileLightingImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)301 PrecompileLightingImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
302 : PrecompileImageFilter(std::move(inputs)) {
303 }
304
305 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const306 void onCreatePipelines(
307 const KeyContext& keyContext,
308 PipelineDataGatherer* gatherer,
309 const RenderPassDesc& renderPassDesc,
310 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
311
312 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
313 PrecompileImageShaderFlags::kExcludeAlpha |
314 PrecompileImageShaderFlags::kExcludeCubic);
315
316 PaintOptions lighting;
317 lighting.setShaders({ PrecompileShadersPriv::Lighting(std::move(imageShader)) });
318
319 lighting.priv().buildCombinations(keyContext,
320 gatherer,
321 DrawTypeFlags::kSimpleShape,
322 /* withPrimitiveBlender= */ false,
323 Coverage::kSingleChannel,
324 renderPassDesc,
325 processCombination);
326 }
327 };
328
Lighting(sk_sp<PrecompileImageFilter> input)329 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Lighting(
330 sk_sp<PrecompileImageFilter> input) {
331 return sk_make_sp<PrecompileLightingImageFilter>(SkSpan(&input, 1));
332 }
333
334 //--------------------------------------------------------------------------------------------------
335 class PrecompileMatrixConvolutionImageFilter : public PrecompileImageFilter {
336 public:
PrecompileMatrixConvolutionImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)337 PrecompileMatrixConvolutionImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
338 : PrecompileImageFilter(std::move(inputs)) {
339 }
340
341 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const342 void onCreatePipelines(
343 const KeyContext& keyContext,
344 PipelineDataGatherer* gatherer,
345 const RenderPassDesc& renderPassDesc,
346 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
347
348 PaintOptions matrixConv;
349
350 // For matrix convolution imagefilters we know we don't have alpha-only textures and don't
351 // need cubic filtering.
352 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
353 PrecompileImageShaderFlags::kExcludeAlpha |
354 PrecompileImageShaderFlags::kExcludeCubic);
355
356 matrixConv.setShaders({ PrecompileShadersPriv::MatrixConvolution(imageShader) });
357
358 matrixConv.priv().buildCombinations(keyContext,
359 gatherer,
360 DrawTypeFlags::kSimpleShape,
361 /* withPrimitiveBlender= */ false,
362 Coverage::kSingleChannel,
363 renderPassDesc,
364 processCombination);
365 }
366 };
367
MatrixConvolution(sk_sp<PrecompileImageFilter> input)368 sk_sp<PrecompileImageFilter> PrecompileImageFilters::MatrixConvolution(
369 sk_sp<PrecompileImageFilter> input) {
370 return sk_make_sp<PrecompileMatrixConvolutionImageFilter>(SkSpan(&input, 1));
371 }
372
373 //--------------------------------------------------------------------------------------------------
374 class PrecompileMorphologyImageFilter : public PrecompileImageFilter {
375 public:
PrecompileMorphologyImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)376 PrecompileMorphologyImageFilter(SkSpan<sk_sp<PrecompileImageFilter>> inputs)
377 : PrecompileImageFilter(std::move(inputs)) {
378 }
379
380 private:
onCreatePipelines(const KeyContext & keyContext,PipelineDataGatherer * gatherer,const RenderPassDesc & renderPassDesc,const PaintOptionsPriv::ProcessCombination & processCombination) const381 void onCreatePipelines(
382 const KeyContext& keyContext,
383 PipelineDataGatherer* gatherer,
384 const RenderPassDesc& renderPassDesc,
385 const PaintOptionsPriv::ProcessCombination& processCombination) const override {
386
387 // For morphology imagefilters we know we don't have alpha-only textures and don't need
388 // cubic filtering.
389 sk_sp<PrecompileShader> imageShader = PrecompileShadersPriv::Image(
390 PrecompileImageShaderFlags::kExcludeAlpha | PrecompileImageShaderFlags::kExcludeCubic);
391
392 {
393 PaintOptions sparse;
394
395 static const SkBlendMode kBlendModes[] = { SkBlendMode::kSrc };
396 sparse.setShaders({ PrecompileShadersPriv::SparseMorphology(imageShader) });
397 sparse.setBlendModes(kBlendModes);
398
399 sparse.priv().buildCombinations(keyContext,
400 gatherer,
401 DrawTypeFlags::kSimpleShape,
402 /* withPrimitiveBlender= */ false,
403 Coverage::kSingleChannel,
404 renderPassDesc,
405 processCombination);
406 }
407
408 {
409 PaintOptions linear;
410
411 static const SkBlendMode kBlendModes[] = { SkBlendMode::kSrcOver };
412 linear.setShaders({ PrecompileShadersPriv::LinearMorphology(std::move(imageShader)) });
413 linear.setBlendModes(kBlendModes);
414
415 linear.priv().buildCombinations(keyContext,
416 gatherer,
417 DrawTypeFlags::kSimpleShape,
418 /* withPrimitiveBlender= */ false,
419 Coverage::kSingleChannel,
420 renderPassDesc,
421 processCombination);
422 }
423 }
424 };
425
Morphology(sk_sp<PrecompileImageFilter> input)426 sk_sp<PrecompileImageFilter> PrecompileImageFilters::Morphology(
427 sk_sp<PrecompileImageFilter> input) {
428 return sk_make_sp<PrecompileMorphologyImageFilter>(SkSpan(&input, 1));
429 }
430
431 } // namespace skgpu::graphite
432