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 
next_id()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 {
SizesSkVertices::Sizes30     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 
isValidSkVertices::Sizes78     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 
Builder(VertexMode mode,int vertexCount,int indexCount,uint32_t builderFlags)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 
Builder(VertexMode mode,int vertexCount,int indexCount,bool isVolatile,const SkVertices::Sizes & sizes)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 
init(VertexMode mode,int vertexCount,int indexCount,bool isVolatile,const SkVertices::Sizes & sizes)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 
detach()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 
vertexCount() const169 int SkVertices::Builder::vertexCount() const {
170     return fVertices ? fVertices->vertexCount() : 0;
171 }
172 
indexCount() const173 int SkVertices::Builder::indexCount() const {
174     return fVertices ? fVertices->indexCount() : 0;
175 }
176 
isVolatile() const177 bool SkVertices::Builder::isVolatile() const {
178     return fVertices ? fVertices->isVolatile() : true;
179 }
180 
positions()181 SkPoint* SkVertices::Builder::positions() {
182     return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
183 }
184 
texCoords()185 SkPoint* SkVertices::Builder::texCoords() {
186     return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
187 }
188 
colors()189 SkColor* SkVertices::Builder::colors() {
190     return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
191 }
192 
boneIndices()193 SkVertices::BoneIndices* SkVertices::Builder::boneIndices() {
194     return fVertices ? const_cast<BoneIndices*>(fVertices->boneIndices()) : nullptr;
195 }
196 
boneWeights()197 SkVertices::BoneWeights* SkVertices::Builder::boneWeights() {
198     return fVertices ? const_cast<BoneWeights*>(fVertices->boneWeights()) : nullptr;
199 }
200 
indices()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 */
applyBones(const SkVertices::Bone bones[],int boneCount) const218 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 
MakeCopy(VertexMode mode,int vertexCount,const SkPoint pos[],const SkPoint texs[],const SkColor colors[],const BoneIndices boneIndices[],const BoneWeights boneWeights[],int indexCount,const uint16_t indices[],bool isVolatile)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 
approximateSize() const308 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 
encode() const332 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 
Decode(const void * data,size_t length)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 
operator delete(void * p)428 void SkVertices::operator delete(void* p)
429 {
430     ::operator delete(p);
431 }
432