xref: /aosp_15_r20/external/skia/src/core/SkMesh.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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 "include/core/SkMesh.h"
9 
10 #include "include/core/SkAlphaType.h"
11 #include "include/core/SkColorSpace.h"
12 #include "include/core/SkData.h"
13 #include "include/private/SkSLSampleUsage.h"
14 #include "include/private/base/SkAlign.h"
15 #include "include/private/base/SkAssert.h"
16 #include "include/private/base/SkMath.h"
17 #include "include/private/base/SkTArray.h"
18 #include "include/private/base/SkTo.h"
19 #include "src/base/SkSafeMath.h"
20 #include "src/core/SkChecksum.h"
21 #include "src/core/SkMeshPriv.h"
22 #include "src/core/SkRuntimeEffectPriv.h"
23 #include "src/sksl/SkSLAnalysis.h"
24 #include "src/sksl/SkSLBuiltinTypes.h"
25 #include "src/sksl/SkSLCompiler.h"
26 #include "src/sksl/SkSLContext.h"
27 #include "src/sksl/SkSLProgramKind.h"
28 #include "src/sksl/SkSLProgramSettings.h"
29 #include "src/sksl/analysis/SkSLProgramVisitor.h"
30 #include "src/sksl/ir/SkSLExpression.h"
31 #include "src/sksl/ir/SkSLFieldAccess.h"
32 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
33 #include "src/sksl/ir/SkSLFunctionDefinition.h"
34 #include "src/sksl/ir/SkSLModifierFlags.h"
35 #include "src/sksl/ir/SkSLProgram.h"
36 #include "src/sksl/ir/SkSLProgramElement.h"
37 #include "src/sksl/ir/SkSLReturnStatement.h"
38 #include "src/sksl/ir/SkSLStatement.h"
39 #include "src/sksl/ir/SkSLStructDefinition.h"
40 #include "src/sksl/ir/SkSLType.h"
41 #include "src/sksl/ir/SkSLVarDeclarations.h"
42 #include "src/sksl/ir/SkSLVariable.h"
43 #include "src/sksl/ir/SkSLVariableReference.h"
44 
45 #include <algorithm>
46 #include <locale>
47 #include <optional>
48 #include <string>
49 #include <tuple>
50 #include <utility>
51 
52 using namespace skia_private;
53 
54 using Attribute = SkMeshSpecification::Attribute;
55 using Varying   = SkMeshSpecification::Varying;
56 
57 using IndexBuffer  = SkMesh::IndexBuffer;
58 using VertexBuffer = SkMesh::VertexBuffer;
59 
60 #define RETURN_FAILURE(...) return Result{nullptr, SkStringPrintf(__VA_ARGS__)}
61 
62 #define RETURN_ERROR(...) return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
63 
64 #define RETURN_SUCCESS return std::make_tuple(true, SkString{})
65 
66 using Uniform = SkMeshSpecification::Uniform;
67 using Child = SkMeshSpecification::Child;
68 
find_uniform(std::vector<Uniform> & uniforms,std::string_view name)69 static std::vector<Uniform>::iterator find_uniform(std::vector<Uniform>& uniforms,
70                                                    std::string_view name) {
71     return std::find_if(uniforms.begin(), uniforms.end(),
72                         [name](const SkMeshSpecification::Uniform& u) { return u.name == name; });
73 }
74 
75 static std::tuple<bool, SkString>
gather_uniforms_and_check_for_main(const SkSL::Program & program,std::vector<Uniform> * uniforms,std::vector<Child> * children,SkMeshSpecification::Uniform::Flags stage,size_t * offset)76 gather_uniforms_and_check_for_main(const SkSL::Program& program,
77                                    std::vector<Uniform>* uniforms,
78                                    std::vector<Child>* children,
79                                    SkMeshSpecification::Uniform::Flags stage,
80                                    size_t* offset) {
81     bool foundMain = false;
82     for (const SkSL::ProgramElement* elem : program.elements()) {
83         if (elem->is<SkSL::FunctionDefinition>()) {
84             const SkSL::FunctionDefinition& defn = elem->as<SkSL::FunctionDefinition>();
85             const SkSL::FunctionDeclaration& decl = defn.declaration();
86             if (decl.isMain()) {
87                 foundMain = true;
88             }
89         } else if (elem->is<SkSL::GlobalVarDeclaration>()) {
90             const SkSL::GlobalVarDeclaration& global = elem->as<SkSL::GlobalVarDeclaration>();
91             const SkSL::VarDeclaration& varDecl = global.declaration()->as<SkSL::VarDeclaration>();
92             const SkSL::Variable& var = *varDecl.var();
93             if (var.modifierFlags().isUniform()) {
94                 if (var.type().isEffectChild()) {
95                     // This is a child effect; add it to our list of children.
96                     children->push_back(SkRuntimeEffectPriv::VarAsChild(var, children->size()));
97                 } else {
98                     // This is a uniform variable; make sure it exists in our list of uniforms, and
99                     // ensure that the type and layout matches between VS and FS.
100                     auto iter = find_uniform(*uniforms, var.name());
101                     const auto& context = *program.fContext;
102                     if (iter == uniforms->end()) {
103                         uniforms->push_back(SkRuntimeEffectPriv::VarAsUniform(var, context,
104                                                                               offset));
105                         uniforms->back().flags |= stage;
106                     } else {
107                         // Check that the two declarations are equivalent
108                         size_t ignoredOffset = 0;
109                         auto uniform = SkRuntimeEffectPriv::VarAsUniform(var, context,
110                                                                          &ignoredOffset);
111                         if (uniform.isArray() != iter->isArray() ||
112                             uniform.type      != iter->type      ||
113                             uniform.count     != iter->count) {
114                             return {false,
115                                     SkStringPrintf("Uniform %.*s declared with different types"
116                                                    " in vertex and fragment shaders.",
117                                                    (int)var.name().size(), var.name().data())};
118                         }
119                         if (uniform.isColor() != iter->isColor()) {
120                             return {false,
121                                     SkStringPrintf("Uniform %.*s declared with different color"
122                                                    " layout in vertex and fragment shaders.",
123                                                    (int)var.name().size(), var.name().data())};
124                         }
125                         (*iter).flags |= stage;
126                     }
127                 }
128             }
129         }
130     }
131     if (!foundMain) {
132         return {false, SkString("No main function found.")};
133     }
134     return {true, {}};
135 }
136 
137 using ColorType = SkMeshSpecificationPriv::ColorType;
138 
get_fs_color_type(const SkSL::Program & fsProgram)139 ColorType get_fs_color_type(const SkSL::Program& fsProgram) {
140     for (const SkSL::ProgramElement* elem : fsProgram.elements()) {
141         if (elem->is<SkSL::FunctionDefinition>()) {
142             const SkSL::FunctionDefinition& defn = elem->as<SkSL::FunctionDefinition>();
143             const SkSL::FunctionDeclaration& decl = defn.declaration();
144             if (decl.isMain()) {
145                 SkASSERT(decl.parameters().size() == 1 || decl.parameters().size() == 2);
146                 if (decl.parameters().size() == 1) {
147                     return ColorType::kNone;
148                 }
149                 const SkSL::Type& paramType = decl.parameters()[1]->type();
150                 SkASSERT(paramType.matches(*fsProgram.fContext->fTypes.fHalf4) ||
151                          paramType.matches(*fsProgram.fContext->fTypes.fFloat4));
152                 return paramType.matches(*fsProgram.fContext->fTypes.fHalf4) ? ColorType::kHalf4
153                                                                              : ColorType::kFloat4;
154             }
155         }
156     }
157     SkUNREACHABLE;
158 }
159 
160 // This is a non-exhaustive check for the validity of a variable name. The SkSL compiler will
161 // actually process the name. We're just guarding against having multiple tokens embedded in the
162 // name before we put it into a struct definition.
check_name(const SkString & name)163 static bool check_name(const SkString& name) {
164     if (name.isEmpty()) {
165         return false;
166     }
167     for (size_t i = 0; i < name.size(); ++i) {
168         if (name[i] != '_' && !std::isalnum(name[i], std::locale::classic())) {
169             return false;
170         }
171     }
172     return true;
173 }
174 
attribute_type_size(Attribute::Type type)175 static size_t attribute_type_size(Attribute::Type type) {
176     switch (type) {
177         case Attribute::Type::kFloat:         return 4;
178         case Attribute::Type::kFloat2:        return 2*4;
179         case Attribute::Type::kFloat3:        return 3*4;
180         case Attribute::Type::kFloat4:        return 4*4;
181         case Attribute::Type::kUByte4_unorm:  return 4;
182     }
183     SkUNREACHABLE;
184 }
185 
attribute_type_string(Attribute::Type type)186 static const char* attribute_type_string(Attribute::Type type) {
187     switch (type) {
188         case Attribute::Type::kFloat:         return "float";
189         case Attribute::Type::kFloat2:        return "float2";
190         case Attribute::Type::kFloat3:        return "float3";
191         case Attribute::Type::kFloat4:        return "float4";
192         case Attribute::Type::kUByte4_unorm:  return "half4";
193     }
194     SkUNREACHABLE;
195 }
196 
varying_type_string(Varying::Type type)197 static const char* varying_type_string(Varying::Type type) {
198     switch (type) {
199         case Varying::Type::kFloat:  return "float";
200         case Varying::Type::kFloat2: return "float2";
201         case Varying::Type::kFloat3: return "float3";
202         case Varying::Type::kFloat4: return "float4";
203         case Varying::Type::kHalf:   return "half";
204         case Varying::Type::kHalf2:  return "half2";
205         case Varying::Type::kHalf3:  return "half3";
206         case Varying::Type::kHalf4:  return "half4";
207     }
208     SkUNREACHABLE;
209 }
210 
211 std::tuple<bool, SkString>
check_vertex_offsets_and_stride(SkSpan<const Attribute> attributes,size_t stride)212 check_vertex_offsets_and_stride(SkSpan<const Attribute> attributes,
213                                 size_t                  stride) {
214     // Vulkan 1.0 has a minimum maximum attribute count of 2048.
215     static_assert(SkMeshSpecification::kMaxStride       <= 2048);
216     // ES 2 has a max of 8.
217     static_assert(SkMeshSpecification::kMaxAttributes   <= 8);
218     // Four bytes alignment is required by Metal.
219     static_assert(SkMeshSpecification::kStrideAlignment >= 4);
220     static_assert(SkMeshSpecification::kOffsetAlignment >= 4);
221     // ES2 has a minimum maximum of 8. We may need one for a broken gl_FragCoord workaround and
222     // one for local coords.
223     static_assert(SkMeshSpecification::kMaxVaryings     <= 6);
224 
225     if (attributes.empty()) {
226         RETURN_ERROR("At least 1 attribute is required.");
227     }
228     if (attributes.size() > SkMeshSpecification::kMaxAttributes) {
229         RETURN_ERROR("A maximum of %zu attributes is allowed.",
230                      SkMeshSpecification::kMaxAttributes);
231     }
232     static_assert(SkIsPow2(SkMeshSpecification::kStrideAlignment));
233     if (stride == 0 || stride & (SkMeshSpecification::kStrideAlignment - 1)) {
234         RETURN_ERROR("Vertex stride must be a non-zero multiple of %zu.",
235                      SkMeshSpecification::kStrideAlignment);
236     }
237     if (stride > SkMeshSpecification::kMaxStride) {
238         RETURN_ERROR("Stride cannot exceed %zu.", SkMeshSpecification::kMaxStride);
239     }
240     for (const auto& a : attributes) {
241         if (a.offset & (SkMeshSpecification::kOffsetAlignment - 1)) {
242             RETURN_ERROR("Attribute offset must be a multiple of %zu.",
243                          SkMeshSpecification::kOffsetAlignment);
244         }
245         // This equivalent to vertexAttributeAccessBeyondStride==VK_FALSE in
246         // VK_KHR_portability_subset. First check is to avoid overflow in second check.
247         if (a.offset >= stride || a.offset + attribute_type_size(a.type) > stride) {
248             RETURN_ERROR("Attribute offset plus size cannot exceed stride.");
249         }
250     }
251     RETURN_SUCCESS;
252 }
253 
check_for_passthrough_local_coords_and_dead_varyings(const SkSL::Program & fsProgram,uint32_t * deadVaryingMask)254 int check_for_passthrough_local_coords_and_dead_varyings(const SkSL::Program& fsProgram,
255                                                          uint32_t* deadVaryingMask) {
256     SkASSERT(deadVaryingMask);
257 
258     using namespace SkSL;
259     static constexpr int kFailed = -2;
260 
261     class Visitor final : public SkSL::ProgramVisitor {
262     public:
263         Visitor(const Context& context) : fContext(context) {}
264 
265         void visit(const Program& program) { ProgramVisitor::visit(program); }
266 
267         int passthroughFieldIndex() const { return fPassthroughFieldIndex; }
268 
269         uint32_t fieldUseMask() const { return fFieldUseMask; }
270 
271     protected:
272         bool visitProgramElement(const ProgramElement& p) override {
273             if (p.is<StructDefinition>()) {
274                 const auto& def = p.as<StructDefinition>();
275                 if (def.type().name() == "Varyings") {
276                     fVaryingsType = &def.type();
277                 }
278                 // No reason to keep looking at this type definition.
279                 return false;
280             }
281             if (p.is<FunctionDefinition>() && p.as<FunctionDefinition>().declaration().isMain()) {
282                 SkASSERT(!fVaryings);
283                 fVaryings = p.as<FunctionDefinition>().declaration().parameters()[0];
284 
285                 SkASSERT(fVaryingsType && fVaryingsType->matches(fVaryings->type()));
286 
287                 fInMain = true;
288                 bool result = ProgramVisitor::visitProgramElement(p);
289                 fInMain = false;
290                 return result;
291             }
292             return ProgramVisitor::visitProgramElement(p);
293         }
294 
295         bool visitStatement(const Statement& s) override {
296             if (!fInMain) {
297                 return ProgramVisitor::visitStatement(s);
298             }
299             // We should only get here if are in main and therefore found the varyings parameter.
300             SkASSERT(fVaryings);
301             SkASSERT(fVaryingsType);
302 
303             if (fPassthroughFieldIndex == kFailed) {
304                 // We've already determined there are return statements that aren't passthrough
305                 // or return different fields.
306                 return ProgramVisitor::visitStatement(s);
307             }
308             if (!s.is<ReturnStatement>()) {
309                 return ProgramVisitor::visitStatement(s);
310             }
311 
312             // We just detect simple cases like "return varyings.foo;"
313             const auto& rs = s.as<ReturnStatement>();
314             SkASSERT(rs.expression());
315             if (!rs.expression()->is<FieldAccess>()) {
316                 this->passthroughFailed();
317                 return ProgramVisitor::visitStatement(s);
318             }
319             const auto& fa = rs.expression()->as<FieldAccess>();
320             if (!fa.base()->is<VariableReference>()) {
321                 this->passthroughFailed();
322                 return ProgramVisitor::visitStatement(s);
323             }
324             const auto& baseRef = fa.base()->as<VariableReference>();
325             if (baseRef.variable() != fVaryings) {
326                 this->passthroughFailed();
327                 return ProgramVisitor::visitStatement(s);
328             }
329             if (fPassthroughFieldIndex >= 0) {
330                 // We already found an OK return statement. Check if this one returns the same
331                 // field.
332                 if (fa.fieldIndex() != fPassthroughFieldIndex) {
333                     this->passthroughFailed();
334                     return ProgramVisitor::visitStatement(s);
335                 }
336                 // We don't call our base class here because we don't want to hit visitExpression
337                 // and mark the returned field as used.
338                 return false;
339             }
340             const Field& field = fVaryings->type().fields()[fa.fieldIndex()];
341             if (!field.fType->matches(*fContext.fTypes.fFloat2)) {
342                 this->passthroughFailed();
343                 return ProgramVisitor::visitStatement(s);
344             }
345             fPassthroughFieldIndex = fa.fieldIndex();
346             // We don't call our base class here because we don't want to hit visitExpression and
347             // mark the returned field as used.
348             return false;
349         }
350 
351         bool visitExpression(const Expression& e) override {
352             // Anything before the Varyings struct is defined doesn't matter.
353             if (!fVaryingsType) {
354                 return false;
355             }
356             if (!e.is<FieldAccess>()) {
357                 return ProgramVisitor::visitExpression(e);
358             }
359             const auto& fa = e.as<FieldAccess>();
360             if (!fa.base()->type().matches(*fVaryingsType)) {
361                 return ProgramVisitor::visitExpression(e);
362             }
363             fFieldUseMask |= 1 << fa.fieldIndex();
364             return false;
365         }
366 
367     private:
368         void passthroughFailed() {
369             if (fPassthroughFieldIndex >= 0) {
370                 fFieldUseMask |= 1 << fPassthroughFieldIndex;
371             }
372             fPassthroughFieldIndex = kFailed;
373         }
374 
375         const Context&  fContext;
376         const Type*     fVaryingsType          = nullptr;
377         const Variable* fVaryings              = nullptr;
378         int             fPassthroughFieldIndex = -1;
379         bool            fInMain                = false;
380         uint32_t        fFieldUseMask          = 0;
381     };
382 
383     Visitor v(*fsProgram.fContext);
384     v.visit(fsProgram);
385     *deadVaryingMask = ~v.fieldUseMask();
386     return v.passthroughFieldIndex();
387 }
388 
Make(SkSpan<const Attribute> attributes,size_t vertexStride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs)389 SkMeshSpecification::Result SkMeshSpecification::Make(SkSpan<const Attribute> attributes,
390                                                       size_t vertexStride,
391                                                       SkSpan<const Varying> varyings,
392                                                       const SkString& vs,
393                                                       const SkString& fs) {
394     return Make(attributes,
395                 vertexStride,
396                 varyings,
397                 vs,
398                 fs,
399                 SkColorSpace::MakeSRGB(),
400                 kPremul_SkAlphaType);
401 }
402 
Make(SkSpan<const Attribute> attributes,size_t vertexStride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs,sk_sp<SkColorSpace> cs)403 SkMeshSpecification::Result SkMeshSpecification::Make(SkSpan<const Attribute> attributes,
404                                                       size_t vertexStride,
405                                                       SkSpan<const Varying> varyings,
406                                                       const SkString& vs,
407                                                       const SkString& fs,
408                                                       sk_sp<SkColorSpace> cs) {
409     return Make(attributes, vertexStride, varyings, vs, fs, std::move(cs), kPremul_SkAlphaType);
410 }
411 
Make(SkSpan<const Attribute> attributes,size_t vertexStride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs,sk_sp<SkColorSpace> cs,SkAlphaType at)412 SkMeshSpecification::Result SkMeshSpecification::Make(SkSpan<const Attribute> attributes,
413                                                       size_t vertexStride,
414                                                       SkSpan<const Varying> varyings,
415                                                       const SkString& vs,
416                                                       const SkString& fs,
417                                                       sk_sp<SkColorSpace> cs,
418                                                       SkAlphaType at) {
419     SkString attributesStruct("struct Attributes {\n");
420     for (const auto& a : attributes) {
421         attributesStruct.appendf("  %s %s;\n", attribute_type_string(a.type), a.name.c_str());
422     }
423     attributesStruct.append("};\n");
424 
425     bool userProvidedPositionVarying = false;
426     for (const auto& v : varyings) {
427         if (v.name.equals("position")) {
428             if (v.type != Varying::Type::kFloat2) {
429                 return {nullptr, SkString("Varying \"position\" must have type float2.")};
430             }
431             userProvidedPositionVarying = true;
432         }
433     }
434 
435     STArray<kMaxVaryings, Varying> tempVaryings;
436     if (!userProvidedPositionVarying) {
437         // Even though we check the # of varyings in MakeFromSourceWithStructs we check here, too,
438         // to avoid overflow with + 1.
439         if (varyings.size() > kMaxVaryings - 1) {
440             RETURN_FAILURE("A maximum of %zu varyings is allowed.", kMaxVaryings);
441         }
442         for (const auto& v : varyings) {
443             tempVaryings.push_back(v);
444         }
445         tempVaryings.push_back(Varying{Varying::Type::kFloat2, SkString("position")});
446         varyings = tempVaryings;
447     }
448 
449     SkString varyingStruct("struct Varyings {\n");
450     for (const auto& v : varyings) {
451         varyingStruct.appendf("  %s %s;\n", varying_type_string(v.type), v.name.c_str());
452     }
453     varyingStruct.append("};\n");
454 
455     SkString fullVS;
456     fullVS.append(varyingStruct.c_str());
457     fullVS.append(attributesStruct.c_str());
458     fullVS.append(vs.c_str());
459 
460     SkString fullFS;
461     fullFS.append(varyingStruct.c_str());
462     fullFS.append(fs.c_str());
463 
464     return MakeFromSourceWithStructs(attributes,
465                                      vertexStride,
466                                      varyings,
467                                      fullVS,
468                                      fullFS,
469                                      std::move(cs),
470                                      at);
471 }
472 
MakeFromSourceWithStructs(SkSpan<const Attribute> attributes,size_t stride,SkSpan<const Varying> varyings,const SkString & vs,const SkString & fs,sk_sp<SkColorSpace> cs,SkAlphaType at)473 SkMeshSpecification::Result SkMeshSpecification::MakeFromSourceWithStructs(
474         SkSpan<const Attribute> attributes,
475         size_t                  stride,
476         SkSpan<const Varying>   varyings,
477         const SkString&         vs,
478         const SkString&         fs,
479         sk_sp<SkColorSpace>     cs,
480         SkAlphaType             at) {
481     if (auto [ok, error] = check_vertex_offsets_and_stride(attributes, stride); !ok) {
482         return {nullptr, error};
483     }
484 
485     for (const auto& a : attributes) {
486         if (!check_name(a.name)) {
487             RETURN_FAILURE("\"%s\" is not a valid attribute name.", a.name.c_str());
488         }
489     }
490 
491     if (varyings.size() > kMaxVaryings) {
492         RETURN_FAILURE("A maximum of %zu varyings is allowed.", kMaxVaryings);
493     }
494 
495     for (const auto& v : varyings) {
496         if (!check_name(v.name)) {
497             return {nullptr, SkStringPrintf("\"%s\" is not a valid varying name.", v.name.c_str())};
498         }
499     }
500 
501     std::vector<Uniform> uniforms;
502     std::vector<Child> children;
503     size_t offset = 0;
504 
505     SkSL::Compiler compiler;
506 
507     // Disable memory pooling; this might slow down compilation slightly, but it will ensure that a
508     // long-lived mesh specification doesn't waste memory.
509     SkSL::ProgramSettings settings;
510     settings.fUseMemoryPool = false;
511 
512     // TODO(skia:11209): Add SkCapabilities to the API, check against required version.
513     std::unique_ptr<SkSL::Program> vsProgram = compiler.convertProgram(
514             SkSL::ProgramKind::kMeshVertex,
515             std::string(vs.c_str()),
516             settings);
517     if (!vsProgram) {
518         RETURN_FAILURE("VS: %s", compiler.errorText().c_str());
519     }
520 
521     if (auto [result, error] = gather_uniforms_and_check_for_main(
522                 *vsProgram,
523                 &uniforms,
524                 &children,
525                 SkMeshSpecification::Uniform::Flags::kVertex_Flag,
526                 &offset);
527         !result) {
528         return {nullptr, std::move(error)};
529     }
530 
531     if (SkSL::Analysis::CallsColorTransformIntrinsics(*vsProgram)) {
532         RETURN_FAILURE("Color transform intrinsics are not permitted in custom mesh shaders");
533     }
534 
535     std::unique_ptr<SkSL::Program> fsProgram = compiler.convertProgram(
536             SkSL::ProgramKind::kMeshFragment,
537             std::string(fs.c_str()),
538             settings);
539 
540     if (!fsProgram) {
541         RETURN_FAILURE("FS: %s", compiler.errorText().c_str());
542     }
543 
544     if (auto [result, error] = gather_uniforms_and_check_for_main(
545                 *fsProgram,
546                 &uniforms,
547                 &children,
548                 SkMeshSpecification::Uniform::Flags::kFragment_Flag,
549                 &offset);
550         !result) {
551         return {nullptr, std::move(error)};
552     }
553 
554     if (SkSL::Analysis::CallsColorTransformIntrinsics(*fsProgram)) {
555         RETURN_FAILURE("Color transform intrinsics are not permitted in custom mesh shaders");
556     }
557 
558     ColorType ct = get_fs_color_type(*fsProgram);
559 
560     if (ct == ColorType::kNone) {
561         cs = nullptr;
562         at = kPremul_SkAlphaType;
563     } else {
564         if (!cs) {
565             return {nullptr, SkString{"Must provide a color space if FS returns a color."}};
566         }
567         if (at == kUnknown_SkAlphaType) {
568             return {nullptr, SkString{"Must provide a valid alpha type if FS returns a color."}};
569         }
570     }
571 
572     uint32_t deadVaryingMask;
573     int passthroughLocalCoordsVaryingIndex =
574             check_for_passthrough_local_coords_and_dead_varyings(*fsProgram, &deadVaryingMask);
575 
576     if (passthroughLocalCoordsVaryingIndex >= 0) {
577         SkASSERT(varyings[passthroughLocalCoordsVaryingIndex].type == Varying::Type::kFloat2);
578     }
579 
580     return {sk_sp<SkMeshSpecification>(new SkMeshSpecification(attributes,
581                                                                stride,
582                                                                varyings,
583                                                                passthroughLocalCoordsVaryingIndex,
584                                                                deadVaryingMask,
585                                                                std::move(uniforms),
586                                                                std::move(children),
587                                                                std::move(vsProgram),
588                                                                std::move(fsProgram),
589                                                                ct,
590                                                                std::move(cs),
591                                                                at)),
592             /*error=*/{}};
593 }
594 
595 SkMeshSpecification::~SkMeshSpecification() = default;
596 
SkMeshSpecification(SkSpan<const Attribute> attributes,size_t stride,SkSpan<const Varying> varyings,int passthroughLocalCoordsVaryingIndex,uint32_t deadVaryingMask,std::vector<Uniform> uniforms,std::vector<Child> children,std::unique_ptr<const SkSL::Program> vs,std::unique_ptr<const SkSL::Program> fs,ColorType ct,sk_sp<SkColorSpace> cs,SkAlphaType at)597 SkMeshSpecification::SkMeshSpecification(
598         SkSpan<const Attribute>              attributes,
599         size_t                               stride,
600         SkSpan<const Varying>                varyings,
601         int                                  passthroughLocalCoordsVaryingIndex,
602         uint32_t                             deadVaryingMask,
603         std::vector<Uniform>                 uniforms,
604         std::vector<Child>                   children,
605         std::unique_ptr<const SkSL::Program> vs,
606         std::unique_ptr<const SkSL::Program> fs,
607         ColorType                            ct,
608         sk_sp<SkColorSpace>                  cs,
609         SkAlphaType                          at)
610         : fAttributes(attributes.begin(), attributes.end())
611         , fVaryings(varyings.begin(), varyings.end())
612         , fUniforms(std::move(uniforms))
613         , fChildren(std::move(children))
614         , fVS(std::move(vs))
615         , fFS(std::move(fs))
616         , fStride(stride)
617         , fPassthroughLocalCoordsVaryingIndex(passthroughLocalCoordsVaryingIndex)
618         , fDeadVaryingMask(deadVaryingMask)
619         , fColorType(ct)
620         , fColorSpace(std::move(cs))
621         , fAlphaType(at) {
622     fHash = SkChecksum::Hash32(fVS->fSource->c_str(), fVS->fSource->size(), 0);
623     fHash = SkChecksum::Hash32(fFS->fSource->c_str(), fFS->fSource->size(), fHash);
624 
625     // The attributes and varyings SkSL struct declarations are included in the program source.
626     // However, the attribute offsets and types need to be included, the latter because the SkSL
627     // struct definition has the GPU type but not the CPU data format.
628     for (const auto& a : fAttributes) {
629         fHash = SkChecksum::Hash32(&a.offset, sizeof(a.offset), fHash);
630         fHash = SkChecksum::Hash32(&a.type,   sizeof(a.type),   fHash);
631     }
632 
633     fHash = SkChecksum::Hash32(&stride, sizeof(stride), fHash);
634 
635     uint64_t csHash = fColorSpace ? fColorSpace->hash() : 0;
636     fHash = SkChecksum::Hash32(&csHash, sizeof(csHash), fHash);
637 
638     auto atInt = static_cast<uint32_t>(fAlphaType);
639     fHash = SkChecksum::Hash32(&atInt, sizeof(atInt), fHash);
640 }
641 
uniformSize() const642 size_t SkMeshSpecification::uniformSize() const {
643     return fUniforms.empty() ? 0
644                              : SkAlign4(fUniforms.back().offset + fUniforms.back().sizeInBytes());
645 }
646 
findUniform(std::string_view name) const647 const Uniform* SkMeshSpecification::findUniform(std::string_view name) const {
648     for (const Uniform& uniform : fUniforms) {
649         if (uniform.name == name) {
650             return &uniform;
651         }
652     }
653     return nullptr;
654 }
655 
findChild(std::string_view name) const656 const Child* SkMeshSpecification::findChild(std::string_view name) const {
657     for (const Child& child : fChildren) {
658         if (child.name == name) {
659             return &child;
660         }
661     }
662     return nullptr;
663 }
664 
findAttribute(std::string_view name) const665 const Attribute* SkMeshSpecification::findAttribute(std::string_view name) const {
666     for (const Attribute& attr : fAttributes) {
667         if (name == attr.name.c_str()) {
668             return &attr;
669         }
670     }
671     return nullptr;
672 }
673 
findVarying(std::string_view name) const674 const Varying* SkMeshSpecification::findVarying(std::string_view name) const {
675     for (const Varying& varying : fVaryings) {
676         if (name == varying.name.c_str()) {
677             return &varying;
678         }
679     }
680     return nullptr;
681 }
682 
683 //////////////////////////////////////////////////////////////////////////////
684 
685 SkMesh::SkMesh()  = default;
686 SkMesh::~SkMesh() = default;
687 
688 SkMesh::SkMesh(const SkMesh&) = default;
689 SkMesh::SkMesh(SkMesh&&)      = default;
690 
691 SkMesh& SkMesh::operator=(const SkMesh&) = default;
692 SkMesh& SkMesh::operator=(SkMesh&&)      = default;
693 
Make(sk_sp<SkMeshSpecification> spec,Mode mode,sk_sp<VertexBuffer> vb,size_t vertexCount,size_t vertexOffset,sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children,const SkRect & bounds)694 SkMesh::Result SkMesh::Make(sk_sp<SkMeshSpecification> spec,
695                             Mode mode,
696                             sk_sp<VertexBuffer> vb,
697                             size_t vertexCount,
698                             size_t vertexOffset,
699                             sk_sp<const SkData> uniforms,
700                             SkSpan<ChildPtr> children,
701                             const SkRect& bounds) {
702     SkMesh mesh;
703     mesh.fSpec     = std::move(spec);
704     mesh.fMode     = mode;
705     mesh.fVB       = std::move(vb);
706     mesh.fUniforms = std::move(uniforms);
707     mesh.fChildren.push_back_n(children.size(), children.data());
708     mesh.fVCount   = vertexCount;
709     mesh.fVOffset  = vertexOffset;
710     mesh.fBounds   = bounds;
711     auto [valid, msg] = mesh.validate();
712     if (!valid) {
713         mesh = {};
714     }
715     return {std::move(mesh), std::move(msg)};
716 }
717 
MakeIndexed(sk_sp<SkMeshSpecification> spec,Mode mode,sk_sp<VertexBuffer> vb,size_t vertexCount,size_t vertexOffset,sk_sp<IndexBuffer> ib,size_t indexCount,size_t indexOffset,sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children,const SkRect & bounds)718 SkMesh::Result SkMesh::MakeIndexed(sk_sp<SkMeshSpecification> spec,
719                                    Mode mode,
720                                    sk_sp<VertexBuffer> vb,
721                                    size_t vertexCount,
722                                    size_t vertexOffset,
723                                    sk_sp<IndexBuffer> ib,
724                                    size_t indexCount,
725                                    size_t indexOffset,
726                                    sk_sp<const SkData> uniforms,
727                                    SkSpan<ChildPtr> children,
728                                    const SkRect& bounds) {
729     if (!ib) {
730         // We check this before calling validate to disambiguate from a non-indexed mesh where
731         // IB is expected to be null.
732         return {{}, SkString{"An index buffer is required."}};
733     }
734     SkMesh mesh;
735     mesh.fSpec     = std::move(spec);
736     mesh.fMode     = mode;
737     mesh.fVB       = std::move(vb);
738     mesh.fVCount   = vertexCount;
739     mesh.fVOffset  = vertexOffset;
740     mesh.fIB       = std::move(ib);
741     mesh.fUniforms = std::move(uniforms);
742     mesh.fChildren.push_back_n(children.size(), children.data());
743     mesh.fICount   = indexCount;
744     mesh.fIOffset  = indexOffset;
745     mesh.fBounds   = bounds;
746     auto [valid, msg] = mesh.validate();
747     if (!valid) {
748         mesh = {};
749     }
750     return {std::move(mesh), std::move(msg)};
751 }
752 
isValid() const753 bool SkMesh::isValid() const {
754     bool valid = SkToBool(fSpec);
755     SkASSERT(valid == std::get<0>(this->validate()));
756     return valid;
757 }
758 
min_vcount_for_mode(SkMesh::Mode mode)759 static size_t min_vcount_for_mode(SkMesh::Mode mode) {
760     switch (mode) {
761         case SkMesh::Mode::kTriangles:     return 3;
762         case SkMesh::Mode::kTriangleStrip: return 3;
763     }
764     SkUNREACHABLE;
765 }
766 
validate() const767 std::tuple<bool, SkString> SkMesh::validate() const {
768 #define FAIL_MESH_VALIDATE(...)  return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
769     if (!fSpec) {
770         FAIL_MESH_VALIDATE("SkMeshSpecification is required.");
771     }
772 
773     if (!fVB) {
774         FAIL_MESH_VALIDATE("A vertex buffer is required.");
775     }
776 
777     if (fSpec->children().size() != SkToSizeT(fChildren.size())) {
778         FAIL_MESH_VALIDATE("The mesh specification declares %zu child effects, "
779                            "but the mesh supplies %d.",
780                            fSpec->children().size(),
781                            fChildren.size());
782     }
783 
784     for (int index = 0; index < fChildren.size(); ++index) {
785         const SkRuntimeEffect::Child& meshSpecChild = fSpec->children()[index];
786         if (fChildren[index].type().has_value()) {
787             if (meshSpecChild.type != fChildren[index].type()) {
788                 FAIL_MESH_VALIDATE("Child effect '%.*s' was specified as a %s, but passed as a %s.",
789                                    (int)meshSpecChild.name.size(), meshSpecChild.name.data(),
790                                    SkRuntimeEffectPriv::ChildTypeToStr(meshSpecChild.type),
791                                    SkRuntimeEffectPriv::ChildTypeToStr(*fChildren[index].type()));
792             }
793         }
794     }
795 
796     auto vb = static_cast<SkMeshPriv::VB*>(fVB.get());
797     auto ib = static_cast<SkMeshPriv::IB*>(fIB.get());
798 
799     SkSafeMath sm;
800     size_t vsize = sm.mul(fSpec->stride(), fVCount);
801     if (sm.add(vsize, fVOffset) > vb->size()) {
802         FAIL_MESH_VALIDATE("The vertex buffer offset and vertex count reads beyond the end of the"
803                            " vertex buffer.");
804     }
805 
806     if (fVOffset%fSpec->stride() != 0) {
807         FAIL_MESH_VALIDATE("The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
808                            fVOffset,
809                            fSpec->stride());
810     }
811 
812     if (size_t uniformSize = fSpec->uniformSize()) {
813         if (!fUniforms || fUniforms->size() < uniformSize) {
814             FAIL_MESH_VALIDATE("The uniform data is %zu bytes but must be at least %zu.",
815                                fUniforms->size(),
816                                uniformSize);
817         }
818     }
819 
820     auto modeToStr = [](Mode m) {
821         switch (m) {
822             case Mode::kTriangles:     return "triangles";
823             case Mode::kTriangleStrip: return "triangle-strip";
824         }
825         SkUNREACHABLE;
826     };
827     if (ib) {
828         if (fICount < min_vcount_for_mode(fMode)) {
829             FAIL_MESH_VALIDATE("%s mode requires at least %zu indices but index count is %zu.",
830                                modeToStr(fMode),
831                                min_vcount_for_mode(fMode),
832                                fICount);
833         }
834         size_t isize = sm.mul(sizeof(uint16_t), fICount);
835         if (sm.add(isize, fIOffset) > ib->size()) {
836             FAIL_MESH_VALIDATE("The index buffer offset and index count reads beyond the end of the"
837                                " index buffer.");
838 
839         }
840         // If we allow 32 bit indices then this should enforce 4 byte alignment in that case.
841         if (!SkIsAlign2(fIOffset)) {
842             FAIL_MESH_VALIDATE("The index offset must be a multiple of 2.");
843         }
844     } else {
845         if (fVCount < min_vcount_for_mode(fMode)) {
846             FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.",
847                                modeToStr(fMode),
848                                min_vcount_for_mode(fMode),
849                                fICount);
850         }
851         SkASSERT(!fICount);
852         SkASSERT(!fIOffset);
853     }
854 
855     if (!sm.ok()) {
856         FAIL_MESH_VALIDATE("Overflow");
857     }
858 #undef FAIL_MESH_VALIDATE
859     return {true, {}};
860 }
861 
862 //////////////////////////////////////////////////////////////////////////////
863 
check_update(const void * data,size_t offset,size_t size,size_t bufferSize)864 static inline bool check_update(const void* data, size_t offset, size_t size, size_t bufferSize) {
865     SkSafeMath sm;
866     return data                                &&
867            size                                &&
868            SkIsAlign4(offset)                  &&
869            SkIsAlign4(size)                    &&
870            sm.add(offset, size) <= bufferSize  &&
871            sm.ok();
872 }
873 
update(GrDirectContext * dc,const void * data,size_t offset,size_t size)874 bool SkMesh::IndexBuffer::update(GrDirectContext* dc,
875                                  const void* data,
876                                  size_t offset,
877                                  size_t size) {
878     return check_update(data, offset, size, this->size()) && this->onUpdate(dc, data, offset, size);
879 }
880 
update(GrDirectContext * dc,const void * data,size_t offset,size_t size)881 bool SkMesh::VertexBuffer::update(GrDirectContext* dc,
882                                   const void* data,
883                                   size_t offset,
884                                   size_t size) {
885     return check_update(data, offset, size, this->size()) && this->onUpdate(dc, data, offset, size);
886 }
887 
888 namespace SkMeshes {
MakeIndexBuffer(const void * data,size_t size)889 sk_sp<IndexBuffer> MakeIndexBuffer(const void* data, size_t size) {
890     return SkMeshPriv::CpuIndexBuffer::Make(data, size);
891 }
892 
CopyIndexBuffer(const sk_sp<IndexBuffer> & src)893 sk_sp<IndexBuffer> CopyIndexBuffer(const sk_sp<IndexBuffer>& src) {
894     if (!src) {
895         return nullptr;
896     }
897     auto* ib = static_cast<SkMeshPriv::IB*>(src.get());
898     const void* data = ib->peek();
899     if (!data) {
900         return nullptr;
901     }
902     return MakeIndexBuffer(data, ib->size());
903 }
904 
MakeVertexBuffer(const void * data,size_t size)905 sk_sp<VertexBuffer> MakeVertexBuffer(const void* data, size_t size) {
906     return SkMeshPriv::CpuVertexBuffer::Make(data, size);
907 }
908 
CopyVertexBuffer(const sk_sp<VertexBuffer> & src)909 sk_sp<VertexBuffer> CopyVertexBuffer(const sk_sp<VertexBuffer>& src) {
910     if (!src) {
911         return nullptr;
912     }
913     auto* vb = static_cast<SkMeshPriv::VB*>(src.get());
914     const void* data = vb->peek();
915     if (!data) {
916         return nullptr;
917     }
918     return MakeVertexBuffer(data, vb->size());
919 }
920 }  // namespace SkMeshes
921