1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "Mesh.h"
18
19 #include <GLES/gl.h>
20 #include <SkMesh.h>
21
22 #include "SafeMath.h"
23
min_vcount_for_mode(SkMesh::Mode mode)24 static size_t min_vcount_for_mode(SkMesh::Mode mode) {
25 switch (mode) {
26 case SkMesh::Mode::kTriangles:
27 return 3;
28 case SkMesh::Mode::kTriangleStrip:
29 return 3;
30 }
31 }
32
33 // Re-implementation of SkMesh::validate to validate user side that their mesh is valid.
validate()34 std::tuple<bool, SkString> Mesh::validate() {
35 #define FAIL_MESH_VALIDATE(...) return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
36 if (!mMeshSpec) {
37 FAIL_MESH_VALIDATE("MeshSpecification is required.");
38 }
39 if (mVertexBufferData.empty()) {
40 FAIL_MESH_VALIDATE("VertexBuffer is required.");
41 }
42
43 auto meshStride = mMeshSpec->stride();
44 auto meshMode = SkMesh::Mode(mMode);
45 SafeMath sm;
46 size_t vsize = sm.mul(meshStride, mVertexCount);
47 if (sm.add(vsize, mVertexOffset) > mVertexBufferData.size()) {
48 FAIL_MESH_VALIDATE(
49 "The vertex buffer offset and vertex count reads beyond the end of the"
50 " vertex buffer.");
51 }
52
53 if (mVertexOffset % meshStride != 0) {
54 FAIL_MESH_VALIDATE("The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
55 mVertexOffset, meshStride);
56 }
57
58 if (size_t uniformSize = mMeshSpec->uniformSize()) {
59 if (!mBuilder->fUniforms || mBuilder->fUniforms->size() < uniformSize) {
60 FAIL_MESH_VALIDATE("The uniform data is %zu bytes but must be at least %zu.",
61 mBuilder->fUniforms->size(), uniformSize);
62 }
63 }
64
65 auto modeToStr = [](SkMesh::Mode m) {
66 switch (m) {
67 case SkMesh::Mode::kTriangles:
68 return "triangles";
69 case SkMesh::Mode::kTriangleStrip:
70 return "triangle-strip";
71 }
72 };
73 if (!mIndexBufferData.empty()) {
74 if (mIndexCount < min_vcount_for_mode(meshMode)) {
75 FAIL_MESH_VALIDATE("%s mode requires at least %zu indices but index count is %zu.",
76 modeToStr(meshMode), min_vcount_for_mode(meshMode), mIndexCount);
77 }
78 size_t isize = sm.mul(sizeof(uint16_t), mIndexCount);
79 if (sm.add(isize, mIndexOffset) > mIndexBufferData.size()) {
80 FAIL_MESH_VALIDATE(
81 "The index buffer offset and index count reads beyond the end of the"
82 " index buffer.");
83 }
84 // If we allow 32 bit indices then this should enforce 4 byte alignment in that case.
85 if (!SkIsAlign2(mIndexOffset)) {
86 FAIL_MESH_VALIDATE("The index offset must be a multiple of 2.");
87 }
88 } else {
89 if (mVertexCount < min_vcount_for_mode(meshMode)) {
90 FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.",
91 modeToStr(meshMode), min_vcount_for_mode(meshMode), mVertexCount);
92 }
93 SkASSERT(!fICount);
94 SkASSERT(!fIOffset);
95 }
96
97 if (!sm.ok()) {
98 FAIL_MESH_VALIDATE("Overflow");
99 }
100 #undef FAIL_MESH_VALIDATE
101 return {true, {}};
102 }
103