• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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