• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef MESH_H_
18 #define MESH_H_
19 
20 #include <GrDirectContext.h>
21 #include <SkMesh.h>
22 #include <include/gpu/ganesh/SkMeshGanesh.h>
23 #include <jni.h>
24 #include <log/log.h>
25 
26 #include <utility>
27 
28 namespace android {
29 
30 class MeshUniformBuilder {
31 public:
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>
setMeshUniform69         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     };
uniform(std::string_view name)88     MeshUniform uniform(std::string_view name) { return {this, fMeshSpec->findUniform(name)}; }
89 
MeshUniformBuilder(sk_sp<SkMeshSpecification> meshSpec)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 
97 private:
writableUniformData()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 
108 // Storage for CPU and GPU copies of the vertex and index data of a mesh.
109 class MeshBufferData {
110 public:
MeshBufferData(std::vector<uint8_t> vertexData,int32_t vertexCount,int32_t vertexOffset,std::vector<uint8_t> indexData,int32_t indexCount,int32_t indexOffset)111     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)
114             , mVertexOffset(vertexOffset)
115             , mIndexCount(indexCount)
116             , mIndexOffset(indexOffset)
117             , mVertexData(std::move(vertexData))
118             , mIndexData(std::move(indexData)) {}
119 
updateBuffers(GrDirectContext * context)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 
vertexBuffer()146     SkMesh::VertexBuffer* vertexBuffer() const { return mSkiaBuffers.fVertexBuffer.get(); }
147 
refVertexBuffer()148     sk_sp<SkMesh::VertexBuffer> refVertexBuffer() const { return mSkiaBuffers.fVertexBuffer; }
vertexCount()149     int32_t vertexCount() const { return mVertexCount; }
vertexOffset()150     int32_t vertexOffset() const { return mVertexOffset; }
151 
refIndexBuffer()152     sk_sp<SkMesh::IndexBuffer> refIndexBuffer() const { return mSkiaBuffers.fIndexBuffer; }
indexCount()153     int32_t indexCount() const { return mIndexCount; }
indexOffset()154     int32_t indexOffset() const { return mIndexOffset; }
155 
vertexData()156     const std::vector<uint8_t>& vertexData() const { return mVertexData; }
indexData()157     const std::vector<uint8_t>& indexData() const { return mIndexData; }
158 
159 private:
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 
175 class Mesh {
176 public:
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 
getSkMesh()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 
Snapshot(sk_sp<SkMeshSpecification> meshSpec,SkMesh::Mode mode,std::shared_ptr<const MeshBufferData> bufferData,sk_sp<const SkData> uniforms,const SkRect & bounds)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 
makeSkMesh()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 
Mesh(sk_sp<SkMeshSpecification> meshSpec,SkMesh::Mode mode,std::vector<uint8_t> vertexData,int32_t vertexCount,int32_t vertexOffset,const SkRect & bounds)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 
Mesh(sk_sp<SkMeshSpecification> meshSpec,SkMesh::Mode mode,std::vector<uint8_t> vertexData,int32_t vertexCount,int32_t vertexOffset,std::vector<uint8_t> indexData,int32_t indexCount,int32_t indexOffset,const SkRect & bounds)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)
248             , mBounds(bounds) {}
249 
250     Mesh(Mesh&&) = default;
251 
252     Mesh& operator=(Mesh&&) = default;
253 
254     [[nodiscard]] std::tuple<bool, SkString> validate();
255 
refBufferData()256     std::shared_ptr<const MeshBufferData> refBufferData() const { return mBufferData; }
257 
takeSnapshot()258     Snapshot takeSnapshot() const {
259         return Snapshot(mMeshSpec, mMode, mBufferData, mUniformBuilder.fUniforms, mBounds);
260     }
261 
uniformBuilder()262     MeshUniformBuilder* uniformBuilder() { return &mUniformBuilder; }
263 
264 private:
265     sk_sp<SkMeshSpecification> mMeshSpec;
266     SkMesh::Mode mMode;
267     std::shared_ptr<MeshBufferData> mBufferData;
268     MeshUniformBuilder mUniformBuilder;
269     SkRect mBounds;
270 };
271 
272 }  // namespace android
273 
274 #endif  // MESH_H_
275