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