• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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 "experimental/graphite/src/ContextUtils.h"
9 
10 #include <string>
11 #include "experimental/graphite/src/DrawTypes.h"
12 #include "experimental/graphite/src/Uniform.h"
13 #include "experimental/graphite/src/UniformCache.h"
14 #include "experimental/graphite/src/UniformManager.h"
15 #include "include/core/SkPaint.h"
16 
17 namespace skgpu {
18 
19 namespace {
20 
21 // TODO: For the sprint we only support 4 stops in the gradients
22 static constexpr int kMaxStops = 4;
23 // TODO: For the sprint we unify all the gradient uniforms into a standard set of 6:
24 //   kMaxStops colors
25 //   kMaxStops offsets
26 //   2 points
27 //   2 radii
28 static constexpr int kNumGradientUniforms = 6;
29 static constexpr Uniform kGradientUniforms[kNumGradientUniforms] {
30         {"colors",  SLType::kHalf4 , kMaxStops },
31         {"offsets", SLType::kFloat, kMaxStops },
32         {"point0",   SLType::kFloat2 },
33         {"point1",   SLType::kFloat2 },
34         {"radius0",  SLType::kFloat },
35         {"radius1",  SLType::kFloat },
36 };
37 
38 static constexpr int kNumSolidUniforms = 1;
39 static constexpr Uniform kSolidUniforms[kNumSolidUniforms] {
40         {"color",  SLType::kFloat4 }
41 };
42 
make_gradient_uniform_data_common(void * srcs[kNumGradientUniforms])43 sk_sp<UniformData> make_gradient_uniform_data_common(void* srcs[kNumGradientUniforms]) {
44     UniformManager mgr(Layout::kMetal);
45 
46     // TODO: Given that, for the sprint, we always know the uniforms we could cache 'dataSize'
47     // for each layout and skip the first call.
48     size_t dataSize = mgr.writeUniforms(SkSpan<const Uniform>(kGradientUniforms,
49                                                               kNumGradientUniforms),
50                                         nullptr, nullptr, nullptr);
51 
52     sk_sp<UniformData> result = UniformData::Make(kNumGradientUniforms,
53                                                   kGradientUniforms,
54                                                   dataSize);
55 
56     mgr.writeUniforms(SkSpan<const Uniform>(kGradientUniforms, kNumGradientUniforms),
57                       srcs, result->offsets(), result->data());
58     return result;
59 }
60 
make_linear_gradient_uniform_data(SkPoint startPoint,SkPoint endPoint,SkColor4f colors[kMaxStops],float offsets[kMaxStops])61 sk_sp<UniformData> make_linear_gradient_uniform_data(SkPoint startPoint,
62                                                      SkPoint endPoint,
63                                                      SkColor4f colors[kMaxStops],
64                                                      float offsets[kMaxStops]) {
65     float unusedRadii[2] = { 0.0f, 0.0f };
66     void* srcs[kNumGradientUniforms] = {
67             colors,
68             offsets,
69             &startPoint,
70             &endPoint,
71             &unusedRadii[0],
72             &unusedRadii[1],
73     };
74 
75     return make_gradient_uniform_data_common(srcs);
76 };
77 
make_radial_gradient_uniform_data(SkPoint point,float radius,SkColor4f colors[kMaxStops],float offsets[kMaxStops])78 sk_sp<UniformData> make_radial_gradient_uniform_data(SkPoint point,
79                                                      float radius,
80                                                      SkColor4f colors[kMaxStops],
81                                                      float offsets[kMaxStops]) {
82     SkPoint unusedPoint = {0.0f, 0.0f};
83     float unusedRadius = 0.0f;
84 
85     void* srcs[kNumGradientUniforms] = {
86             colors,
87             offsets,
88             &point,
89             &unusedPoint,
90             &radius,
91             &unusedRadius,
92     };
93 
94     return make_gradient_uniform_data_common(srcs);
95 };
96 
make_sweep_gradient_uniform_data(SkPoint point,SkColor4f colors[kMaxStops],float offsets[kMaxStops])97 sk_sp<UniformData> make_sweep_gradient_uniform_data(SkPoint point,
98                                                     SkColor4f colors[kMaxStops],
99                                                     float offsets[kMaxStops]) {
100     SkPoint unusedPoint = {0.0f, 0.0f};
101     float unusedRadii[2] = {0.0f, 0.0f};
102 
103     void* srcs[kNumGradientUniforms] = {
104             colors,
105             offsets,
106             &point,
107             &unusedPoint,
108             &unusedRadii[0],
109             &unusedRadii[1],
110     };
111 
112     return make_gradient_uniform_data_common(srcs);
113 };
114 
make_conical_gradient_uniform_data(SkPoint point0,SkPoint point1,float radius0,float radius1,SkColor4f colors[kMaxStops],float offsets[kMaxStops])115 sk_sp<UniformData> make_conical_gradient_uniform_data(SkPoint point0,
116                                                       SkPoint point1,
117                                                       float radius0,
118                                                       float radius1,
119                                                       SkColor4f colors[kMaxStops],
120                                                       float offsets[kMaxStops]) {
121 
122     void* srcs[kNumGradientUniforms] = {
123             colors,
124             offsets,
125             &point0,
126             &point1,
127             &radius0,
128             &radius1,
129     };
130 
131     return make_gradient_uniform_data_common(srcs);
132 };
133 
to_color4fs(int numColors,SkColor colors[kMaxStops],SkColor4f color4fs[kMaxStops])134 void to_color4fs(int numColors, SkColor colors[kMaxStops], SkColor4f color4fs[kMaxStops]) {
135     SkASSERT(numColors >= 2 && numColors <= kMaxStops);
136 
137     int i;
138     for (i = 0; i < numColors; ++i) {
139         color4fs[i] = SkColor4f::FromColor(colors[i]);
140     }
141     for ( ; i < kMaxStops; ++i) {
142         color4fs[i] = color4fs[numColors-1];
143     }
144 }
145 
expand_stops(int numStops,float offsets[kMaxStops])146 void expand_stops(int numStops, float offsets[kMaxStops]) {
147     SkASSERT(numStops >= 2 && numStops <= kMaxStops);
148 
149     for (int i = numStops ; i < kMaxStops; ++i) {
150         offsets[i] = offsets[numStops-1];
151     }
152 }
153 
make_solid_uniform_data(SkColor4f color)154 sk_sp<UniformData> make_solid_uniform_data(SkColor4f color) {
155     UniformManager mgr(Layout::kMetal);
156 
157     size_t dataSize = mgr.writeUniforms(SkSpan<const Uniform>(kSolidUniforms, kNumSolidUniforms),
158                                         nullptr, nullptr, nullptr);
159 
160     sk_sp<UniformData> result = UniformData::Make(kNumSolidUniforms, kSolidUniforms, dataSize);
161 
162     void* srcs[kNumSolidUniforms] = { &color };
163 
164     mgr.writeUniforms(SkSpan<const Uniform>(kSolidUniforms, kNumSolidUniforms),
165                       srcs, result->offsets(), result->data());
166     return result;
167 }
168 
169 } // anonymous namespace
170 
Make(int count,const Uniform * uniforms,size_t dataSize)171 sk_sp<UniformData> UniformData::Make(int count,
172                                      const Uniform* uniforms,
173                                      size_t dataSize) {
174     // TODO: the offsets and data should just be allocated right after UniformData in an arena
175     uint32_t* offsets = new uint32_t[count];
176     char* data = new char[dataSize];
177 
178     return sk_sp<UniformData>(new UniformData(count, uniforms, offsets, data, dataSize));
179 }
180 
ExtractCombo(UniformCache * cache,const SkPaint & p)181 std::tuple<Combination, sk_sp<UniformData>> ExtractCombo(UniformCache* cache, const SkPaint& p) {
182     Combination result;
183     sk_sp<UniformData> uniforms;
184 
185     if (auto s = p.getShader()) {
186         SkColor colors[kMaxStops];
187         SkColor4f color4fs[kMaxStops];
188         float offsets[kMaxStops];
189         SkShader::GradientInfo gradInfo;
190 
191         gradInfo.fColorCount = kMaxStops;
192         gradInfo.fColors = colors;
193         gradInfo.fColorOffsets = offsets;
194 
195         SkShader::GradientType type = s->asAGradient(&gradInfo);
196         if (gradInfo.fColorCount > kMaxStops) {
197             type = SkShader::GradientType::kNone_GradientType;
198         }
199 
200         switch (type) {
201             case SkShader::kLinear_GradientType: {
202                 to_color4fs(gradInfo.fColorCount, colors, color4fs);
203                 expand_stops(gradInfo.fColorCount, offsets);
204 
205                 result.fShaderType = ShaderCombo::ShaderType::kLinearGradient;
206                 result.fTileMode = gradInfo.fTileMode;
207 
208                 uniforms = make_linear_gradient_uniform_data(gradInfo.fPoint[0],
209                                                              gradInfo.fPoint[1],
210                                                              color4fs,
211                                                              offsets);
212             } break;
213             case SkShader::kRadial_GradientType: {
214                 to_color4fs(gradInfo.fColorCount, colors, color4fs);
215                 expand_stops(gradInfo.fColorCount, offsets);
216 
217                 result.fShaderType = ShaderCombo::ShaderType::kRadialGradient;
218                 result.fTileMode = gradInfo.fTileMode;
219 
220                 uniforms =  make_radial_gradient_uniform_data(gradInfo.fPoint[0],
221                                                               gradInfo.fRadius[0],
222                                                               color4fs,
223                                                               offsets);
224             } break;
225             case SkShader::kSweep_GradientType:
226                 to_color4fs(gradInfo.fColorCount, colors, color4fs);
227                 expand_stops(gradInfo.fColorCount, offsets);
228 
229                 result.fShaderType = ShaderCombo::ShaderType::kSweepGradient;
230                 result.fTileMode = gradInfo.fTileMode;
231 
232                 uniforms = make_sweep_gradient_uniform_data(gradInfo.fPoint[0],
233                                                             color4fs,
234                                                             offsets);
235                 break;
236             case SkShader::GradientType::kConical_GradientType:
237                 to_color4fs(gradInfo.fColorCount, colors, color4fs);
238                 expand_stops(gradInfo.fColorCount, offsets);
239 
240                 result.fShaderType = ShaderCombo::ShaderType::kConicalGradient;
241                 result.fTileMode = gradInfo.fTileMode;
242 
243                 uniforms = make_conical_gradient_uniform_data(gradInfo.fPoint[0],
244                                                               gradInfo.fPoint[1],
245                                                               gradInfo.fRadius[0],
246                                                               gradInfo.fRadius[1],
247                                                               color4fs,
248                                                               offsets);
249                 break;
250             case SkShader::GradientType::kColor_GradientType:
251             case SkShader::GradientType::kNone_GradientType:
252             default:
253                 result.fShaderType = ShaderCombo::ShaderType::kNone;
254                 result.fTileMode = SkTileMode::kRepeat;
255 
256                 uniforms = make_solid_uniform_data(p.getColor4f());
257                 break;
258         }
259     } else {
260         // Solid colored paint
261         result.fShaderType = ShaderCombo::ShaderType::kNone;
262         result.fTileMode = SkTileMode::kRepeat;
263 
264         uniforms = make_solid_uniform_data(p.getColor4f());
265     }
266 
267     result.fBlendMode = p.getBlendMode_or(SkBlendMode::kSrcOver);
268 
269     sk_sp<UniformData> trueUD = cache->findOrCreate(std::move(uniforms));
270     return { result, std::move(trueUD) };
271 }
272 
273 namespace {
274 
275 // TODO: use a SkSpan for the parameters
emit_MSL_uniform_struct(const Uniform * uniforms,int numUniforms)276 std::string emit_MSL_uniform_struct(const Uniform *uniforms, int numUniforms) {
277     std::string result;
278 
279     result.append("struct FragmentUniforms {\n");
280     for (int i = 0; i < numUniforms; ++i) {
281         // TODO: this is sufficient for the sprint but should be changed to use SkSL's
282         // machinery
283         switch (uniforms[i].type()) {
284             case SLType::kFloat4:
285                 result.append("vector_float4");
286                 break;
287             case SLType::kFloat2:
288                 result.append("vector_float2");
289                 break;
290             case SLType::kFloat:
291                 result.append("float");
292                 break;
293             case SLType::kHalf4:
294                 result.append("vector_half4");
295                 break;
296             default:
297                 SkASSERT(0);
298         }
299 
300         result.append(" ");
301         result.append(uniforms[i].name());
302         if (uniforms[i].count()) {
303             result.append("[");
304             result.append(std::to_string(uniforms[i].count()));
305             result.append("]");
306         }
307         result.append(";\n");
308     }
309     result.append("};\n");
310     return result;
311 }
312 
313 } // anonymous namespace
314 
GetMSLUniformStruct(ShaderCombo::ShaderType shaderType)315 std::string GetMSLUniformStruct(ShaderCombo::ShaderType shaderType) {
316     switch (shaderType) {
317         case ShaderCombo::ShaderType::kLinearGradient:
318         case ShaderCombo::ShaderType::kRadialGradient:
319         case ShaderCombo::ShaderType::kSweepGradient:
320         case ShaderCombo::ShaderType::kConicalGradient:
321             return emit_MSL_uniform_struct(kGradientUniforms, kNumGradientUniforms);
322         case ShaderCombo::ShaderType::kNone:
323         default:
324             return emit_MSL_uniform_struct(kSolidUniforms, kNumSolidUniforms);
325     }
326 }
327 
328 } // namespace skgpu
329