blob: 936d70dc099941da1ee6f659ceae29ade74111e0 [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 Reed0c492cf2017-03-16 16:44:25 +000023static size_t compute_arrays_size(int vertexCount, int indexCount, uint32_t builderFlags) {
24 if (vertexCount < 0 || indexCount < 0) {
25 return 0; // signal error
Mike Reedbdce9c22017-03-14 14:10:54 -040026 }
27
Mike Reed0c492cf2017-03-16 16:44:25 +000028 uint64_t size = vertexCount * sizeof(SkPoint);
29 if (builderFlags & SkVertices::kHasTexs_Flag) {
30 size += vertexCount * sizeof(SkPoint);
31 }
32 if (builderFlags & SkVertices::kHasColors_Flag) {
33 size += vertexCount * sizeof(SkColor);
34 }
35 size += indexCount * sizeof(uint16_t);
36 if (!sk_64_isS32(size)) {
37 return 0; // signal error
38 }
39 return (size_t)size;
Mike Reedbdce9c22017-03-14 14:10:54 -040040}
Mike Reed97eb4fe2017-03-14 12:04:16 -040041
42SkVertices::Builder::Builder(SkCanvas::VertexMode mode, int vertexCount, int indexCount,
Mike Reed0c492cf2017-03-16 16:44:25 +000043 uint32_t flags) {
44 fPositions = nullptr; // signal that we have nothing to cleanup
45 fColors = nullptr;
46 fTexs = nullptr;
47 fIndices = nullptr;
48 fVertexCnt = 0;
49 fIndexCnt = 0;
Mike Reed9e62df62017-03-15 17:32:39 +000050
Mike Reed0c492cf2017-03-16 16:44:25 +000051 size_t size = compute_arrays_size(vertexCount, indexCount, flags);
52 if (0 == size) {
53 return;
Mike Reed7d9f9e32017-03-15 18:35:07 +000054 }
55
Mike Reed0c492cf2017-03-16 16:44:25 +000056 char* ptr = (char*)sk_malloc_throw(sk_64_asS32(size));
Mike Reed7d9f9e32017-03-15 18:35:07 +000057
Mike Reed0c492cf2017-03-16 16:44:25 +000058 fMode = mode;
59 fVertexCnt = vertexCount;
60 fIndexCnt = indexCount;
61 fPositions = (SkPoint*)ptr; // owner
62 ptr += vertexCount * sizeof(SkPoint);
Mike Reed7d9f9e32017-03-15 18:35:07 +000063
Mike Reed0c492cf2017-03-16 16:44:25 +000064 if (flags & kHasTexs_Flag) {
65 fTexs = (SkPoint*)ptr;
66 ptr += vertexCount * sizeof(SkPoint);
67 }
68 if (flags & kHasColors_Flag) {
69 fColors = (SkColor*)ptr;
70 ptr += vertexCount * sizeof(SkColor);
71 }
72 if (indexCount) {
73 fIndices = (uint16_t*)ptr;
74 }
75}
76
77SkVertices::Builder::~Builder() {
78 sk_free(fPositions);
Mike Reed97eb4fe2017-03-14 12:04:16 -040079}
80
81sk_sp<SkVertices> SkVertices::Builder::detach() {
Mike Reed0c492cf2017-03-16 16:44:25 +000082 if (!fPositions) {
83 return nullptr;
Mike Reed97eb4fe2017-03-14 12:04:16 -040084 }
Mike Reedeaaebb12017-03-15 12:19:07 -040085
Mike Reed0c492cf2017-03-16 16:44:25 +000086 SkVertices* obj = new SkVertices;
87 obj->fPositions = fPositions; // owner of storage, use sk_free
88 obj->fTexs = fTexs;
89 obj->fColors = fColors;
90 obj->fIndices = fIndices;
91 obj->fBounds.set(fPositions, fVertexCnt);
92 obj->fUniqueID = next_id();
93 obj->fVertexCnt = fVertexCnt;
94 obj->fIndexCnt = fIndexCnt;
95 obj->fMode = fMode;
Mike Reed7d9f9e32017-03-15 18:35:07 +000096
Mike Reed0c492cf2017-03-16 16:44:25 +000097 fPositions = nullptr; // so we don't free the memory, now that obj owns it
Mike Reed7d9f9e32017-03-15 18:35:07 +000098
Mike Reed0c492cf2017-03-16 16:44:25 +000099 return sk_sp<SkVertices>(obj);
Mike Reed7d9f9e32017-03-15 18:35:07 +0000100}
101
Mike Reed97eb4fe2017-03-14 12:04:16 -0400102sk_sp<SkVertices> SkVertices::MakeCopy(SkCanvas::VertexMode mode, int vertexCount,
103 const SkPoint pos[], const SkPoint texs[],
104 const SkColor colors[], int indexCount,
105 const uint16_t indices[]) {
Mike Reed0c492cf2017-03-16 16:44:25 +0000106 uint32_t flags = 0;
107 if (texs) {
108 flags |= kHasTexs_Flag;
109 }
110 if (colors) {
111 flags |= kHasColors_Flag;
112 }
113 Builder builder(mode, vertexCount, indexCount, flags);
114 if (!builder.isValid()) {
Mike Reed97eb4fe2017-03-14 12:04:16 -0400115 return nullptr;
116 }
117
Mike Reed0c492cf2017-03-16 16:44:25 +0000118 memcpy(builder.positions(), pos, vertexCount * sizeof(SkPoint));
119 if (texs) {
120 memcpy(builder.texCoords(), texs, vertexCount * sizeof(SkPoint));
121 }
122 if (colors) {
123 memcpy(builder.colors(), colors, vertexCount * sizeof(SkColor));
124 }
125 if (indices) {
126 memcpy(builder.indices(), indices, indexCount * sizeof(uint16_t));
127 }
Mike Reed97eb4fe2017-03-14 12:04:16 -0400128 return builder.detach();
129}
Mike Reedbdce9c22017-03-14 14:10:54 -0400130
131///////////////////////////////////////////////////////////////////////////////////////////////////
132
Mike Reed0c492cf2017-03-16 16:44:25 +0000133// storage = flags | vertex_count | index_count | pos[] | texs[] | colors[] | indices[]
Mike Reedbdce9c22017-03-14 14:10:54 -0400134
135#define kMode_Mask 0x0FF
136#define kHasTexs_Mask 0x100
137#define kHasColors_Mask 0x200
138
139sk_sp<SkData> SkVertices::encode() const {
Mike Reed0c492cf2017-03-16 16:44:25 +0000140 uint32_t flags = static_cast<uint32_t>(fMode);
141 SkASSERT((flags & ~kMode_Mask) == 0);
142 if (fTexs) {
143 flags |= kHasTexs_Mask;
Mike Reedbdce9c22017-03-14 14:10:54 -0400144 }
Mike Reed0c492cf2017-03-16 16:44:25 +0000145 if (fColors) {
146 flags |= kHasColors_Mask;
Mike Reedbdce9c22017-03-14 14:10:54 -0400147 }
148
Mike Reed0c492cf2017-03-16 16:44:25 +0000149 size_t size = sizeof(uint32_t) * 3; // flags | verts_count | indices_count
150 size += fVertexCnt * sizeof(SkPoint);
151 if (fTexs) {
152 size += fVertexCnt * sizeof(SkPoint);
153 }
154 if (fColors) {
155 size += fVertexCnt * sizeof(SkColor);
156 }
157 size += fIndexCnt * sizeof(uint16_t);
Mike Reedbdce9c22017-03-14 14:10:54 -0400158
159 sk_sp<SkData> data = SkData::MakeUninitialized(size);
160 SkWriter32 writer(data->writable_data(), data->size());
161
Mike Reed0c492cf2017-03-16 16:44:25 +0000162 writer.write32(flags);
Mike Reedbdce9c22017-03-14 14:10:54 -0400163 writer.write32(fVertexCnt);
164 writer.write32(fIndexCnt);
Mike Reed0c492cf2017-03-16 16:44:25 +0000165 writer.write(fPositions, fVertexCnt * sizeof(SkPoint));
166 if (fTexs) {
167 writer.write(fTexs, fVertexCnt * sizeof(SkPoint));
168 }
169 if (fColors) {
170 writer.write(fColors, fVertexCnt * sizeof(SkColor));
171 }
172 writer.write(fIndices, fIndexCnt * sizeof(uint16_t));
Mike Reedbdce9c22017-03-14 14:10:54 -0400173
174 return data;
175}
176
177sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
Mike Reed0c492cf2017-03-16 16:44:25 +0000178 if (length < 3 * sizeof(uint32_t)) {
179 return nullptr; // buffer too small
Mike Reedbdce9c22017-03-14 14:10:54 -0400180 }
181
182 SkReader32 reader(data, length);
183
Mike Reed0c492cf2017-03-16 16:44:25 +0000184 uint32_t storageFlags = reader.readInt();
185 SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(storageFlags & kMode_Mask);
186 int vertexCount = reader.readInt();
187 int indexCount = reader.readInt();
188 uint32_t builderFlags = 0;
189 if (storageFlags & kHasTexs_Mask) {
190 builderFlags |= SkVertices::kHasTexs_Flag;
Mike Reed7d9f9e32017-03-15 18:35:07 +0000191 }
Mike Reed0c492cf2017-03-16 16:44:25 +0000192 if (storageFlags & kHasColors_Mask) {
193 builderFlags |= SkVertices::kHasColors_Flag;
194 }
195
196 size_t size = compute_arrays_size(vertexCount, indexCount, builderFlags);
197 if (0 == size) {
Mike Reedbdce9c22017-03-14 14:10:54 -0400198 return nullptr;
199 }
200
Mike Reed0c492cf2017-03-16 16:44:25 +0000201 length -= 3 * sizeof(uint32_t); // already read the header
202 if (length < size) { // buffer too small
203 return nullptr;
204 }
Mike Reedbdce9c22017-03-14 14:10:54 -0400205
Mike Reed0c492cf2017-03-16 16:44:25 +0000206 Builder builder(mode, vertexCount, indexCount, builderFlags);
207 if (!builder.isValid()) {
208 return nullptr;
209 }
210
211 reader.read(builder.positions(), vertexCount * sizeof(SkPoint));
212 if (builderFlags & SkVertices::kHasTexs_Flag) {
213 reader.read(builder.texCoords(), vertexCount * sizeof(SkPoint));
214 }
215 if (builderFlags & SkVertices::kHasColors_Flag) {
216 reader.read(builder.colors(), vertexCount * sizeof(SkColor));
217 }
218 reader.read(builder.indices(), indexCount * sizeof(uint16_t));
Mike Reedbdce9c22017-03-14 14:10:54 -0400219
220 return builder.detach();
221}