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
24 namespace android {
25
min_vcount_for_mode(SkMesh::Mode mode)26 static size_t min_vcount_for_mode(SkMesh::Mode mode) {
27 switch (mode) {
28 case SkMesh::Mode::kTriangles:
29 return 3;
30 case SkMesh::Mode::kTriangleStrip:
31 return 3;
32 }
33 return 1;
34 }
35
36 // Re-implementation of SkMesh::validate to validate user side that their mesh is valid.
validate()37 std::tuple<bool, SkString> Mesh::validate() {
38 #define FAIL_MESH_VALIDATE(...) return std::make_tuple(false, SkStringPrintf(__VA_ARGS__))
39 if (!mMeshSpec) {
40 FAIL_MESH_VALIDATE("MeshSpecification is required.");
41 }
42 if (mBufferData->vertexData().empty()) {
43 FAIL_MESH_VALIDATE("VertexBuffer is required.");
44 }
45
46 size_t vertexStride = mMeshSpec->stride();
47 size_t vertexCount = mBufferData->vertexCount();
48 size_t vertexOffset = mBufferData->vertexOffset();
49 SafeMath sm;
50 size_t vertexSize = sm.mul(vertexStride, vertexCount);
51 if (sm.add(vertexSize, vertexOffset) > mBufferData->vertexData().size()) {
52 FAIL_MESH_VALIDATE(
53 "The vertex buffer offset and vertex count reads beyond the end of the"
54 " vertex buffer.");
55 }
56
57 if (vertexOffset % vertexStride != 0) {
58 FAIL_MESH_VALIDATE("The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
59 vertexOffset, vertexStride);
60 }
61
62 if (size_t uniformSize = mMeshSpec->uniformSize()) {
63 if (!mUniformBuilder.fUniforms || mUniformBuilder.fUniforms->size() < uniformSize) {
64 FAIL_MESH_VALIDATE("The uniform data is %zu bytes but must be at least %zu.",
65 mUniformBuilder.fUniforms->size(), uniformSize);
66 }
67 }
68
69 auto modeToStr = [](SkMesh::Mode m) {
70 switch (m) {
71 case SkMesh::Mode::kTriangles:
72 return "triangles";
73 case SkMesh::Mode::kTriangleStrip:
74 return "triangle-strip";
75 }
76 return "unknown";
77 };
78
79 size_t indexCount = mBufferData->indexCount();
80 size_t indexOffset = mBufferData->indexOffset();
81 if (!mBufferData->indexData().empty()) {
82 if (indexCount < min_vcount_for_mode(mMode)) {
83 FAIL_MESH_VALIDATE("%s mode requires at least %zu indices but index count is %zu.",
84 modeToStr(mMode), min_vcount_for_mode(mMode), indexCount);
85 }
86 size_t isize = sm.mul(sizeof(uint16_t), indexCount);
87 if (sm.add(isize, indexOffset) > mBufferData->indexData().size()) {
88 FAIL_MESH_VALIDATE(
89 "The index buffer offset and index count reads beyond the end of the"
90 " index buffer.");
91 }
92 // If we allow 32 bit indices then this should enforce 4 byte alignment in that case.
93 if (!SkIsAlign2(indexOffset)) {
94 FAIL_MESH_VALIDATE("The index offset must be a multiple of 2.");
95 }
96 } else {
97 if (vertexCount < min_vcount_for_mode(mMode)) {
98 FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.",
99 modeToStr(mMode), min_vcount_for_mode(mMode), vertexCount);
100 }
101 LOG_ALWAYS_FATAL_IF(indexCount != 0);
102 LOG_ALWAYS_FATAL_IF(indexOffset != 0);
103 }
104
105 if (!sm.ok()) {
106 FAIL_MESH_VALIDATE("Overflow");
107 }
108 #undef FAIL_MESH_VALIDATE
109 return {true, {}};
110 }
111
112 } // namespace android
113