Home | History | Annotate | Download | only in core
      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 "SkVertices.h"
      9 
     10 #include "SkData.h"
     11 #include "SkReader32.h"
     12 #include "SkSafeMath.h"
     13 #include "SkSafeRange.h"
     14 #include "SkTo.h"
     15 #include "SkWriter32.h"
     16 #include <atomic>
     17 #include <new>
     18 
     19 static int32_t next_id() {
     20     static std::atomic<int32_t> nextID{1};
     21 
     22     int32_t id;
     23     do {
     24         id = nextID++;
     25     } while (id == SK_InvalidGenID);
     26     return id;
     27 }
     28 
     29 struct SkVertices::Sizes {
     30     Sizes(SkVertices::VertexMode mode, int vertexCount, int indexCount, bool hasTexs,
     31           bool hasColors, bool hasBones) {
     32         SkSafeMath safe;
     33 
     34         fVSize = safe.mul(vertexCount, sizeof(SkPoint));
     35         fTSize = hasTexs ? safe.mul(vertexCount, sizeof(SkPoint)) : 0;
     36         fCSize = hasColors ? safe.mul(vertexCount, sizeof(SkColor)) : 0;
     37         fBISize = hasBones ? safe.mul(vertexCount, sizeof(BoneIndices)) : 0;
     38         fBWSize = hasBones ? safe.mul(vertexCount, sizeof(BoneWeights)) : 0;
     39 
     40         fBuilderTriFanISize = 0;
     41         fISize = safe.mul(indexCount, sizeof(uint16_t));
     42         if (kTriangleFan_VertexMode == mode) {
     43             int numFanTris = 0;
     44             if (indexCount) {
     45                 fBuilderTriFanISize = fISize;
     46                 numFanTris = indexCount - 2;
     47             } else {
     48                 numFanTris = vertexCount - 2;
     49                 // By forcing this to become indexed we are adding a constraint to the maximum
     50                 // number of vertices.
     51                 if (vertexCount > (SkTo<int>(UINT16_MAX) + 1)) {
     52                     sk_bzero(this, sizeof(*this));
     53                     return;
     54                 }
     55             }
     56             if (numFanTris <= 0) {
     57                 sk_bzero(this, sizeof(*this));
     58                 return;
     59             }
     60             fISize = safe.mul(numFanTris, 3 * sizeof(uint16_t));
     61         }
     62 
     63         fTotal = safe.add(sizeof(SkVertices),
     64                  safe.add(fVSize,
     65                  safe.add(fTSize,
     66                  safe.add(fCSize,
     67                  safe.add(fBISize,
     68                  safe.add(fBWSize,
     69                           fISize))))));
     70 
     71         if (safe.ok()) {
     72             fArrays = fTotal - sizeof(SkVertices);  // just the sum of the arrays
     73         } else {
     74             sk_bzero(this, sizeof(*this));
     75         }
     76     }
     77 
     78     bool isValid() const { return fTotal != 0; }
     79 
     80     size_t fTotal;  // size of entire SkVertices allocation (obj + arrays)
     81     size_t fArrays; // size of all the arrays (V + T + C + BI + BW + I)
     82     size_t fVSize;
     83     size_t fTSize;
     84     size_t fCSize;
     85     size_t fBISize;
     86     size_t fBWSize;
     87     size_t fISize;
     88 
     89     // For indexed tri-fans this is the number of amount of space fo indices needed in the builder
     90     // before conversion to indexed triangles (or zero if not indexed or not a triangle fan).
     91     size_t fBuilderTriFanISize;
     92 };
     93 
     94 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount,
     95                              uint32_t builderFlags) {
     96     bool hasTexs = SkToBool(builderFlags & SkVertices::kHasTexCoords_BuilderFlag);
     97     bool hasColors = SkToBool(builderFlags & SkVertices::kHasColors_BuilderFlag);
     98     bool hasBones = SkToBool(builderFlags & SkVertices::kHasBones_BuilderFlag);
     99     bool isVolatile = !SkToBool(builderFlags & SkVertices::kIsNonVolatile_BuilderFlag);
    100     this->init(mode, vertexCount, indexCount, isVolatile,
    101                SkVertices::Sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones));
    102 }
    103 
    104 SkVertices::Builder::Builder(VertexMode mode, int vertexCount, int indexCount, bool isVolatile,
    105                              const SkVertices::Sizes& sizes) {
    106     this->init(mode, vertexCount, indexCount, isVolatile, sizes);
    107 }
    108 
    109 void SkVertices::Builder::init(VertexMode mode, int vertexCount, int indexCount, bool isVolatile,
    110                                const SkVertices::Sizes& sizes) {
    111     if (!sizes.isValid()) {
    112         return; // fVertices will already be null
    113     }
    114 
    115     void* storage = ::operator new (sizes.fTotal);
    116     if (sizes.fBuilderTriFanISize) {
    117         fIntermediateFanIndices.reset(new uint8_t[sizes.fBuilderTriFanISize]);
    118     }
    119 
    120     fVertices.reset(new (storage) SkVertices);
    121 
    122     // need to point past the object to store the arrays
    123     char* ptr = (char*)storage + sizeof(SkVertices);
    124 
    125     fVertices->fPositions = (SkPoint*)ptr;                                  ptr += sizes.fVSize;
    126     fVertices->fTexs = sizes.fTSize ? (SkPoint*)ptr : nullptr;              ptr += sizes.fTSize;
    127     fVertices->fColors = sizes.fCSize ? (SkColor*)ptr : nullptr;            ptr += sizes.fCSize;
    128     fVertices->fBoneIndices = sizes.fBISize ? (BoneIndices*) ptr : nullptr; ptr += sizes.fBISize;
    129     fVertices->fBoneWeights = sizes.fBWSize ? (BoneWeights*) ptr : nullptr; ptr += sizes.fBWSize;
    130     fVertices->fIndices = sizes.fISize ? (uint16_t*)ptr : nullptr;
    131     fVertices->fVertexCnt = vertexCount;
    132     fVertices->fIndexCnt = indexCount;
    133     fVertices->fIsVolatile = isVolatile;
    134     fVertices->fMode = mode;
    135 
    136     // We defer assigning fBounds and fUniqueID until detach() is called
    137 }
    138 
    139 sk_sp<SkVertices> SkVertices::Builder::detach() {
    140     if (fVertices) {
    141         fVertices->fBounds.set(fVertices->fPositions, fVertices->fVertexCnt);
    142         if (fVertices->fMode == kTriangleFan_VertexMode) {
    143             if (fIntermediateFanIndices.get()) {
    144                 SkASSERT(fVertices->fIndexCnt);
    145                 auto tempIndices = this->indices();
    146                 for (int t = 0; t < fVertices->fIndexCnt - 2; ++t) {
    147                     fVertices->fIndices[3 * t + 0] = tempIndices[0];
    148                     fVertices->fIndices[3 * t + 1] = tempIndices[t + 1];
    149                     fVertices->fIndices[3 * t + 2] = tempIndices[t + 2];
    150                 }
    151                 fVertices->fIndexCnt = 3 * (fVertices->fIndexCnt - 2);
    152             } else {
    153                 SkASSERT(!fVertices->fIndexCnt);
    154                 for (int t = 0; t < fVertices->fVertexCnt - 2; ++t) {
    155                     fVertices->fIndices[3 * t + 0] = 0;
    156                     fVertices->fIndices[3 * t + 1] = SkToU16(t + 1);
    157                     fVertices->fIndices[3 * t + 2] = SkToU16(t + 2);
    158                 }
    159                 fVertices->fIndexCnt = 3 * (fVertices->fVertexCnt - 2);
    160             }
    161             fVertices->fMode = kTriangles_VertexMode;
    162         }
    163         fVertices->fUniqueID = next_id();
    164         return std::move(fVertices);        // this will null fVertices after the return
    165     }
    166     return nullptr;
    167 }
    168 
    169 int SkVertices::Builder::vertexCount() const {
    170     return fVertices ? fVertices->vertexCount() : 0;
    171 }
    172 
    173 int SkVertices::Builder::indexCount() const {
    174     return fVertices ? fVertices->indexCount() : 0;
    175 }
    176 
    177 bool SkVertices::Builder::isVolatile() const {
    178     return fVertices ? fVertices->isVolatile() : true;
    179 }
    180 
    181 SkPoint* SkVertices::Builder::positions() {
    182     return fVertices ? const_cast<SkPoint*>(fVertices->positions()) : nullptr;
    183 }
    184 
    185 SkPoint* SkVertices::Builder::texCoords() {
    186     return fVertices ? const_cast<SkPoint*>(fVertices->texCoords()) : nullptr;
    187 }
    188 
    189 SkColor* SkVertices::Builder::colors() {
    190     return fVertices ? const_cast<SkColor*>(fVertices->colors()) : nullptr;
    191 }
    192 
    193 SkVertices::BoneIndices* SkVertices::Builder::boneIndices() {
    194     return fVertices ? const_cast<BoneIndices*>(fVertices->boneIndices()) : nullptr;
    195 }
    196 
    197 SkVertices::BoneWeights* SkVertices::Builder::boneWeights() {
    198     return fVertices ? const_cast<BoneWeights*>(fVertices->boneWeights()) : nullptr;
    199 }
    200 
    201 uint16_t* SkVertices::Builder::indices() {
    202     if (!fVertices) {
    203         return nullptr;
    204     }
    205     if (fIntermediateFanIndices) {
    206         return reinterpret_cast<uint16_t*>(fIntermediateFanIndices.get());
    207     }
    208     return const_cast<uint16_t*>(fVertices->indices());
    209 }
    210 
    211 /** Makes a copy of the SkVertices and applies a set of bones, then returns the deformed
    212     vertices.
    213 
    214     @param bones      The bones to apply.
    215     @param boneCount  The number of bones.
    216     @return           The transformed SkVertices.
    217 */
    218 sk_sp<SkVertices> SkVertices::applyBones(const SkVertices::Bone bones[], int boneCount) const {
    219     // If there aren't any bones, then nothing changes.
    220     // We don't check if the SkVertices object has bone indices/weights because there is the case
    221     // where the object can have no indices/weights but still have a world transform applied.
    222     if (!bones || !boneCount) {
    223         return sk_ref_sp(this);
    224     }
    225     SkASSERT(boneCount >= 1);
    226 
    227     // Copy the SkVertices.
    228     sk_sp<SkVertices> copy = SkVertices::MakeCopy(this->mode(),
    229                                                   this->vertexCount(),
    230                                                   this->positions(),
    231                                                   this->texCoords(),
    232                                                   this->colors(),
    233                                                   nullptr,
    234                                                   nullptr,
    235                                                   this->indexCount(),
    236                                                   this->indices());
    237 
    238     // Transform the positions.
    239     for (int i = 0; i < this->vertexCount(); i++) {
    240         SkPoint& position = copy->fPositions[i];
    241 
    242         // Apply the world transform.
    243         position = bones[0].mapPoint(position);
    244 
    245         // Apply the bone deformations.
    246         if (boneCount > 1) {
    247             SkASSERT(this->boneIndices());
    248             SkASSERT(this->boneWeights());
    249 
    250             SkPoint result = SkPoint::Make(0.0f, 0.0f);
    251             const SkVertices::BoneIndices& indices = this->boneIndices()[i];
    252             const SkVertices::BoneWeights& weights = this->boneWeights()[i];
    253             for (int j = 0; j < 4; j++) {
    254                 int index = indices[j];
    255                 float weight = weights[j];
    256                 if (index == 0 || weight == 0.0f) {
    257                     continue;
    258                 }
    259                 SkASSERT(index < boneCount);
    260 
    261                 // result += M * v * w.
    262                 result += bones[index].mapPoint(position) * weight;
    263             }
    264             position = result;
    265         }
    266     }
    267 
    268     // Recalculate the bounds.
    269     copy->fBounds.set(copy->fPositions, copy->fVertexCnt);
    270 
    271     return copy;
    272 }
    273 
    274 ///////////////////////////////////////////////////////////////////////////////////////////////////
    275 
    276 sk_sp<SkVertices> SkVertices::MakeCopy(VertexMode mode, int vertexCount,
    277                                        const SkPoint pos[], const SkPoint texs[],
    278                                        const SkColor colors[],
    279                                        const BoneIndices boneIndices[],
    280                                        const BoneWeights boneWeights[],
    281                                        int indexCount, const uint16_t indices[],
    282                                        bool isVolatile) {
    283     SkASSERT((!boneIndices && !boneWeights) || (boneIndices && boneWeights));
    284     Sizes sizes(mode,
    285                 vertexCount,
    286                 indexCount,
    287                 texs != nullptr,
    288                 colors != nullptr,
    289                 boneIndices != nullptr);
    290     if (!sizes.isValid()) {
    291         return nullptr;
    292     }
    293 
    294     Builder builder(mode, vertexCount, indexCount, isVolatile, sizes);
    295     SkASSERT(builder.isValid());
    296 
    297     sk_careful_memcpy(builder.positions(), pos, sizes.fVSize);
    298     sk_careful_memcpy(builder.texCoords(), texs, sizes.fTSize);
    299     sk_careful_memcpy(builder.colors(), colors, sizes.fCSize);
    300     sk_careful_memcpy(builder.boneIndices(), boneIndices, sizes.fBISize);
    301     sk_careful_memcpy(builder.boneWeights(), boneWeights, sizes.fBWSize);
    302     size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
    303     sk_careful_memcpy(builder.indices(), indices, isize);
    304 
    305     return builder.detach();
    306 }
    307 
    308 size_t SkVertices::approximateSize() const {
    309     Sizes sizes(fMode,
    310                 fVertexCnt,
    311                 fIndexCnt,
    312                 this->hasTexCoords(),
    313                 this->hasColors(),
    314                 this->hasBones());
    315     SkASSERT(sizes.isValid());
    316     return sizeof(SkVertices) + sizes.fArrays;
    317 }
    318 
    319 ///////////////////////////////////////////////////////////////////////////////////////////////////
    320 
    321 // storage = packed | vertex_count | index_count | pos[] | texs[] | colors[] | boneIndices[] |
    322 //           boneWeights[] | indices[]
    323 //         = header + arrays
    324 
    325 #define kMode_Mask          0x0FF
    326 #define kHasTexs_Mask       0x100
    327 #define kHasColors_Mask     0x200
    328 #define kHasBones_Mask      0x400
    329 #define kIsNonVolatile_Mask 0x800
    330 #define kHeaderSize         (3 * sizeof(uint32_t))
    331 
    332 sk_sp<SkData> SkVertices::encode() const {
    333     // packed has room for addtional flags in the future (e.g. versioning)
    334     uint32_t packed = static_cast<uint32_t>(fMode);
    335     SkASSERT((packed & ~kMode_Mask) == 0);  // our mode fits in the mask bits
    336     if (this->hasTexCoords()) {
    337         packed |= kHasTexs_Mask;
    338     }
    339     if (this->hasColors()) {
    340         packed |= kHasColors_Mask;
    341     }
    342     if (this->hasBones()) {
    343         packed |= kHasBones_Mask;
    344     }
    345     if (!this->isVolatile()) {
    346         packed |= kIsNonVolatile_Mask;
    347     }
    348 
    349     Sizes sizes(fMode,
    350                 fVertexCnt,
    351                 fIndexCnt,
    352                 this->hasTexCoords(),
    353                 this->hasColors(),
    354                 this->hasBones());
    355     SkASSERT(sizes.isValid());
    356     SkASSERT(!sizes.fBuilderTriFanISize);
    357     // need to force alignment to 4 for SkWriter32 -- will pad w/ 0s as needed
    358     const size_t size = SkAlign4(kHeaderSize + sizes.fArrays);
    359 
    360     sk_sp<SkData> data = SkData::MakeUninitialized(size);
    361     SkWriter32 writer(data->writable_data(), data->size());
    362 
    363     writer.write32(packed);
    364     writer.write32(fVertexCnt);
    365     writer.write32(fIndexCnt);
    366     writer.write(fPositions, sizes.fVSize);
    367     writer.write(fTexs, sizes.fTSize);
    368     writer.write(fColors, sizes.fCSize);
    369     writer.write(fBoneIndices, sizes.fBISize);
    370     writer.write(fBoneWeights, sizes.fBWSize);
    371     // if index-count is odd, we won't be 4-bytes aligned, so we call the pad version
    372     writer.writePad(fIndices, sizes.fISize);
    373 
    374     return data;
    375 }
    376 
    377 sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) {
    378     if (length < kHeaderSize) {
    379         return nullptr;
    380     }
    381 
    382     SkReader32 reader(data, length);
    383     SkSafeRange safe;
    384 
    385     const uint32_t packed = reader.readInt();
    386     const int vertexCount = safe.checkGE(reader.readInt(), 0);
    387     const int indexCount = safe.checkGE(reader.readInt(), 0);
    388     const VertexMode mode = safe.checkLE<VertexMode>(packed & kMode_Mask,
    389                                                      SkVertices::kLast_VertexMode);
    390     if (!safe) {
    391         return nullptr;
    392     }
    393     const bool hasTexs = SkToBool(packed & kHasTexs_Mask);
    394     const bool hasColors = SkToBool(packed & kHasColors_Mask);
    395     const bool hasBones = SkToBool(packed & kHasBones_Mask);
    396     const bool isVolatile = !SkToBool(packed & kIsNonVolatile_Mask);
    397     Sizes sizes(mode, vertexCount, indexCount, hasTexs, hasColors, hasBones);
    398     if (!sizes.isValid()) {
    399         return nullptr;
    400     }
    401     // logically we can be only 2-byte aligned, but our buffer is always 4-byte aligned
    402     if (SkAlign4(kHeaderSize + sizes.fArrays) != length) {
    403         return nullptr;
    404     }
    405 
    406     Builder builder(mode, vertexCount, indexCount, isVolatile, sizes);
    407 
    408     reader.read(builder.positions(), sizes.fVSize);
    409     reader.read(builder.texCoords(), sizes.fTSize);
    410     reader.read(builder.colors(), sizes.fCSize);
    411     reader.read(builder.boneIndices(), sizes.fBISize);
    412     reader.read(builder.boneWeights(), sizes.fBWSize);
    413     size_t isize = (mode == kTriangleFan_VertexMode) ? sizes.fBuilderTriFanISize : sizes.fISize;
    414     reader.read(builder.indices(), isize);
    415     if (indexCount > 0) {
    416         // validate that the indicies are in range
    417         SkASSERT(indexCount == builder.indexCount());
    418         const uint16_t* indices = builder.indices();
    419         for (int i = 0; i < indexCount; ++i) {
    420             if (indices[i] >= (unsigned)vertexCount) {
    421                 return nullptr;
    422             }
    423         }
    424     }
    425     return builder.detach();
    426 }
    427 
    428 void SkVertices::operator delete(void* p)
    429 {
    430     ::operator delete(p);
    431 }
    432