blob: 8dadad056bd231366921d140861cff49966a3cf7 [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
Mike Reed9a8065d2017-03-14 21:05:17 -04008#include "SkAtomics.h"
Mike Reed97eb4fe2017-03-14 12:04:16 -04009#include "SkVertices.h"
Mike Reedbdce9c22017-03-14 14:10:54 -040010#include "SkData.h"
11#include "SkReader32.h"
12#include "SkWriter32.h"
13
Mike Reed9a8065d2017-03-14 21:05:17 -040014static int32_t gNextID = 1;
15static 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
Mike Reedaa9e3322017-03-16 14:38:48 -040023struct SkVertices::Sizes {
24 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 }
Mike Reedbdce9c22017-03-14 14:10:54 -040041 }
42
Mike Reedaa9e3322017-03-16 14:38:48 -040043 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
Mike Reed887cdf12017-04-03 11:11:09 -040053SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -040054 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));
Mike Reedbdce9c22017-03-14 14:10:54 -040059}
Mike Reed97eb4fe2017-03-14 12:04:16 -040060
Mike Reed887cdf12017-04-03 11:11:09 -040061SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -040062 const SkVertices::Sizes& sizes) {
63 this->init(mode, vertexCount, indexCount, sizes);
Mike Reed0c492cf2017-03-16 16:44:25 +000064}
65
Mike Reed887cdf12017-04-03 11:11:09 -040066void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount,
Mike Reedaa9e3322017-03-16 14:38:48 -040067 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
Mike Reed97eb4fe2017-03-14 12:04:16 -040086}
87
88sk_sp<SkVertices> SkVertices::Builder::detach() {
Mike Reedaa9e3322017-03-16 14:38:48 -040089 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
Mike Reed97eb4fe2017-03-14 12:04:16 -040093 }
Mike Reedaa9e3322017-03-16 14:38:48 -040094 return nullptr;
Mike Reed7d9f9e32017-03-15 18:35:07 +000095}
96
Mike Reedaa9e3322017-03-16 14:38:48 -040097int SkVertices::Builder::vertexCount() const {
98 return fVertices ? fVertices->vertexCount() : 0;
99}
100
101int SkVertices::Builder::indexCount() const {
102 return fVertices ? fVertices->indexCount() : 0;
103}
104
105SkPoint* SkVertices::Builder::positions() {
106 return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
107}
108
109SkPoint* SkVertices::Builder::texCoords() {
110 return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
111}
112
113SkColor* SkVertices::Builder::colors() {
114 return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
115}
116
117uint16_t* SkVertices::Builder::indices() {
118 return fVertices ? const_cast<uint16_t*>(fVertices->indices()) : nullptr;
119}
120
121///////////////////////////////////////////////////////////////////////////////////////////////////
122
Mike Reed887cdf12017-04-03 11:11:09 -0400123sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
Mike Reed97eb4fe2017-03-14 12:04:16 -0400124 const SkPoint pos[], const SkPoint texs[],
125 const SkColor colors[], int indexCount,
126 const uint16_t indices[]) {
Mike Reedaa9e3322017-03-16 14:38:48 -0400127 Sizes sizes(vertexCount, indexCount, texs != nullptr, colors != nullptr);
128 if (!sizes.isValid()) {
Mike Reed97eb4fe2017-03-14 12:04:16 -0400129 return nullptr;
130 }
131
Mike Reedaa9e3322017-03-16 14:38:48 -0400132 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
Mike Reed97eb4fe2017-03-14 12:04:16 -0400140 return builder.detach();
141}
Mike Reedbdce9c22017-03-14 14:10:54 -0400142
Mike Reedaa9e3322017-03-16 14:38:48 -0400143size_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
Mike Reedbdce9c22017-03-14 14:10:54 -0400149///////////////////////////////////////////////////////////////////////////////////////////////////
150
Mike Reedaa9e3322017-03-16 14:38:48 -0400151// storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
152// = header + arrays
Mike Reedbdce9c22017-03-14 14:10:54 -0400153
154#define kMode_Mask 0x0FF
155#define kHasTexs_Mask 0x100
156#define kHasColors_Mask 0x200
Mike Reedaa9e3322017-03-16 14:38:48 -0400157#define kHeaderSize (3 * sizeof(uint32_t))
Mike Reedbdce9c22017-03-14 14:10:54 -0400158
159sk_sp<SkData> SkVertices::encode() const {
Mike Reedaa9e3322017-03-16 14:38:48 -0400160 // 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;
Mike Reedbdce9c22017-03-14 14:10:54 -0400165 }
Mike Reedaa9e3322017-03-16 14:38:48 -0400166 if (this->hasColors()) {
167 packed |= kHasColors_Mask;
Mike Reedbdce9c22017-03-14 14:10:54 -0400168 }
169
Mike Reedaa9e3322017-03-16 14:38:48 -0400170 Sizes sizes(fVertexCnt, fIndexCnt, this->hasTexCoords(), this->hasColors());
171 SkASSERT(sizes.isValid());
Mike Reed6ff6af92017-04-05 17:05:16 -0400172 // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
173 const size_t size = SkAlign4(kHeaderSize + sizes.fArrays);
Mike Reedbdce9c22017-03-14 14:10:54 -0400174
175 sk_sp<SkData> data = SkData::MakeUninitialized(size);
176 SkWriter32 writer(data->writable_data(), data->size());
177
Mike Reedaa9e3322017-03-16 14:38:48 -0400178 writer.write32(packed);
Mike Reedbdce9c22017-03-14 14:10:54 -0400179 writer.write32(fVertexCnt);
180 writer.write32(fIndexCnt);
Mike Reedaa9e3322017-03-16 14:38:48 -0400181 writer.write(fPositions, sizes.fVSize);
182 writer.write(fTexs, sizes.fTSize);
183 writer.write(fColors, sizes.fCSize);
Mike Reed6ff6af92017-04-05 17:05:16 -0400184 // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
185 writer.writePad(fIndices, sizes.fISize);
Mike Reedbdce9c22017-03-14 14:10:54 -0400186
187 return data;
188}
189
190sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
Mike Reedaa9e3322017-03-16 14:38:48 -0400191 if (length < kHeaderSize) {
192 return nullptr;
Mike Reedbdce9c22017-03-14 14:10:54 -0400193 }
194
195 SkReader32 reader(data, length);
196
Mike Reedaa9e3322017-03-16 14:38:48 -0400197 const uint32_t packed = reader.readInt();
198 const int vertexCount = reader.readInt();
199 const int indexCount = reader.readInt();
Mike Reed0c492cf2017-03-16 16:44:25 +0000200
Mike Reed887cdf12017-04-03 11:11:09 -0400201 const VertexMode mode = static_cast<VertexMode>(packed & kMode_Mask);
Mike Reedaa9e3322017-03-16 14:38:48 -0400202 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 }
Mike Reed6ff6af92017-04-05 17:05:16 -0400208 // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
209 if (SkAlign4(kHeaderSize + sizes.fArrays) != length) {
Mike Reedbdce9c22017-03-14 14:10:54 -0400210 return nullptr;
211 }
212
Mike Reedaa9e3322017-03-16 14:38:48 -0400213 Builder builder(mode, vertexCount, indexCount, sizes);
Mike Reedbdce9c22017-03-14 14:10:54 -0400214
Mike Reedaa9e3322017-03-16 14:38:48 -0400215 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);
Mike Reedbdce9c22017-03-14 14:10:54 -0400219
220 return builder.detach();
221}