Coverage Report

Created: 2024-09-14 07:19

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