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