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