xref: /aosp_15_r20/external/skia/src/gpu/graphite/precompile/PrecompileImageFilter.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 "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