blob: afc6adf7f3e0f0134a540985dd84c37dbd9a667a [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#ifndef MESH_H_
18#define MESH_H_
19
Nader Jawad5f0a8002023-02-21 17:00:51 -080020#include <SkMesh.h>
Nolan Scobie572d8012024-08-30 13:43:34 -040021#include <include/gpu/ganesh/GrDirectContext.h>
Kevin Lubick9cc7f772023-07-20 17:11:30 +000022#include <include/gpu/ganesh/SkMeshGanesh.h>
Nader Jawad5f0a8002023-02-21 17:00:51 -080023#include <jni.h>
24#include <log/log.h>
25
26#include <utility>
27
Alex Strelnikovb58afe62024-03-07 20:38:10 +000028namespace android {
29
Nader Jawad5f0a8002023-02-21 17:00:51 -080030class MeshUniformBuilder {
31public:
32 struct MeshUniform {
33 template <typename T>
34 std::enable_if_t<std::is_trivially_copyable<T>::value, MeshUniform> operator=(
35 const T& val) {
36 if (!fVar) {
37 LOG_FATAL("Assigning to missing variable");
38 } else if (sizeof(val) != fVar->sizeInBytes()) {
39 LOG_FATAL("Incorrect value size");
40 } else {
41 void* dst = reinterpret_cast<void*>(
42 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset);
43 memcpy(dst, &val, sizeof(val));
44 }
45 }
46
47 MeshUniform& operator=(const SkMatrix& val) {
48 if (!fVar) {
49 LOG_FATAL("Assigning to missing variable");
50 } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
51 LOG_FATAL("Incorrect value size");
52 } else {
53 float* data = reinterpret_cast<float*>(
54 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset);
55 data[0] = val.get(0);
56 data[1] = val.get(3);
57 data[2] = val.get(6);
58 data[3] = val.get(1);
59 data[4] = val.get(4);
60 data[5] = val.get(7);
61 data[6] = val.get(2);
62 data[7] = val.get(5);
63 data[8] = val.get(8);
64 }
65 return *this;
66 }
67
68 template <typename T>
69 bool set(const T val[], const int count) {
70 static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable");
71 if (!fVar) {
72 LOG_FATAL("Assigning to missing variable");
73 return false;
74 } else if (sizeof(T) * count != fVar->sizeInBytes()) {
75 LOG_FATAL("Incorrect value size");
76 return false;
77 } else {
78 void* dst = reinterpret_cast<void*>(
79 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset);
80 memcpy(dst, val, sizeof(T) * count);
81 }
82 return true;
83 }
84
85 MeshUniformBuilder* fOwner;
86 const SkRuntimeEffect::Uniform* fVar;
87 };
88 MeshUniform uniform(std::string_view name) { return {this, fMeshSpec->findUniform(name)}; }
89
90 explicit MeshUniformBuilder(sk_sp<SkMeshSpecification> meshSpec) {
91 fMeshSpec = sk_sp(meshSpec);
92 fUniforms = (SkData::MakeZeroInitialized(meshSpec->uniformSize()));
93 }
94
95 sk_sp<SkData> fUniforms;
96
97private:
98 void* writableUniformData() {
99 if (!fUniforms->unique()) {
100 fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
101 }
102 return fUniforms->writable_data();
103 }
104
105 sk_sp<SkMeshSpecification> fMeshSpec;
106};
107
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000108// Storage for CPU and GPU copies of the vertex and index data of a mesh.
109class MeshBufferData {
Nader Jawad5f0a8002023-02-21 17:00:51 -0800110public:
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000111 MeshBufferData(std::vector<uint8_t> vertexData, int32_t vertexCount, int32_t vertexOffset,
112 std::vector<uint8_t> indexData, int32_t indexCount, int32_t indexOffset)
113 : mVertexCount(vertexCount)
Nader Jawad5f0a8002023-02-21 17:00:51 -0800114 , mVertexOffset(vertexOffset)
Nader Jawad5f0a8002023-02-21 17:00:51 -0800115 , mIndexCount(indexCount)
116 , mIndexOffset(indexOffset)
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000117 , mVertexData(std::move(vertexData))
118 , mIndexData(std::move(indexData)) {}
119
120 void updateBuffers(GrDirectContext* context) const {
121 GrDirectContext::DirectContextID currentId = context == nullptr
122 ? GrDirectContext::DirectContextID()
123 : context->directContextID();
124 if (currentId == mSkiaBuffers.fGenerationId && mSkiaBuffers.fVertexBuffer != nullptr) {
125 // Nothing to update since the Android API does not support partial updates yet.
126 return;
127 }
128
129 mSkiaBuffers.fVertexBuffer =
130#ifdef __ANDROID__
131 SkMeshes::MakeVertexBuffer(context, mVertexData.data(), mVertexData.size());
132#else
133 SkMeshes::MakeVertexBuffer(mVertexData.data(), mVertexData.size());
134#endif
135 if (mIndexCount != 0) {
136 mSkiaBuffers.fIndexBuffer =
137#ifdef __ANDROID__
138 SkMeshes::MakeIndexBuffer(context, mIndexData.data(), mIndexData.size());
139#else
140 SkMeshes::MakeIndexBuffer(mIndexData.data(), mIndexData.size());
141#endif
142 }
143 mSkiaBuffers.fGenerationId = currentId;
144 }
145
146 SkMesh::VertexBuffer* vertexBuffer() const { return mSkiaBuffers.fVertexBuffer.get(); }
147
148 sk_sp<SkMesh::VertexBuffer> refVertexBuffer() const { return mSkiaBuffers.fVertexBuffer; }
149 int32_t vertexCount() const { return mVertexCount; }
150 int32_t vertexOffset() const { return mVertexOffset; }
151
152 sk_sp<SkMesh::IndexBuffer> refIndexBuffer() const { return mSkiaBuffers.fIndexBuffer; }
153 int32_t indexCount() const { return mIndexCount; }
154 int32_t indexOffset() const { return mIndexOffset; }
155
156 const std::vector<uint8_t>& vertexData() const { return mVertexData; }
157 const std::vector<uint8_t>& indexData() const { return mIndexData; }
158
159private:
160 struct CachedSkiaBuffers {
161 sk_sp<SkMesh::VertexBuffer> fVertexBuffer;
162 sk_sp<SkMesh::IndexBuffer> fIndexBuffer;
163 GrDirectContext::DirectContextID fGenerationId = GrDirectContext::DirectContextID();
164 };
165
166 mutable CachedSkiaBuffers mSkiaBuffers;
167 int32_t mVertexCount = 0;
168 int32_t mVertexOffset = 0;
169 int32_t mIndexCount = 0;
170 int32_t mIndexOffset = 0;
171 std::vector<uint8_t> mVertexData;
172 std::vector<uint8_t> mIndexData;
173};
174
175class Mesh {
176public:
177 // A snapshot of the mesh for use by the render thread.
178 //
179 // After a snapshot is taken, future uniform changes to the original Mesh will not modify the
180 // uniforms returned by makeSkMesh.
181 class Snapshot {
182 public:
183 Snapshot() = delete;
184 Snapshot(const Snapshot&) = default;
185 Snapshot(Snapshot&&) = default;
186 Snapshot& operator=(const Snapshot&) = default;
187 Snapshot& operator=(Snapshot&&) = default;
188 ~Snapshot() = default;
189
190 const SkMesh& getSkMesh() const {
191 SkMesh::VertexBuffer* vertexBuffer = mBufferData->vertexBuffer();
192 LOG_FATAL_IF(vertexBuffer == nullptr,
193 "Attempt to obtain SkMesh when vertexBuffer has not been created, did you "
194 "forget to call MeshBufferData::updateBuffers with a GrDirectContext?");
195 if (vertexBuffer != mMesh.vertexBuffer()) mMesh = makeSkMesh();
196 return mMesh;
197 }
198
199 private:
200 friend class Mesh;
201
202 Snapshot(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode,
203 std::shared_ptr<const MeshBufferData> bufferData, sk_sp<const SkData> uniforms,
204 const SkRect& bounds)
205 : mMeshSpec(std::move(meshSpec))
206 , mMode(mode)
207 , mBufferData(std::move(bufferData))
208 , mUniforms(std::move(uniforms))
209 , mBounds(bounds) {}
210
211 SkMesh makeSkMesh() const {
212 const MeshBufferData& d = *mBufferData;
213 if (d.indexCount() != 0) {
214 return SkMesh::MakeIndexed(mMeshSpec, mMode, d.refVertexBuffer(), d.vertexCount(),
215 d.vertexOffset(), d.refIndexBuffer(), d.indexCount(),
216 d.indexOffset(), mUniforms,
217 SkSpan<SkRuntimeEffect::ChildPtr>(), mBounds)
218 .mesh;
219 }
220 return SkMesh::Make(mMeshSpec, mMode, d.refVertexBuffer(), d.vertexCount(),
221 d.vertexOffset(), mUniforms, SkSpan<SkRuntimeEffect::ChildPtr>(),
222 mBounds)
223 .mesh;
224 }
225
226 mutable SkMesh mMesh;
227 sk_sp<SkMeshSpecification> mMeshSpec;
228 SkMesh::Mode mMode;
229 std::shared_ptr<const MeshBufferData> mBufferData;
230 sk_sp<const SkData> mUniforms;
231 SkRect mBounds;
232 };
233
234 Mesh(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode, std::vector<uint8_t> vertexData,
235 int32_t vertexCount, int32_t vertexOffset, const SkRect& bounds)
236 : Mesh(std::move(meshSpec), mode, std::move(vertexData), vertexCount, vertexOffset,
237 /* indexData = */ {}, /* indexCount = */ 0, /* indexOffset = */ 0, bounds) {}
238
239 Mesh(sk_sp<SkMeshSpecification> meshSpec, SkMesh::Mode mode, std::vector<uint8_t> vertexData,
240 int32_t vertexCount, int32_t vertexOffset, std::vector<uint8_t> indexData,
241 int32_t indexCount, int32_t indexOffset, const SkRect& bounds)
242 : mMeshSpec(std::move(meshSpec))
243 , mMode(mode)
244 , mBufferData(std::make_shared<MeshBufferData>(std::move(vertexData), vertexCount,
245 vertexOffset, std::move(indexData),
246 indexCount, indexOffset))
247 , mUniformBuilder(mMeshSpec)
Nader Jawad8c1d7aa2023-03-02 15:59:11 -0800248 , mBounds(bounds) {}
Nader Jawad5f0a8002023-02-21 17:00:51 -0800249
250 Mesh(Mesh&&) = default;
251
252 Mesh& operator=(Mesh&&) = default;
253
254 [[nodiscard]] std::tuple<bool, SkString> validate();
255
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000256 std::shared_ptr<const MeshBufferData> refBufferData() const { return mBufferData; }
Nader Jawad5f0a8002023-02-21 17:00:51 -0800257
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000258 Snapshot takeSnapshot() const {
259 return Snapshot(mMeshSpec, mMode, mBufferData, mUniformBuilder.fUniforms, mBounds);
Nader Jawad5f0a8002023-02-21 17:00:51 -0800260 }
261
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000262 MeshUniformBuilder* uniformBuilder() { return &mUniformBuilder; }
Nader Jawad5f0a8002023-02-21 17:00:51 -0800263
264private:
Nader Jawad5f0a8002023-02-21 17:00:51 -0800265 sk_sp<SkMeshSpecification> mMeshSpec;
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000266 SkMesh::Mode mMode;
267 std::shared_ptr<MeshBufferData> mBufferData;
268 MeshUniformBuilder mUniformBuilder;
269 SkRect mBounds;
Nader Jawad5f0a8002023-02-21 17:00:51 -0800270};
Alex Strelnikovb58afe62024-03-07 20:38:10 +0000271
272} // namespace android
273
Nader Jawad5f0a8002023-02-21 17:00:51 -0800274#endif // MESH_H_