blob: d4c6ed56de8fb39b8b514e4b0af43505f4d2b28e [file] [log] [blame]
Mike Reed97eb4fe2017-03-14 12:04:16 -04001/*
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
Hal Canaryfdcfb8b2018-06-13 09:42:32 -04008#include "SkVertices.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -04009
10#include "SkAtomics.h"
Mike Reedbdce9c22017-03-14 14:10:54 -040011#include "SkData.h"
12#include "SkReader32.h"
Mike Reedf00faa32018-01-09 13:30:54 -050013#include "SkSafeMath.h"
Mike Reed165fa632018-01-23 11:50:25 -050014#include "SkSafeRange.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040015#include "SkTo.h"
Mike Reedbdce9c22017-03-14 14:10:54 -040016#include "SkWriter32.h"
Mike Klein79aea6a2018-06-11 10:45:26 -040017#include <new>
Mike Reedbdce9c22017-03-14 14:10:54 -040018
Mike Reed9a8065d2017-03-14 21:05:17 -040019static int32_t gNextID = 1;
20static int32_t next_id() {
21 int32_t id;
22 do {
23 id = sk_atomic_inc(&gNextID);
24 } while (id == SK_InvalidGenID);
25 return id;
26}
27
Mike Reedaa9e3322017-03-16 14:38:48 -040028struct SkVertices::Sizes {
Brian Salomoncccafe82018-04-28 16:13:08 -040029 Sizes(SkVertices::VertexMode mode, int vertexCount, int indexCount, bool hasTexs,
30 bool hasColors) {
Mike Reedf00faa32018-01-09 13:30:54 -050031 SkSafeMath safe;
Mike Reedaa9e3322017-03-16 14:38:48 -040032
Mike Reedf00faa32018-01-09 13:30:54 -050033 fVSize = safe.mul(vertexCount, sizeof(SkPoint));
34 fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0;
35 fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0;
Brian Salomoncccafe82018-04-28 16:13:08 -040036
37 fBuilderTriFanISize = 0;
Mike Reedf00faa32018-01-09 13:30:54 -050038 fISize = safe.mul(indexCount, sizeof(uint16_t));
Brian Salomoncccafe82018-04-28 16:13:08 -040039 if (kTriangleFan_VertexMode == mode) {
40 int numFanTris = 0;
41 if (indexCount) {
42 fBuilderTriFanISize = fISize;
43 numFanTris = indexCount - 2;
44 } else {
45 numFanTris = vertexCount - 2;
46 // By forcing this to become indexed we are adding a constraint to the maximum
47 // number of vertices.
Ben Wagnerdde9b522018-06-15 16:19:56 -040048 if (vertexCount > (SkTo<int>(UINT16_MAX) + 1)) {
Brian Salomoncccafe82018-04-28 16:13:08 -040049 sk_bzero(this, sizeof(*this));
50 return;
51 }
52 }
53 if (numFanTris <= 0) {
54 sk_bzero(this, sizeof(*this));
55 return;
56 }
57 fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t));
58 }
59
Mike Reedf00faa32018-01-09 13:30:54 -050060 fTotal = safe.add(sizeof(SkVertices),
61 safe.add(fVSize,
62 safe.add(fTSize,
63 safe.add(fCSize,
64 fISize))));
65
66 if (safe.ok()) {
Mike Reedaa9e3322017-03-16 14:38:48 -040067 fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays
Mike Reedf00faa32018-01-09 13:30:54 -050068 } else {
69 sk_bzero(this, sizeof(*this));
Mike Reedaa9e3322017-03-16 14:38:48 -040070 }
Mike Reedbdce9c22017-03-14 14:10:54 -040071 }
72
Mike Reedaa9e3322017-03-16 14:38:48 -040073 bool isValid() const { return fTotal != 0; }
74
75 size_t fTotal; // size of entire SkVertices allocation (obj + arrays)
76 size_t fArrays; // size of all the arrays (V + T + C + I)
77 size_t fVSize;
78 size_t fTSize;
79 size_t fCSize;
80 size_t fISize;
Brian Salomoncccafe82018-04-28 16:13:08 -040081
82 // For indexed tri-fans this is the number of amount of space fo indices needed in the builder
83 // before conversion to indexed triangles (or zero if not indexed or not a triangle fan).
84 size_t fBuilderTriFanISize;
Mike Reedaa9e3322017-03-16 14:38:48 -040085};
86
Mike Reed887cdf12017-04-03 11:11:09 -040087SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -040088 uint32_t builderFlags) {
89 bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
90 bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
91 this->init(mode, vertexCount, indexCount,
Brian Salomoncccafe82018-04-28 16:13:08 -040092 SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors));
Mike Reedbdce9c22017-03-14 14:10:54 -040093}
Mike Reed97eb4fe2017-03-14 12:04:16 -040094
Mike Reed887cdf12017-04-03 11:11:09 -040095SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -040096 const SkVertices::Sizes& sizes) {
97 this->init(mode, vertexCount, indexCount, sizes);
Mike Reed0c492cf2017-03-16 16:44:25 +000098}
99
Mike Reed887cdf12017-04-03 11:11:09 -0400100void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -0400101 const SkVertices::Sizes& sizes) {
102 if (!sizes.isValid()) {
103 return; // fVertices will already be null
104 }
105
106 void* storage = ::operator new (sizes.fTotal);
Brian Salomoncccafe82018-04-28 16:13:08 -0400107 if (sizes.fBuilderTriFanISize) {
108 fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]);
109 }
110
Mike Reedaa9e3322017-03-16 14:38:48 -0400111 fVertices.reset(new (storage) SkVertices);
112
113 // need to point past the object to store the arrays
114 char* ptr = (char*)storage + sizeof(SkVertices);
115
116 fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize;
117 fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize;
118 fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize;
119 fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr;
120 fVertices->fVertexCnt = vertexCount;
121 fVertices->fIndexCnt = indexCount;
122 fVertices->fMode = mode;
123 // We defer assigning fBounds and fUniqueID until detach() is called
Mike Reed97eb4fe2017-03-14 12:04:16 -0400124}
125
126sk_sp<SkVertices> SkVertices::Builder::detach() {
Mike Reedaa9e3322017-03-16 14:38:48 -0400127 if (fVertices) {
128 fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt);
Brian Salomoncccafe82018-04-28 16:13:08 -0400129 if (fVertices->fMode == kTriangleFan_VertexMode) {
130 if (fIntermediateFanIndices.get()) {
131 SkASSERT(fVertices->fIndexCnt);
132 auto tempIndices = this->indices();
133 for (int t = 0; t < fVertices->fIndexCnt - 2; ++t) {
134 fVertices->fIndices[3 * t + 0] = tempIndices[0];
135 fVertices->fIndices[3 * t + 1] = tempIndices[t + 1];
136 fVertices->fIndices[3 * t + 2] = tempIndices[t + 2];
137 }
138 fVertices->fIndexCnt = 3 * (fVertices->fIndexCnt - 2);
139 } else {
140 SkASSERT(!fVertices->fIndexCnt);
141 for (int t = 0; t < fVertices->fVertexCnt - 2; ++t) {
142 fVertices->fIndices[3 * t + 0] = 0;
143 fVertices->fIndices[3 * t + 1] = SkToU16(t + 1);
144 fVertices->fIndices[3 * t + 2] = SkToU16(t + 2);
145 }
146 fVertices->fIndexCnt = 3 * (fVertices->fVertexCnt - 2);
147 }
148 fVertices->fMode = kTriangles_VertexMode;
149 }
Mike Reedaa9e3322017-03-16 14:38:48 -0400150 fVertices->fUniqueID = next_id();
151 return std::move(fVertices); // this will null fVertices after the return
Mike Reed97eb4fe2017-03-14 12:04:16 -0400152 }
Mike Reedaa9e3322017-03-16 14:38:48 -0400153 return nullptr;
Mike Reed7d9f9e32017-03-15 18:35:07 +0000154}
155
Mike Reedaa9e3322017-03-16 14:38:48 -0400156int SkVertices::Builder::vertexCount() const {
157 return fVertices ? fVertices->vertexCount() : 0;
158}
159
160int SkVertices::Builder::indexCount() const {
161 return fVertices ? fVertices->indexCount() : 0;
162}
163
164SkPoint* SkVertices::Builder::positions() {
165 return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
166}
167
168SkPoint* SkVertices::Builder::texCoords() {
169 return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
170}
171
172SkColor* SkVertices::Builder::colors() {
173 return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
174}
175
176uint16_t* SkVertices::Builder::indices() {
Brian Salomoncccafe82018-04-28 16:13:08 -0400177 if (!fVertices) {
178 return nullptr;
179 }
180 if (fIntermediateFanIndices) {
181 return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get());
182 }
183 return const_cast<uint16_t*>(fVertices->indices());
Mike Reedaa9e3322017-03-16 14:38:48 -0400184}
185
186///////////////////////////////////////////////////////////////////////////////////////////////////
187
Mike Reed887cdf12017-04-03 11:11:09 -0400188sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
Mike Reed97eb4fe2017-03-14 12:04:16 -0400189 const SkPoint pos[], const SkPoint texs[],
190 const SkColor colors[], int indexCount,
191 const uint16_t indices[]) {
Brian Salomoncccafe82018-04-28 16:13:08 -0400192 Sizes sizes(mode, vertexCount, indexCount, texs != nullptr, colors != nullptr);
Mike Reedaa9e3322017-03-16 14:38:48 -0400193 if (!sizes.isValid()) {
Mike Reed97eb4fe2017-03-14 12:04:16 -0400194 return nullptr;
195 }
196
Mike Reedaa9e3322017-03-16 14:38:48 -0400197 Builder builder(mode, vertexCount, indexCount, sizes);
198 SkASSERT(builder.isValid());
199
200 sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
201 sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
202 sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
Brian Salomoncccafe82018-04-28 16:13:08 -0400203 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
204 sk_careful_memcpy(builder.indices(), indices, isize);
Mike Reedaa9e3322017-03-16 14:38:48 -0400205
Mike Reed97eb4fe2017-03-14 12:04:16 -0400206 return builder.detach();
207}
Mike Reedbdce9c22017-03-14 14:10:54 -0400208
Mike Reedaa9e3322017-03-16 14:38:48 -0400209size_t SkVertices::approximateSize() const {
Brian Salomoncccafe82018-04-28 16:13:08 -0400210 Sizes sizes(fMode, fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
Mike Reedaa9e3322017-03-16 14:38:48 -0400211 SkASSERT(sizes.isValid());
212 return sizeof(SkVertices) + sizes.fArrays;
213}
214
Mike Reedbdce9c22017-03-14 14:10:54 -0400215///////////////////////////////////////////////////////////////////////////////////////////////////
216
Mike Reedaa9e3322017-03-16 14:38:48 -0400217// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
218// = header + arrays
Mike Reedbdce9c22017-03-14 14:10:54 -0400219
220#define kMode_Mask 0x0FF
221#define kHasTexs_Mask 0x100
222#define kHasColors_Mask 0x200
Mike Reedaa9e3322017-03-16 14:38:48 -0400223#define kHeaderSize (3 * sizeof(uint32_t))
Mike Reedbdce9c22017-03-14 14:10:54 -0400224
225sk_sp<SkData> SkVertices::encode() const {
Mike Reedaa9e3322017-03-16 14:38:48 -0400226 // packed has room for addtional flags in the future (e.g. versioning)
227 uint32_t packed = static_cast<uint32_t>(fMode);
228 SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits
229 if (this->hasTexCoords()) {
230 packed |= kHasTexs_Mask;
Mike Reedbdce9c22017-03-14 14:10:54 -0400231 }
Mike Reedaa9e3322017-03-16 14:38:48 -0400232 if (this->hasColors()) {
233 packed |= kHasColors_Mask;
Mike Reedbdce9c22017-03-14 14:10:54 -0400234 }
235
Brian Salomoncccafe82018-04-28 16:13:08 -0400236 Sizes sizes(fMode, fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
Mike Reedaa9e3322017-03-16 14:38:48 -0400237 SkASSERT(sizes.isValid());
Brian Salomoncccafe82018-04-28 16:13:08 -0400238 SkASSERT(!sizes.fBuilderTriFanISize);
Mike Reed6ff6af92017-04-05 17:05:16 -0400239 // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
240 const size_t size = SkAlign4(kHeaderSize + sizes.fArrays);
Mike Reedbdce9c22017-03-14 14:10:54 -0400241
242 sk_sp<SkData> data = SkData::MakeUninitialized(size);
243 SkWriter32 writer(data->writable_data(), data->size());
244
Mike Reedaa9e3322017-03-16 14:38:48 -0400245 writer.write32(packed);
Mike Reedbdce9c22017-03-14 14:10:54 -0400246 writer.write32(fVertexCnt);
247 writer.write32(fIndexCnt);
Mike Reedaa9e3322017-03-16 14:38:48 -0400248 writer.write(fPositions, sizes.fVSize);
249 writer.write(fTexs, sizes.fTSize);
250 writer.write(fColors, sizes.fCSize);
Mike Reed6ff6af92017-04-05 17:05:16 -0400251 // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
252 writer.writePad(fIndices, sizes.fISize);
Mike Reedbdce9c22017-03-14 14:10:54 -0400253
254 return data;
255}
256
257sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
Mike Reedaa9e3322017-03-16 14:38:48 -0400258 if (length < kHeaderSize) {
259 return nullptr;
Mike Reedbdce9c22017-03-14 14:10:54 -0400260 }
261
262 SkReader32 reader(data, length);
Mike Reed165fa632018-01-23 11:50:25 -0500263 SkSafeRange safe;
Mike Reedbdce9c22017-03-14 14:10:54 -0400264
Mike Reedaa9e3322017-03-16 14:38:48 -0400265 const uint32_t packed = reader.readInt();
Mike Reedd2bc6202018-02-01 10:48:59 -0500266 const int vertexCount = safe.checkGE(reader.readInt(), 0);
267 const int indexCount = safe.checkGE(reader.readInt(), 0);
Mike Reed165fa632018-01-23 11:50:25 -0500268 const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask,
269 SkVertices::kLast_VertexMode);
Mike Reedd2bc6202018-02-01 10:48:59 -0500270 if (!safe) {
271 return nullptr;
272 }
Mike Reedaa9e3322017-03-16 14:38:48 -0400273 const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
274 const bool hasColors = SkToBool(packed & kHasColors_Mask);
Brian Salomoncccafe82018-04-28 16:13:08 -0400275 Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors);
Mike Reedd2bc6202018-02-01 10:48:59 -0500276 if (!sizes.isValid()) {
Mike Reedaa9e3322017-03-16 14:38:48 -0400277 return nullptr;
278 }
Mike Reed6ff6af92017-04-05 17:05:16 -0400279 // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
280 if (SkAlign4(kHeaderSize + sizes.fArrays) != length) {
Mike Reedbdce9c22017-03-14 14:10:54 -0400281 return nullptr;
282 }
283
Mike Reedaa9e3322017-03-16 14:38:48 -0400284 Builder builder(mode, vertexCount, indexCount, sizes);
Mike Reedbdce9c22017-03-14 14:10:54 -0400285
Mike Reedaa9e3322017-03-16 14:38:48 -0400286 reader.read(builder.positions(), sizes.fVSize);
287 reader.read(builder.texCoords(), sizes.fTSize);
288 reader.read(builder.colors(), sizes.fCSize);
Brian Salomoncccafe82018-04-28 16:13:08 -0400289 size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
290 reader.read(builder.indices(), isize);
Mike Reedd2bc6202018-02-01 10:48:59 -0500291 if (indexCount > 0) {
292 // validate that the indicies are in range
293 SkASSERT(indexCount == builder.indexCount());
294 const uint16_t* indices = builder.indices();
295 for (int i = 0; i < indexCount; ++i) {
296 if (indices[i] >= (unsigned)vertexCount) {
297 return nullptr;
298 }
299 }
300 }
Mike Reedbdce9c22017-03-14 14:10:54 -0400301 return builder.detach();
302}
Yong-Hwan Baek701a3ca2018-04-20 21:44:43 +0900303
304void SkVertices::operator delete(void* p)
305{
306 ::operator delete(p);
307}