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