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