1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkVertices.h" 9 10 #include "SkData.h" 11 #include "SkReader32.h" 12 #include "SkSafeMath.h" 13 #include "SkSafeRange.h" 14 #include "SkTo.h" 15 #include "SkWriter32.h" 16 #include <atomic> 17 #include <new> 18 19 static int32_t next_id() { 20 static std::atomic<int32_t> nextID{1}; 21 22 int32_t id; 23 do { 24 id = nextID++; 25 } while (id == SK_InvalidGenID); 26 return id; 27 } 28 29 struct SkVertices::Sizes { 30 Sizes(SkVertices::VertexMode mode, int vertexCount, int indexCount, bool hasTexs, 31 bool hasColors, bool hasBones) { 32 SkSafeMath safe; 33 34 fVSize = safe.mul(vertexCount, sizeof(SkPoint)); 35 fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0; 36 fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0; 37 fBISize = hasBones ? safe.mul(vertexCount, sizeof(BoneIndices)) : 0; 38 fBWSize = hasBones ? safe.mul(vertexCount, sizeof(BoneWeights)) : 0; 39 40 fBuilderTriFanISize = 0; 41 fISize = safe.mul(indexCount, sizeof(uint16_t)); 42 if (kTriangleFan_VertexMode == mode) { 43 int numFanTris = 0; 44 if (indexCount) { 45 fBuilderTriFanISize = fISize; 46 numFanTris = indexCount - 2; 47 } else { 48 numFanTris = vertexCount - 2; 49 // By forcing this to become indexed we are adding a constraint to the maximum 50 // number of vertices. 51 if (vertexCount > (SkTo<int>(UINT16_MAX) + 1)) { 52 sk_bzero(this, sizeof(*this)); 53 return; 54 } 55 } 56 if (numFanTris <= 0) { 57 sk_bzero(this, sizeof(*this)); 58 return; 59 } 60 fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t)); 61 } 62 63 fTotal = safe.add(sizeof(SkVertices), 64 safe.add(fVSize, 65 safe.add(fTSize, 66 safe.add(fCSize, 67 safe.add(fBISize, 68 safe.add(fBWSize, 69 fISize)))))); 70 71 if (safe.ok()) { 72 fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays 73 } else { 74 sk_bzero(this, sizeof(*this)); 75 } 76 } 77 78 bool isValid() const { return fTotal != 0; } 79 80 size_t fTotal; // size of entire SkVertices allocation (obj + arrays) 81 size_t fArrays; // size of all the arrays (V + T + C + BI + BW + I) 82 size_t fVSize; 83 size_t fTSize; 84 size_t fCSize; 85 size_t fBISize; 86 size_t fBWSize; 87 size_t fISize; 88 89 // For indexed tri-fans this is the number of amount of space fo indices needed in the builder 90 // before conversion to indexed triangles (or zero if not indexed or not a triangle fan). 91 size_t fBuilderTriFanISize; 92 }; 93 94 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, 95 uint32_t builderFlags) { 96 bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag); 97 bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag); 98 bool hasBones = SkToBool(builderFlags & SkVertices::kHasBones_BuilderFlag); 99 bool isVolatile = !SkToBool(builderFlags & SkVertices::kIsNonVolatile_BuilderFlag); 100 this->init(mode, vertexCount, indexCount, isVolatile, 101 SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones)); 102 } 103 104 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, 105 const SkVertices::Sizes& sizes) { 106 this->init(mode, vertexCount, indexCount, isVolatile, sizes); 107 } 108 109 void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile, 110 const SkVertices::Sizes& sizes) { 111 if (!sizes.isValid()) { 112 return; // fVertices will already be null 113 } 114 115 void* storage = ::operator new (sizes.fTotal); 116 if (sizes.fBuilderTriFanISize) { 117 fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]); 118 } 119 120 fVertices.reset(new (storage) SkVertices); 121 122 // need to point past the object to store the arrays 123 char* ptr = (char*)storage + sizeof(SkVertices); 124 125 fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize; 126 fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize; 127 fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize; 128 fVertices->fBoneIndices = sizes.fBISize ? (BoneIndices*) ptr : nullptr; ptr += sizes.fBISize; 129 fVertices->fBoneWeights = sizes.fBWSize ? (BoneWeights*) ptr : nullptr; ptr += sizes.fBWSize; 130 fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr; 131 fVertices->fVertexCnt = vertexCount; 132 fVertices->fIndexCnt = indexCount; 133 fVertices->fIsVolatile = isVolatile; 134 fVertices->fMode = mode; 135 136 // We defer assigning fBounds and fUniqueID until detach() is called 137 } 138 139 sk_sp<SkVertices> SkVertices::Builder::detach() { 140 if (fVertices) { 141 fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt); 142 if (fVertices->fMode == kTriangleFan_VertexMode) { 143 if (fIntermediateFanIndices.get()) { 144 SkASSERT(fVertices->fIndexCnt); 145 auto tempIndices = this->indices(); 146 for (int t = 0; t < fVertices->fIndexCnt - 2; ++t) { 147 fVertices->fIndices[3 * t + 0] = tempIndices[0]; 148 fVertices->fIndices[3 * t + 1] = tempIndices[t + 1]; 149 fVertices->fIndices[3 * t + 2] = tempIndices[t + 2]; 150 } 151 fVertices->fIndexCnt = 3 * (fVertices->fIndexCnt - 2); 152 } else { 153 SkASSERT(!fVertices->fIndexCnt); 154 for (int t = 0; t < fVertices->fVertexCnt - 2; ++t) { 155 fVertices->fIndices[3 * t + 0] = 0; 156 fVertices->fIndices[3 * t + 1] = SkToU16(t + 1); 157 fVertices->fIndices[3 * t + 2] = SkToU16(t + 2); 158 } 159 fVertices->fIndexCnt = 3 * (fVertices->fVertexCnt - 2); 160 } 161 fVertices->fMode = kTriangles_VertexMode; 162 } 163 fVertices->fUniqueID = next_id(); 164 return std::move(fVertices); // this will null fVertices after the return 165 } 166 return nullptr; 167 } 168 169 int SkVertices::Builder::vertexCount() const { 170 return fVertices ? fVertices->vertexCount() : 0; 171 } 172 173 int SkVertices::Builder::indexCount() const { 174 return fVertices ? fVertices->indexCount() : 0; 175 } 176 177 bool SkVertices::Builder::isVolatile() const { 178 return fVertices ? fVertices->isVolatile() : true; 179 } 180 181 SkPoint* SkVertices::Builder::positions() { 182 return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr; 183 } 184 185 SkPoint* SkVertices::Builder::texCoords() { 186 return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr; 187 } 188 189 SkColor* SkVertices::Builder::colors() { 190 return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr; 191 } 192 193 SkVertices::BoneIndices* SkVertices::Builder::boneIndices() { 194 return fVertices ? const_cast<BoneIndices*>(fVertices->boneIndices()) : nullptr; 195 } 196 197 SkVertices::BoneWeights* SkVertices::Builder::boneWeights() { 198 return fVertices ? const_cast<BoneWeights*>(fVertices->boneWeights()) : nullptr; 199 } 200 201 uint16_t* SkVertices::Builder::indices() { 202 if (!fVertices) { 203 return nullptr; 204 } 205 if (fIntermediateFanIndices) { 206 return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get()); 207 } 208 return const_cast<uint16_t*>(fVertices->indices()); 209 } 210 211 /** Makes a copy of the SkVertices and applies a set of bones, then returns the deformed 212 vertices. 213 214 @param bones The bones to apply. 215 @param boneCount The number of bones. 216 @return The transformed SkVertices. 217 */ 218 sk_sp<SkVertices> SkVertices::applyBones(const SkVertices::Bone bones[], int boneCount) const { 219 // If there aren't any bones, then nothing changes. 220 // We don't check if the SkVertices object has bone indices/weights because there is the case 221 // where the object can have no indices/weights but still have a world transform applied. 222 if (!bones || !boneCount) { 223 return sk_ref_sp(this); 224 } 225 SkASSERT(boneCount >= 1); 226 227 // Copy the SkVertices. 228 sk_sp<SkVertices> copy = SkVertices::MakeCopy(this->mode(), 229 this->vertexCount(), 230 this->positions(), 231 this->texCoords(), 232 this->colors(), 233 nullptr, 234 nullptr, 235 this->indexCount(), 236 this->indices()); 237 238 // Transform the positions. 239 for (int i = 0; i < this->vertexCount(); i++) { 240 SkPoint& position = copy->fPositions[i]; 241 242 // Apply the world transform. 243 position = bones[0].mapPoint(position); 244 245 // Apply the bone deformations. 246 if (boneCount > 1) { 247 SkASSERT(this->boneIndices()); 248 SkASSERT(this->boneWeights()); 249 250 SkPoint result = SkPoint::Make(0.0f, 0.0f); 251 const SkVertices::BoneIndices& indices = this->boneIndices()[i]; 252 const SkVertices::BoneWeights& weights = this->boneWeights()[i]; 253 for (int j = 0; j < 4; j++) { 254 int index = indices[j]; 255 float weight = weights[j]; 256 if (index == 0 || weight == 0.0f) { 257 continue; 258 } 259 SkASSERT(index < boneCount); 260 261 // result += M * v * w. 262 result += bones[index].mapPoint(position) * weight; 263 } 264 position = result; 265 } 266 } 267 268 // Recalculate the bounds. 269 copy->fBounds.set(copy->fPositions, copy->fVertexCnt); 270 271 return copy; 272 } 273 274 /////////////////////////////////////////////////////////////////////////////////////////////////// 275 276 sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount, 277 const SkPoint pos[], const SkPoint texs[], 278 const SkColor colors[], 279 const BoneIndices boneIndices[], 280 const BoneWeights boneWeights[], 281 int indexCount, const uint16_t indices[], 282 bool isVolatile) { 283 SkASSERT((!boneIndices && !boneWeights) || (boneIndices && boneWeights)); 284 Sizes sizes(mode, 285 vertexCount, 286 indexCount, 287 texs != nullptr, 288 colors != nullptr, 289 boneIndices != nullptr); 290 if (!sizes.isValid()) { 291 return nullptr; 292 } 293 294 Builder builder(mode, vertexCount, indexCount, isVolatile, sizes); 295 SkASSERT(builder.isValid()); 296 297 sk_careful_memcpy(builder.positions(), pos, sizes.fVSize); 298 sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize); 299 sk_careful_memcpy(builder.colors(), colors, sizes.fCSize); 300 sk_careful_memcpy(builder.boneIndices(), boneIndices, sizes.fBISize); 301 sk_careful_memcpy(builder.boneWeights(), boneWeights, sizes.fBWSize); 302 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize; 303 sk_careful_memcpy(builder.indices(), indices, isize); 304 305 return builder.detach(); 306 } 307 308 size_t SkVertices::approximateSize() const { 309 Sizes sizes(fMode, 310 fVertexCnt, 311 fIndexCnt, 312 this->hasTexCoords(), 313 this->hasColors(), 314 this->hasBones()); 315 SkASSERT(sizes.isValid()); 316 return sizeof(SkVertices) + sizes.fArrays; 317 } 318 319 /////////////////////////////////////////////////////////////////////////////////////////////////// 320 321 // storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | boneIndices[] | 322 // boneWeights[] | indices[] 323 // = header + arrays 324 325 #define kMode_Mask 0x0FF 326 #define kHasTexs_Mask 0x100 327 #define kHasColors_Mask 0x200 328 #define kHasBones_Mask 0x400 329 #define kIsNonVolatile_Mask 0x800 330 #define kHeaderSize (3 * sizeof(uint32_t)) 331 332 sk_sp<SkData> SkVertices::encode() const { 333 // packed has room for addtional flags in the future (e.g. versioning) 334 uint32_t packed = static_cast<uint32_t>(fMode); 335 SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits 336 if (this->hasTexCoords()) { 337 packed |= kHasTexs_Mask; 338 } 339 if (this->hasColors()) { 340 packed |= kHasColors_Mask; 341 } 342 if (this->hasBones()) { 343 packed |= kHasBones_Mask; 344 } 345 if (!this->isVolatile()) { 346 packed |= kIsNonVolatile_Mask; 347 } 348 349 Sizes sizes(fMode, 350 fVertexCnt, 351 fIndexCnt, 352 this->hasTexCoords(), 353 this->hasColors(), 354 this->hasBones()); 355 SkASSERT(sizes.isValid()); 356 SkASSERT(!sizes.fBuilderTriFanISize); 357 // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed 358 const size_t size = SkAlign4(kHeaderSize + sizes.fArrays); 359 360 sk_sp<SkData> data = SkData::MakeUninitialized(size); 361 SkWriter32 writer(data->writable_data(), data->size()); 362 363 writer.write32(packed); 364 writer.write32(fVertexCnt); 365 writer.write32(fIndexCnt); 366 writer.write(fPositions, sizes.fVSize); 367 writer.write(fTexs, sizes.fTSize); 368 writer.write(fColors, sizes.fCSize); 369 writer.write(fBoneIndices, sizes.fBISize); 370 writer.write(fBoneWeights, sizes.fBWSize); 371 // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version 372 writer.writePad(fIndices, sizes.fISize); 373 374 return data; 375 } 376 377 sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) { 378 if (length < kHeaderSize) { 379 return nullptr; 380 } 381 382 SkReader32 reader(data, length); 383 SkSafeRange safe; 384 385 const uint32_t packed = reader.readInt(); 386 const int vertexCount = safe.checkGE(reader.readInt(), 0); 387 const int indexCount = safe.checkGE(reader.readInt(), 0); 388 const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask, 389 SkVertices::kLast_VertexMode); 390 if (!safe) { 391 return nullptr; 392 } 393 const bool hasTexs = SkToBool(packed & kHasTexs_Mask); 394 const bool hasColors = SkToBool(packed & kHasColors_Mask); 395 const bool hasBones = SkToBool(packed & kHasBones_Mask); 396 const bool isVolatile = !SkToBool(packed & kIsNonVolatile_Mask); 397 Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones); 398 if (!sizes.isValid()) { 399 return nullptr; 400 } 401 // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned 402 if (SkAlign4(kHeaderSize + sizes.fArrays) != length) { 403 return nullptr; 404 } 405 406 Builder builder(mode, vertexCount, indexCount, isVolatile, sizes); 407 408 reader.read(builder.positions(), sizes.fVSize); 409 reader.read(builder.texCoords(), sizes.fTSize); 410 reader.read(builder.colors(), sizes.fCSize); 411 reader.read(builder.boneIndices(), sizes.fBISize); 412 reader.read(builder.boneWeights(), sizes.fBWSize); 413 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize; 414 reader.read(builder.indices(), isize); 415 if (indexCount > 0) { 416 // validate that the indicies are in range 417 SkASSERT(indexCount == builder.indexCount()); 418 const uint16_t* indices = builder.indices(); 419 for (int i = 0; i < indexCount; ++i) { 420 if (indices[i] >= (unsigned)vertexCount) { 421 return nullptr; 422 } 423 } 424 } 425 return builder.detach(); 426 } 427 428 void SkVertices::operator delete(void* p) 429 { 430 ::operator delete(p); 431 } 432