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 "include/core/SkVertices.h"
9
10#include "include/core/SkData.h"
11#include "include/private/SkTo.h"
12#include "src/core/SkReader32.h"
13#include "src/core/SkSafeMath.h"
14#include "src/core/SkSafeRange.h"
15#include "src/core/SkVerticesPriv.h"
16#include "src/core/SkWriter32.h"
17#include <atomic>
18#include <new>
19
20static int32_t next_id() {
21 static std::atomic<int32_t> nextID{1};
22
23 int32_t id;
24 do {
25 id = nextID++;
26 } while (id == SK_InvalidGenID);
27 return id;
28}
29
30int SkVertices::Attribute::channelCount() const {
31 SkASSERT(this->isValid());
32 switch (fUsage) {
33 case Usage::kRaw: break;
34 case Usage::kColor: return 4;
35 case Usage::kVector: return 3;
36 case Usage::kNormalVector: return 3;
37 case Usage::kPosition: return 3;
38 }
39 switch (fType) {
40 case Type::kFloat: return 1;
41 case Type::kFloat2: return 2;
42 case Type::kFloat3: return 3;
43 case Type::kFloat4: return 4;
44 case Type::kByte4_unorm: return 4;
45 }
46 SkUNREACHABLE;
47}
48
49size_t SkVertices::Attribute::bytesPerVertex() const {
50 switch (fType) {
51 case Type::kFloat: return 1 * sizeof(float);
52 case Type::kFloat2: return 2 * sizeof(float);
53 case Type::kFloat3: return 3 * sizeof(float);
54 case Type::kFloat4: return 4 * sizeof(float);
55 case Type::kByte4_unorm: return 4 * sizeof(uint8_t);
56 }
57 SkUNREACHABLE;
58}
59
60bool SkVertices::Attribute::isValid() const {
61 switch (fUsage) {
62 case Usage::kRaw:
63 return true;
64 case Usage::kColor:
65 return fType == Type::kFloat3 || fType == Type::kFloat4 || fType == Type::kByte4_unorm;
66 case Usage::kVector:
67 case Usage::kNormalVector:
68 case Usage::kPosition:
69 return fType == Type::kFloat2 || fType == Type::kFloat3;
70 }
71 SkUNREACHABLE;
72}
73
74static size_t custom_data_size(const SkVertices::Attribute* attrs, int attrCount) {
75 size_t size = 0;
76 for (int i = 0; i < attrCount; ++i) {
77 size += attrs[i].bytesPerVertex();
78 }
79 return size;
80}
81
82struct SkVertices::Desc {
83 VertexMode fMode;
84 int fVertexCount,
85 fIndexCount;
86 bool fHasTexs,
87 fHasColors;
88
89 const Attribute* fAttributes;
90 int fAttributeCount;
91
92 void validate() const {
93 SkASSERT(fAttributeCount == 0 || (!fHasTexs && !fHasColors));
94 }
95};
96
97struct SkVertices::Sizes {
98 Sizes(const Desc& desc) {
99 desc.validate();
100
101 for (int i = 0; i < desc.fAttributeCount; ++i) {
102 if (!desc.fAttributes[i].isValid()) {
103 return;
104 }
105 }
106
107 SkSafeMath safe;
108
109 fVSize = safe.mul(desc.fVertexCount, sizeof(SkPoint));
110 fDSize = safe.mul(custom_data_size(desc.fAttributes, desc.fAttributeCount),
111 desc.fVertexCount);
112 fTSize = desc.fHasTexs ? safe.mul(desc.fVertexCount, sizeof(SkPoint)) : 0;
113 fCSize = desc.fHasColors ? safe.mul(desc.fVertexCount, sizeof(SkColor)) : 0;
114
115 fBuilderTriFanISize = 0;
116 fISize = safe.mul(desc.fIndexCount, sizeof(uint16_t));
117 if (kTriangleFan_VertexMode == desc.fMode) {
118 int numFanTris = 0;
119 if (desc.fIndexCount) {
120 fBuilderTriFanISize = fISize;
121 numFanTris = desc.fIndexCount - 2;
122 } else {
123 numFanTris = desc.fVertexCount - 2;
124 // By forcing this to become indexed we are adding a constraint to the maximum
125 // number of vertices.
126 if (desc.fVertexCount > (SkTo<int>(UINT16_MAX) + 1)) {
127 sk_bzero(this, sizeof(*this));
128 return;
129 }
130 }
131 if (numFanTris <= 0) {
132 sk_bzero(this, sizeof(*this));
133 return;
134 }
135 fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t));
136 }
137
138 fTotal = safe.add(sizeof(SkVertices),
139 safe.add(fVSize,
140 safe.add(fDSize,
141 safe.add(fTSize,
142 safe.add(fCSize,
143 fISize)))));
144
145 if (safe.ok()) {
146 fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays
147 } else {
148 sk_bzero(this, sizeof(*this));
149 }
150 }
151
152 bool isValid() const { return fTotal != 0; }
153
154 size_t fTotal; // size of entire SkVertices allocation (obj + arrays)
155 size_t fArrays; // size of all the arrays (V + D + T + C + I)
156 size_t fVSize;
157 size_t fDSize; // size of all customData = [customDataSize * fVertexCount]
158 size_t fTSize;
159 size_t fCSize;
160 size_t fISize;
161
162 // For indexed tri-fans this is the number of amount of space fo indices needed in the builder
163 // before conversion to indexed triangles (or zero if not indexed or not a triangle fan).
164 size_t fBuilderTriFanISize;
165};
166
167SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
168 uint32_t builderFlags) {
169 bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
170 bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
171 this->init({mode, vertexCount, indexCount, hasTexs, hasColors, nullptr, 0});
172}
173
174SkVertices::Builder::Builder(VertexMode mode,
175 int vertexCount,
176 int indexCount,
177 const SkVertices::Attribute* attrs,
178 int attrCount) {
179 if (attrCount <= 0 || attrCount > kMaxCustomAttributes || !attrs) {
180 return;
181 }
182 this->init({mode, vertexCount, indexCount, false, false, attrs, attrCount});
183}
184
185SkVertices::Builder::Builder(const Desc& desc) {
186 this->init(desc);
187}
188
189void SkVertices::Builder::init(const Desc& desc) {
190 Sizes sizes(desc);
191 if (!sizes.isValid()) {
192 SkASSERT(!this->isValid());
193 return;
194 }
195
196 void* storage = ::operator new (sizes.fTotal);
197 if (sizes.fBuilderTriFanISize) {
198 fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]);
199 }
200
201 fVertices.reset(new (storage) SkVertices);
202
203 // need to point past the object to store the arrays
204 char* ptr = (char*)storage + sizeof(SkVertices);
205
206 // return the original ptr (or null), but then advance it by size
207 auto advance = [&ptr](size_t size) {
208 char* new_ptr = size ? ptr : nullptr;
209 ptr += size;
210 return new_ptr;
211 };
212
213 fVertices->fPositions = (SkPoint*) advance(sizes.fVSize);
214 fVertices->fCustomData = (void*) advance(sizes.fDSize);
215 fVertices->fTexs = (SkPoint*) advance(sizes.fTSize);
216 fVertices->fColors = (SkColor*) advance(sizes.fCSize);
217 fVertices->fIndices = (uint16_t*)advance(sizes.fISize);
218
219 fVertices->fVertexCount = desc.fVertexCount;
220 fVertices->fIndexCount = desc.fIndexCount;
221
222 sk_careful_memcpy(fVertices->fAttributes, desc.fAttributes,
223 desc.fAttributeCount * sizeof(Attribute));
224 fVertices->fAttributeCount = desc.fAttributeCount;
225
226 fVertices->fMode = desc.fMode;
227
228 // We defer assigning fBounds and fUniqueID until detach() is called
229}
230
231sk_sp<SkVertices> SkVertices::Builder::detach() {
232 if (fVertices) {
233 fVertices->fBounds.setBounds(fVertices->fPositions, fVertices->fVertexCount);
234 if (fVertices->fMode == kTriangleFan_VertexMode) {
235 if (fIntermediateFanIndices.get()) {
236 SkASSERT(fVertices->fIndexCount);
237 auto tempIndices = this->indices();
238 for (int t = 0; t < fVertices->fIndexCount - 2; ++t) {
239 fVertices->fIndices[3 * t + 0] = tempIndices[0];
240 fVertices->fIndices[3 * t + 1] = tempIndices[t + 1];
241 fVertices->fIndices[3 * t + 2] = tempIndices[t + 2];
242 }
243 fVertices->fIndexCount = 3 * (fVertices->fIndexCount - 2);
244 } else {
245 SkASSERT(!fVertices->fIndexCount);
246 for (int t = 0; t < fVertices->fVertexCount - 2; ++t) {
247 fVertices->fIndices[3 * t + 0] = 0;
248 fVertices->fIndices[3 * t + 1] = SkToU16(t + 1);
249 fVertices->fIndices[3 * t + 2] = SkToU16(t + 2);
250 }
251 fVertices->fIndexCount = 3 * (fVertices->fVertexCount - 2);
252 }
253 fVertices->fMode = kTriangles_VertexMode;
254 }
255 fVertices->fUniqueID = next_id();
256 return std::move(fVertices); // this will null fVertices after the return
257 }
258 return nullptr;
259}
260
261SkPoint* SkVertices::Builder::positions() {
262 return fVertices ? const_cast<SkPoint*>(fVertices->fPositions) : nullptr;
263}
264
265void* SkVertices::Builder::customData() {
266 return fVertices ? const_cast<void*>(fVertices->fCustomData) : nullptr;
267}
268
269SkPoint* SkVertices::Builder::texCoords() {
270 return fVertices ? const_cast<SkPoint*>(fVertices->fTexs) : nullptr;
271}
272
273SkColor* SkVertices::Builder::colors() {
274 return fVertices ? const_cast<SkColor*>(fVertices->fColors) : nullptr;
275}
276
277uint16_t* SkVertices::Builder::indices() {
278 if (!fVertices) {
279 return nullptr;
280 }
281 if (fIntermediateFanIndices) {
282 return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get());
283 }
284 return const_cast<uint16_t*>(fVertices->fIndices);
285}
286
287///////////////////////////////////////////////////////////////////////////////////////////////////
288
289sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
290 const SkPoint pos[], const SkPoint texs[],
291 const SkColor colors[],
292 int indexCount, const uint16_t indices[]) {
293 auto desc = Desc{mode, vertexCount, indexCount, !!texs, !!colors, nullptr, 0};
294 Builder builder(desc);
295 if (!builder.isValid()) {
296 return nullptr;
297 }
298
299 Sizes sizes(desc);
300 SkASSERT(sizes.isValid());
301 sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
302 sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
303 sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
304 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
305 sk_careful_memcpy(builder.indices(), indices, isize);
306
307 return builder.detach();
308}
309
310size_t SkVertices::approximateSize() const {
311 return sizeof(SkVertices) + this->getSizes().fArrays;
312}
313
314SkVertices::Sizes SkVertices::getSizes() const {
315 Sizes sizes(
316 {fMode, fVertexCount, fIndexCount, !!fTexs, !!fColors, fAttributes, fAttributeCount});
317 SkASSERT(sizes.isValid());
318 return sizes;
319}
320
321size_t SkVerticesPriv::customDataSize() const {
322 return custom_data_size(fVertices->fAttributes, fVertices->fAttributeCount);
323}
324
325bool SkVerticesPriv::hasUsage(SkVertices::Attribute::Usage u) const {
326 for (int i = 0; i < fVertices->fAttributeCount; ++i) {
327 if (fVertices->fAttributes[i].fUsage == u) {
328 return true;
329 }
330 }
331 return false;
332}
333
334bool SkVerticesPriv::usesLocalToWorldMatrix() const {
335 for (int i = 0; i < fVertices->fAttributeCount; ++i) {
336 switch (fVertices->fAttributes[i].fUsage) {
337 case SkVertices::Attribute::Usage::kVector:
338 case SkVertices::Attribute::Usage::kNormalVector:
339 case SkVertices::Attribute::Usage::kPosition:
340 return true;
341 default:
342 break;
343 }
344 }
345 return false;
346}
347
348///////////////////////////////////////////////////////////////////////////////////////////////////
349
350enum EncodedVerticesVersions {
351 kOriginal_Version = 0, // before we called out the mask for versions
352 kNoBones_Version = 1, // we explicitly ignore the bones-flag (0x400)
353 kPerVertexData_Version = 2, // add new count (and array)
354 kAttribute_Version = 3, // Adds array of custom attribute types
355
356 kCurrent_Version = kAttribute_Version
357};
358
359struct Header_v1 {
360 uint32_t fPacked;
361 int32_t fVertexCount;
362 int32_t fIndexCount;
363 // [pos] + [texs] + [colors] + [indices]
364};
365
366struct Header_v2 {
367 uint32_t fPacked;
368 int32_t fVertexCount;
369 int32_t fIndexCount;
370 int32_t fPerVertexDataCount;
371 // [pos] + [vertexData] + [texs] + [colors] + [indices]
372};
373
374struct Header_v3 {
375 uint32_t fPacked;
376 int32_t fVertexCount;
377 int32_t fIndexCount;
378 int32_t fAttributeCount;
379 SkVertices::Attribute fAttributes[SkVertices::kMaxCustomAttributes];
380 // [pos] + [vertexData] + [texs] + [colors] + [indices]
381};
382
383#define kCurrentHeaderSize sizeof(Header_v3)
384
385// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | boneIndices[] |
386// boneWeights[] | indices[]
387// = header + arrays
388
389#define kMode_Mask 0x0FF
390#define kHasTexs_Mask 0x100
391#define kHasColors_Mask 0x200
392#define kHasBones_Mask_V0 0x400
393#define kIsNonVolatile_Mask 0x800 // Deprecated flag
394// new as of 3/2020
395#define kVersion_Shift 24
396#define kVersion_Mask (0xFF << kVersion_Shift)
397
398sk_sp<SkData> SkVertices::encode() const {
399 // packed has room for addtional flags in the future (e.g. versioning)
400 uint32_t packed = static_cast<uint32_t>(fMode);
401 SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits
402 if (fTexs) {
403 packed |= kHasTexs_Mask;
404 }
405 if (fColors) {
406 packed |= kHasColors_Mask;
407 }
408 packed |= kCurrent_Version << kVersion_Shift;
409
410 Sizes sizes = this->getSizes();
411 SkASSERT(!sizes.fBuilderTriFanISize);
412 // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
413 const size_t size = SkAlign4(kCurrentHeaderSize + sizes.fArrays);
414
415 sk_sp<SkData> data = SkData::MakeUninitialized(size);
416 SkWriter32 writer(data->writable_data(), data->size());
417
418 writer.write32(packed);
419 writer.write32(fVertexCount);
420 writer.write32(fIndexCount);
421 writer.write32(fAttributeCount);
422
423 // Write all custom attribute slots to simplify alignment
424 writer.write(fAttributes, sizeof(fAttributes));
425
426 writer.write(fPositions, sizes.fVSize);
427 writer.write(fCustomData, sizes.fDSize);
428 writer.write(fTexs, sizes.fTSize);
429 writer.write(fColors, sizes.fCSize);
430 // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
431 writer.writePad(fIndices, sizes.fISize);
432
433 return data;
434}
435
436sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
437 if (length < sizeof(Header_v1)) {
438 return nullptr;
439 }
440
441 SkReader32 reader(data, length);
442 SkSafeRange safe;
443
444 const uint32_t packed = reader.readInt();
445 const unsigned version = safe.checkLE<unsigned>((packed & kVersion_Mask) >> kVersion_Shift,
446 kCurrent_Version);
447 const int vertexCount = safe.checkGE(reader.readInt(), 0);
448 const int indexCount = safe.checkGE(reader.readInt(), 0);
449 const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask,
450 SkVertices::kLast_VertexMode);
451 if (!safe) {
452 return nullptr;
453 }
454 if (version >= kPerVertexData_Version && length < sizeof(Header_v2)) {
455 return nullptr;
456 }
457 if (version >= kAttribute_Version && length < sizeof(Header_v3)) {
458 return nullptr;
459 }
460
461 Attribute attrs[kMaxCustomAttributes];
462 const int attrCount = (version >= kPerVertexData_Version) ? reader.readS32() : 0;
463 if (attrCount < 0 || attrCount > kMaxCustomAttributes) {
464 return nullptr;
465 }
466
467 if (version >= kAttribute_Version) {
468 reader.read(attrs, sizeof(attrs));
469 } else if (version == kPerVertexData_Version) {
470 // Attributes default to kFloat, which works fine to migrate this version of data.
471 }
472
473 // now we finish unpacking the packed field
474 const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
475 const bool hasColors = SkToBool(packed & kHasColors_Mask);
476 const bool hasBones = SkToBool(packed & kHasBones_Mask_V0);
477
478 // check if we're overspecified for v2+
479 if (attrCount > 0 && (hasTexs || hasColors || hasBones)) {
480 return nullptr;
481 }
482 const Desc desc{
483 mode, vertexCount, indexCount, hasTexs, hasColors, attrCount ? attrs : nullptr, attrCount
484 };
485 Sizes sizes(desc);
486 if (!sizes.isValid()) {
487 return nullptr;
488 }
489 // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
490 if (reader.available() != SkAlign4(sizes.fArrays)) {
491 return nullptr;
492 }
493
494 Builder builder(desc);
495 if (!builder.isValid()) {
496 return nullptr;
497 }
498 SkSafeMath safe_math;
499
500 reader.read(builder.positions(), sizes.fVSize);
501 reader.read(builder.customData(), sizes.fDSize);
502 reader.read(builder.texCoords(), sizes.fTSize);
503 reader.read(builder.colors(), sizes.fCSize);
504 if (hasBones) {
505 reader.skip(safe_math.mul(vertexCount, sizeof(SkVertices_DeprecatedBoneIndices)));
506 reader.skip(safe_math.mul(vertexCount, sizeof(SkVertices_DeprecatedBoneWeights)));
507 }
508 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
509 reader.read(builder.indices(), isize);
510 if (indexCount > 0) {
511 // validate that the indices are in range
512 const uint16_t* indices = builder.indices();
513 for (int i = 0; i < indexCount; ++i) {
514 if (indices[i] >= (unsigned)vertexCount) {
515 return nullptr;
516 }
517 }
518 }
519
520 if (!safe_math.ok()) {
521 return nullptr;
522 }
523 return builder.detach();
524}
525
526void SkVertices::operator delete(void* p) {
527 ::operator delete(p);
528}
529