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 <jni.h> 23 #include <log/log.h> 24 25 #include <utility> 26 27 class MeshUniformBuilder { 28 public: 29 struct MeshUniform { 30 template <typename T> 31 std::enable_if_t<std::is_trivially_copyable<T>::value, MeshUniform> operator=( 32 const T& val) { 33 if (!fVar) { 34 LOG_FATAL("Assigning to missing variable"); 35 } else if (sizeof(val) != fVar->sizeInBytes()) { 36 LOG_FATAL("Incorrect value size"); 37 } else { 38 void* dst = reinterpret_cast<void*>( 39 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset); 40 memcpy(dst, &val, sizeof(val)); 41 } 42 } 43 44 MeshUniform& operator=(const SkMatrix& val) { 45 if (!fVar) { 46 LOG_FATAL("Assigning to missing variable"); 47 } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { 48 LOG_FATAL("Incorrect value size"); 49 } else { 50 float* data = reinterpret_cast<float*>( 51 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset); 52 data[0] = val.get(0); 53 data[1] = val.get(3); 54 data[2] = val.get(6); 55 data[3] = val.get(1); 56 data[4] = val.get(4); 57 data[5] = val.get(7); 58 data[6] = val.get(2); 59 data[7] = val.get(5); 60 data[8] = val.get(8); 61 } 62 return *this; 63 } 64 65 template <typename T> setMeshUniform66 bool set(const T val[], const int count) { 67 static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); 68 if (!fVar) { 69 LOG_FATAL("Assigning to missing variable"); 70 return false; 71 } else if (sizeof(T) * count != fVar->sizeInBytes()) { 72 LOG_FATAL("Incorrect value size"); 73 return false; 74 } else { 75 void* dst = reinterpret_cast<void*>( 76 reinterpret_cast<uint8_t*>(fOwner->writableUniformData()) + fVar->offset); 77 memcpy(dst, val, sizeof(T) * count); 78 } 79 return true; 80 } 81 82 MeshUniformBuilder* fOwner; 83 const SkRuntimeEffect::Uniform* fVar; 84 }; uniform(std::string_view name)85 MeshUniform uniform(std::string_view name) { return {this, fMeshSpec->findUniform(name)}; } 86 MeshUniformBuilder(sk_sp<SkMeshSpecification> meshSpec)87 explicit MeshUniformBuilder(sk_sp<SkMeshSpecification> meshSpec) { 88 fMeshSpec = sk_sp(meshSpec); 89 fUniforms = (SkData::MakeZeroInitialized(meshSpec->uniformSize())); 90 } 91 92 sk_sp<SkData> fUniforms; 93 94 private: writableUniformData()95 void* writableUniformData() { 96 if (!fUniforms->unique()) { 97 fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); 98 } 99 return fUniforms->writable_data(); 100 } 101 102 sk_sp<SkMeshSpecification> fMeshSpec; 103 }; 104 105 class Mesh { 106 public: Mesh(const sk_sp<SkMeshSpecification> & meshSpec,int mode,std::vector<uint8_t> && vertexBufferData,jint vertexCount,jint vertexOffset,std::unique_ptr<MeshUniformBuilder> builder,const SkRect & bounds)107 Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, 108 std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset, 109 std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds) 110 : mMeshSpec(meshSpec) 111 , mMode(mode) 112 , mVertexBufferData(std::move(vertexBufferData)) 113 , mVertexCount(vertexCount) 114 , mVertexOffset(vertexOffset) 115 , mBuilder(std::move(builder)) 116 , mBounds(bounds) {} 117 Mesh(const sk_sp<SkMeshSpecification> & meshSpec,int mode,std::vector<uint8_t> && vertexBufferData,jint vertexCount,jint vertexOffset,std::vector<uint8_t> && indexBuffer,jint indexCount,jint indexOffset,std::unique_ptr<MeshUniformBuilder> builder,const SkRect & bounds)118 Mesh(const sk_sp<SkMeshSpecification>& meshSpec, int mode, 119 std::vector<uint8_t>&& vertexBufferData, jint vertexCount, jint vertexOffset, 120 std::vector<uint8_t>&& indexBuffer, jint indexCount, jint indexOffset, 121 std::unique_ptr<MeshUniformBuilder> builder, const SkRect& bounds) 122 : mMeshSpec(meshSpec) 123 , mMode(mode) 124 , mVertexBufferData(std::move(vertexBufferData)) 125 , mVertexCount(vertexCount) 126 , mVertexOffset(vertexOffset) 127 , mIndexBufferData(std::move(indexBuffer)) 128 , mIndexCount(indexCount) 129 , mIndexOffset(indexOffset) 130 , mBuilder(std::move(builder)) 131 , mBounds(bounds) {} 132 133 Mesh(Mesh&&) = default; 134 135 Mesh& operator=(Mesh&&) = default; 136 137 [[nodiscard]] std::tuple<bool, SkString> validate(); 138 updateSkMesh(GrDirectContext * context)139 void updateSkMesh(GrDirectContext* context) const { 140 GrDirectContext::DirectContextID genId = GrDirectContext::DirectContextID(); 141 if (context) { 142 genId = context->directContextID(); 143 } 144 145 if (mIsDirty || genId != mGenerationId) { 146 auto vb = SkMesh::MakeVertexBuffer( 147 context, reinterpret_cast<const void*>(mVertexBufferData.data()), 148 mVertexBufferData.size()); 149 auto meshMode = SkMesh::Mode(mMode); 150 if (!mIndexBufferData.empty()) { 151 auto ib = SkMesh::MakeIndexBuffer( 152 context, reinterpret_cast<const void*>(mIndexBufferData.data()), 153 mIndexBufferData.size()); 154 mMesh = SkMesh::MakeIndexed(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset, 155 ib, mIndexCount, mIndexOffset, mBuilder->fUniforms, 156 mBounds) 157 .mesh; 158 } else { 159 mMesh = SkMesh::Make(mMeshSpec, meshMode, vb, mVertexCount, mVertexOffset, 160 mBuilder->fUniforms, mBounds) 161 .mesh; 162 } 163 mIsDirty = false; 164 mGenerationId = genId; 165 } 166 } 167 getSkMesh()168 SkMesh& getSkMesh() const { 169 LOG_FATAL_IF(mIsDirty, 170 "Attempt to obtain SkMesh when Mesh is dirty, did you " 171 "forget to call updateSkMesh with a GrDirectContext? " 172 "Defensively creating a CPU mesh"); 173 return mMesh; 174 } 175 markDirty()176 void markDirty() { mIsDirty = true; } 177 uniformBuilder()178 MeshUniformBuilder* uniformBuilder() { return mBuilder.get(); } 179 180 private: 181 sk_sp<SkMeshSpecification> mMeshSpec; 182 int mMode = 0; 183 184 std::vector<uint8_t> mVertexBufferData; 185 size_t mVertexCount = 0; 186 size_t mVertexOffset = 0; 187 188 std::vector<uint8_t> mIndexBufferData; 189 size_t mIndexCount = 0; 190 size_t mIndexOffset = 0; 191 192 std::unique_ptr<MeshUniformBuilder> mBuilder; 193 SkRect mBounds{}; 194 195 mutable SkMesh mMesh{}; 196 mutable bool mIsDirty = true; 197 mutable GrDirectContext::DirectContextID mGenerationId = GrDirectContext::DirectContextID(); 198 }; 199 #endif // MESH_H_ 200