1 /*
2 * Copyright 2022 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/FactoryFunctions.h"
9 #include "src/gpu/graphite/KeyContext.h"
10 #include "src/gpu/graphite/KeyHelpers.h"
11 #include "src/gpu/graphite/PaintParamsKey.h"
12 #include "src/gpu/graphite/Precompile.h"
13 #include "src/gpu/graphite/PrecompileBasePriv.h"
14 #include "src/gpu/graphite/ShaderCodeDictionary.h"
15
16 namespace skgpu::graphite {
17
18 //--------------------------------------------------------------------------------------------------
makeWithLocalMatrix()19 sk_sp<PrecompileShader> PrecompileShader::makeWithLocalMatrix() {
20 if (this->priv().isALocalMatrixShader()) {
21 // SkShader::makeWithLocalMatrix collapses chains of localMatrix shaders so we need to
22 // follow suit here
23 return sk_ref_sp(this);
24 }
25
26 return PrecompileShaders::LocalMatrix(sk_ref_sp(this));
27 }
28
makeWithColorFilter(sk_sp<PrecompileColorFilter> cf)29 sk_sp<PrecompileShader> PrecompileShader::makeWithColorFilter(sk_sp<PrecompileColorFilter> cf) {
30 if (!cf) {
31 return sk_ref_sp(this);
32 }
33
34 return PrecompileShaders::ColorFilter(sk_ref_sp(this), std::move(cf));
35 }
36
37 //--------------------------------------------------------------------------------------------------
numShaderCombinations() const38 int PaintOptions::numShaderCombinations() const {
39 int numShaderCombinations = 0;
40 for (const sk_sp<PrecompileShader>& s : fShaderOptions) {
41 numShaderCombinations += s->numCombinations();
42 }
43
44 // If no shader option is specified we will add a solid color shader option
45 return numShaderCombinations ? numShaderCombinations : 1;
46 }
47
numMaskFilterCombinations() const48 int PaintOptions::numMaskFilterCombinations() const {
49 int numMaskFilterCombinations = 0;
50 for (const sk_sp<PrecompileMaskFilter>& mf : fMaskFilterOptions) {
51 numMaskFilterCombinations += mf->numCombinations();
52 }
53
54 // If no mask filter options are specified we will use the geometry's coverage
55 return numMaskFilterCombinations ? numMaskFilterCombinations : 1;
56 }
57
numColorFilterCombinations() const58 int PaintOptions::numColorFilterCombinations() const {
59 int numColorFilterCombinations = 0;
60 for (const sk_sp<PrecompileColorFilter>& cf : fColorFilterOptions) {
61 numColorFilterCombinations += cf->numCombinations();
62 }
63
64 // If no color filter options are specified we will use the unmodified result color
65 return numColorFilterCombinations ? numColorFilterCombinations : 1;
66 }
67
numBlendModeCombinations() const68 int PaintOptions::numBlendModeCombinations() const {
69 bool bmBased = false;
70 int numBlendCombos = 0;
71 for (auto b: fBlenderOptions) {
72 if (b->asBlendMode().has_value()) {
73 bmBased = true;
74 } else {
75 numBlendCombos += b->numChildCombinations();
76 }
77 }
78
79 if (bmBased || !numBlendCombos) {
80 // If numBlendCombos is zero we will fallback to kSrcOver blending
81 ++numBlendCombos;
82 }
83
84 return numBlendCombos;
85 }
86
numCombinations() const87 int PaintOptions::numCombinations() const {
88 // TODO: we need to handle ImageFilters separately
89 return this->numShaderCombinations() *
90 this->numMaskFilterCombinations() *
91 this->numColorFilterCombinations() *
92 this->numBlendModeCombinations();
93 }
94
createKey(const KeyContext & keyContext,int desiredCombination,PaintParamsKeyBuilder * keyBuilder,bool addPrimitiveBlender) const95 void PaintOptions::createKey(const KeyContext& keyContext,
96 int desiredCombination,
97 PaintParamsKeyBuilder* keyBuilder,
98 bool addPrimitiveBlender) const {
99 SkDEBUGCODE(keyBuilder->checkReset();)
100 SkASSERT(desiredCombination < this->numCombinations());
101
102 const int numBlendModeCombos = this->numBlendModeCombinations();
103 const int numColorFilterCombinations = this->numColorFilterCombinations();
104 const int numMaskFilterCombinations = this->numMaskFilterCombinations();
105
106 const int desiredBlendCombination = desiredCombination % numBlendModeCombos;
107 int remainingCombinations = desiredCombination / numBlendModeCombos;
108
109 const int desiredColorFilterCombination = remainingCombinations % numColorFilterCombinations;
110 remainingCombinations /= numColorFilterCombinations;
111
112 const int desiredMaskFilterCombination = remainingCombinations % numMaskFilterCombinations;
113 remainingCombinations /= numMaskFilterCombinations;
114
115 const int desiredShaderCombination = remainingCombinations;
116 SkASSERT(desiredShaderCombination < this->numShaderCombinations());
117
118 // TODO: eliminate this block for the Paint's color when it isn't needed
119 SolidColorShaderBlock::BeginBlock(keyContext, keyBuilder, /* gatherer= */ nullptr,
120 {1, 0, 0, 1});
121 keyBuilder->endBlock();
122
123 if (!fShaderOptions.empty()) {
124 PrecompileBase::AddToKey(keyContext, keyBuilder, fShaderOptions, desiredShaderCombination);
125 }
126
127 if (addPrimitiveBlender) {
128 PrimitiveBlendModeBlock::BeginBlock(keyContext, keyBuilder, /* gatherer= */ nullptr,
129 SkBlendMode::kSrcOver);
130 keyBuilder->endBlock();
131 }
132
133 PrecompileBase::AddToKey(keyContext, keyBuilder, fMaskFilterOptions,
134 desiredMaskFilterCombination);
135 PrecompileBase::AddToKey(keyContext, keyBuilder, fColorFilterOptions,
136 desiredColorFilterCombination);
137
138 if (fBlenderOptions.empty()) {
139 BlendModeBlock::BeginBlock(keyContext, keyBuilder, /* gatherer= */ nullptr,
140 SkBlendMode::kSrcOver);
141 keyBuilder->endBlock();
142 } else {
143 PrecompileBase::AddToKey(keyContext, keyBuilder, fBlenderOptions, desiredBlendCombination);
144 }
145 }
146
buildCombinations(const KeyContext & keyContext,bool addPrimitiveBlender,const std::function<void (UniquePaintParamsID)> & processCombination) const147 void PaintOptions::buildCombinations(
148 const KeyContext& keyContext,
149 bool addPrimitiveBlender,
150 const std::function<void(UniquePaintParamsID)>& processCombination) const {
151
152 PaintParamsKeyBuilder builder(keyContext.dict());
153
154 int numCombinations = this->numCombinations();
155 for (int i = 0; i < numCombinations; ++i) {
156 this->createKey(keyContext, i, &builder, addPrimitiveBlender);
157
158 // The 'findOrCreate' calls lockAsKey on builder and then destroys the returned
159 // PaintParamsKey. This serves to reset the builder.
160 auto entry = keyContext.dict()->findOrCreate(&builder);
161
162 processCombination(entry->uniqueID());
163 }
164 }
165
166 } // namespace skgpu::graphite
167