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