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 "SkAtomics.h"
9 #include "SkVertices.h"
10 #include "SkData.h"
11 #include "SkReader32.h"
12 #include "SkWriter32.h"
13
14 static int32_t gNextID = 1;
next_id()15 static int32_t next_id() {
16 int32_t id;
17 do {
18 id = sk_atomic_inc(&gNextID);
19 } while (id == SK_InvalidGenID);
20 return id;
21 }
22
23 struct SkVertices::Sizes {
SizesSkVertices::Sizes24 Sizes(int vertexCount, int indexCount, bool hasTexs, bool hasColors) {
25 int64_t vSize = (int64_t)vertexCount * sizeof(SkPoint);
26 int64_t tSize = hasTexs ? (int64_t)vertexCount * sizeof(SkPoint) : 0;
27 int64_t cSize = hasColors ? (int64_t)vertexCount * sizeof(SkColor) : 0;
28 int64_t iSize = (int64_t)indexCount * sizeof(uint16_t);
29
30 int64_t total = sizeof(SkVertices) + vSize + tSize + cSize + iSize;
31 if (!sk_64_isS32(total)) {
32 sk_bzero(this, sizeof(*this));
33 } else {
34 fTotal = SkToSizeT(total);
35 fVSize = SkToSizeT(vSize);
36 fTSize = SkToSizeT(tSize);
37 fCSize = SkToSizeT(cSize);
38 fISize = SkToSizeT(iSize);
39 fArrays = fTotal - sizeof(SkVertices); // just the sum of the arrays
40 }
41 }
42
isValidSkVertices::Sizes43 bool isValid() const { return fTotal != 0; }
44
45 size_t fTotal; // size of entire SkVertices allocation (obj + arrays)
46 size_t fArrays; // size of all the arrays (V + T + C + I)
47 size_t fVSize;
48 size_t fTSize;
49 size_t fCSize;
50 size_t fISize;
51 };
52
Builder(VertexMode mode,int vertexCount,int indexCount,uint32_t builderFlags)53 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
54 uint32_t builderFlags) {
55 bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
56 bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
57 this->init(mode, vertexCount, indexCount,
58 SkVertices::Sizes(vertexCount, indexCount, hasTexs, hasColors));
59 }
60
Builder(VertexMode mode,int vertexCount,int indexCount,const SkVertices::Sizes & sizes)61 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
62 const SkVertices::Sizes& sizes) {
63 this->init(mode, vertexCount, indexCount, sizes);
64 }
65
init(VertexMode mode,int vertexCount,int indexCount,const SkVertices::Sizes & sizes)66 void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount,
67 const SkVertices::Sizes& sizes) {
68 if (!sizes.isValid()) {
69 return; // fVertices will already be null
70 }
71
72 void* storage = ::operator new (sizes.fTotal);
73 fVertices.reset(new (storage) SkVertices);
74
75 // need to point past the object to store the arrays
76 char* ptr = (char*)storage + sizeof(SkVertices);
77
78 fVertices->fPositions = (SkPoint*)ptr; ptr += sizes.fVSize;
79 fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr; ptr += sizes.fTSize;
80 fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr; ptr += sizes.fCSize;
81 fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr;
82 fVertices->fVertexCnt = vertexCount;
83 fVertices->fIndexCnt = indexCount;
84 fVertices->fMode = mode;
85 // We defer assigning fBounds and fUniqueID until detach() is called
86 }
87
detach()88 sk_sp<SkVertices> SkVertices::Builder::detach() {
89 if (fVertices) {
90 fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt);
91 fVertices->fUniqueID = next_id();
92 return std::move(fVertices); // this will null fVertices after the return
93 }
94 return nullptr;
95 }
96
vertexCount() const97 int SkVertices::Builder::vertexCount() const {
98 return fVertices ? fVertices->vertexCount() : 0;
99 }
100
indexCount() const101 int SkVertices::Builder::indexCount() const {
102 return fVertices ? fVertices->indexCount() : 0;
103 }
104
positions()105 SkPoint* SkVertices::Builder::positions() {
106 return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
107 }
108
texCoords()109 SkPoint* SkVertices::Builder::texCoords() {
110 return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
111 }
112
colors()113 SkColor* SkVertices::Builder::colors() {
114 return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
115 }
116
indices()117 uint16_t* SkVertices::Builder::indices() {
118 return fVertices ? const_cast<uint16_t*>(fVertices->indices()) : nullptr;
119 }
120
121 ///////////////////////////////////////////////////////////////////////////////////////////////////
122
MakeCopy(VertexMode mode,int vertexCount,const SkPoint pos[],const SkPoint texs[],const SkColor colors[],int indexCount,const uint16_t indices[])123 sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
124 const SkPoint pos[], const SkPoint texs[],
125 const SkColor colors[], int indexCount,
126 const uint16_t indices[]) {
127 Sizes sizes(vertexCount, indexCount, texs != nullptr, colors != nullptr);
128 if (!sizes.isValid()) {
129 return nullptr;
130 }
131
132 Builder builder(mode, vertexCount, indexCount, sizes);
133 SkASSERT(builder.isValid());
134
135 sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
136 sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
137 sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
138 sk_careful_memcpy(builder.indices(), indices, sizes.fISize);
139
140 return builder.detach();
141 }
142
approximateSize() const143 size_t SkVertices::approximateSize() const {
144 Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
145 SkASSERT(sizes.isValid());
146 return sizeof(SkVertices) + sizes.fArrays;
147 }
148
149 ///////////////////////////////////////////////////////////////////////////////////////////////////
150
151 // storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
152 // = header + arrays
153
154 #define kMode_Mask 0x0FF
155 #define kHasTexs_Mask 0x100
156 #define kHasColors_Mask 0x200
157 #define kHeaderSize (3 * sizeof(uint32_t))
158
encode() const159 sk_sp<SkData> SkVertices::encode() const {
160 // packed has room for addtional flags in the future (e.g. versioning)
161 uint32_t packed = static_cast<uint32_t>(fMode);
162 SkASSERT((packed & ~kMode_Mask) == 0); // our mode fits in the mask bits
163 if (this->hasTexCoords()) {
164 packed |= kHasTexs_Mask;
165 }
166 if (this->hasColors()) {
167 packed |= kHasColors_Mask;
168 }
169
170 Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
171 SkASSERT(sizes.isValid());
172 // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
173 const size_t size = SkAlign4(kHeaderSize + sizes.fArrays);
174
175 sk_sp<SkData> data = SkData::MakeUninitialized(size);
176 SkWriter32 writer(data->writable_data(), data->size());
177
178 writer.write32(packed);
179 writer.write32(fVertexCnt);
180 writer.write32(fIndexCnt);
181 writer.write(fPositions, sizes.fVSize);
182 writer.write(fTexs, sizes.fTSize);
183 writer.write(fColors, sizes.fCSize);
184 // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
185 writer.writePad(fIndices, sizes.fISize);
186
187 return data;
188 }
189
Decode(const void * data,size_t length)190 sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
191 if (length < kHeaderSize) {
192 return nullptr;
193 }
194
195 SkReader32 reader(data, length);
196
197 const uint32_t packed = reader.readInt();
198 const int vertexCount = reader.readInt();
199 const int indexCount = reader.readInt();
200
201 const VertexMode mode = static_cast<VertexMode>(packed & kMode_Mask);
202 const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
203 const bool hasColors = SkToBool(packed & kHasColors_Mask);
204 Sizes sizes(vertexCount, indexCount, hasTexs, hasColors);
205 if (!sizes.isValid()) {
206 return nullptr;
207 }
208 // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
209 if (SkAlign4(kHeaderSize + sizes.fArrays) != length) {
210 return nullptr;
211 }
212
213 Builder builder(mode, vertexCount, indexCount, sizes);
214
215 reader.read(builder.positions(), sizes.fVSize);
216 reader.read(builder.texCoords(), sizes.fTSize);
217 reader.read(builder.colors(), sizes.fCSize);
218 reader.read(builder.indices(), sizes.fISize);
219
220 return builder.detach();
221 }
222