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