blob: 5ef7acdaf0fac10f79c926b6faffa448b8d787ea [file] [log] [blame]
Nader Jawad5f0a8002023-02-21 17:00:51 -08001/*
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
Alex Strelnikovb58afe62024-03-07 20:38:10 +000024namespace android {
25
Nader Jawad5f0a8002023-02-21 17:00:51 -080026static 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 }
Alex Strelnikovb58afe62024-03-07 20:38:10 +000033 return 1;
Nader Jawad5f0a8002023-02-21 17:00:51 -080034}
35
36// Re-implementation of SkMesh::validate to validate user side that their mesh is valid.
37std::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 }
Alex Strelnikovb58afe62024-03-07 20:38:10 +000042 if (mBufferData->vertexData().empty()) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080043 FAIL_MESH_VALIDATE("VertexBuffer is required.");
44 }
45
Alex Strelnikovb58afe62024-03-07 20:38:10 +000046 size_t vertexStride = mMeshSpec->stride();
47 size_t vertexCount = mBufferData->vertexCount();
48 size_t vertexOffset = mBufferData->vertexOffset();
Nader Jawad5f0a8002023-02-21 17:00:51 -080049 SafeMath sm;
Alex Strelnikovb58afe62024-03-07 20:38:10 +000050 size_t vertexSize = sm.mul(vertexStride, vertexCount);
51 if (sm.add(vertexSize, vertexOffset) > mBufferData->vertexData().size()) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080052 FAIL_MESH_VALIDATE(
53 "The vertex buffer offset and vertex count reads beyond the end of the"
54 " vertex buffer.");
55 }
56
Alex Strelnikovb58afe62024-03-07 20:38:10 +000057 if (vertexOffset % vertexStride != 0) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080058 FAIL_MESH_VALIDATE("The vertex offset (%zu) must be a multiple of the vertex stride (%zu).",
Alex Strelnikovb58afe62024-03-07 20:38:10 +000059 vertexOffset, vertexStride);
Nader Jawad5f0a8002023-02-21 17:00:51 -080060 }
61
62 if (size_t uniformSize = mMeshSpec->uniformSize()) {
Alex Strelnikovb58afe62024-03-07 20:38:10 +000063 if (!mUniformBuilder.fUniforms || mUniformBuilder.fUniforms->size() < uniformSize) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080064 FAIL_MESH_VALIDATE("The uniform data is %zu bytes but must be at least %zu.",
Alex Strelnikovb58afe62024-03-07 20:38:10 +000065 mUniformBuilder.fUniforms->size(), uniformSize);
Nader Jawad5f0a8002023-02-21 17:00:51 -080066 }
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 }
Alex Strelnikovb58afe62024-03-07 20:38:10 +000076 return "unknown";
Nader Jawad5f0a8002023-02-21 17:00:51 -080077 };
Alex Strelnikovb58afe62024-03-07 20:38:10 +000078
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)) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080083 FAIL_MESH_VALIDATE("%s mode requires at least %zu indices but index count is %zu.",
Alex Strelnikovb58afe62024-03-07 20:38:10 +000084 modeToStr(mMode), min_vcount_for_mode(mMode), indexCount);
Nader Jawad5f0a8002023-02-21 17:00:51 -080085 }
Alex Strelnikovb58afe62024-03-07 20:38:10 +000086 size_t isize = sm.mul(sizeof(uint16_t), indexCount);
87 if (sm.add(isize, indexOffset) > mBufferData->indexData().size()) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080088 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.
Alex Strelnikovb58afe62024-03-07 20:38:10 +000093 if (!SkIsAlign2(indexOffset)) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080094 FAIL_MESH_VALIDATE("The index offset must be a multiple of 2.");
95 }
96 } else {
Alex Strelnikovb58afe62024-03-07 20:38:10 +000097 if (vertexCount < min_vcount_for_mode(mMode)) {
Nader Jawad5f0a8002023-02-21 17:00:51 -080098 FAIL_MESH_VALIDATE("%s mode requires at least %zu vertices but vertex count is %zu.",
Alex Strelnikovb58afe62024-03-07 20:38:10 +000099 modeToStr(mMode), min_vcount_for_mode(mMode), vertexCount);
Nader Jawad5f0a8002023-02-21 17:00:51 -0800100 }
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000101 LOG_ALWAYS_FATAL_IF(indexCount != 0);
102 LOG_ALWAYS_FATAL_IF(indexOffset != 0);
Nader Jawad5f0a8002023-02-21 17:00:51 -0800103 }
104
105 if (!sm.ok()) {
106 FAIL_MESH_VALIDATE("Overflow");
107 }
108#undef FAIL_MESH_VALIDATE
109 return {true, {}};
110}
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000111
112} // namespace android