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