diff options
-rw-r--r-- | gn/tests.gni | 1 | ||||
-rw-r--r-- | include/core/SkVertices.h | 5 | ||||
-rw-r--r-- | src/core/SkVertices.cpp | 136 | ||||
-rw-r--r-- | tests/VerticesTest.cpp | 85 |
4 files changed, 207 insertions, 20 deletions
diff --git a/gn/tests.gni b/gn/tests.gni index 1e9fb0eca9..b2a814e1ba 100644 --- a/gn/tests.gni +++ b/gn/tests.gni @@ -247,6 +247,7 @@ tests_sources = [ "$_tests/UnicodeTest.cpp", "$_tests/UtilsTest.cpp", "$_tests/VarAllocTest.cpp", + "$_tests/VerticesTest.cpp", "$_tests/VkClearTests.cpp", "$_tests/VkHeapTests.cpp", "$_tests/VkUploadPixelsTests.cpp", diff --git a/include/core/SkVertices.h b/include/core/SkVertices.h index 2e4f09ff8c..5dbdefaa3c 100644 --- a/include/core/SkVertices.h +++ b/include/core/SkVertices.h @@ -10,6 +10,7 @@ #include "SkCanvas.h" #include "SkColor.h" +#include "SkData.h" #include "SkPoint.h" #include "SkRect.h" #include "SkRefCnt.h" @@ -91,6 +92,10 @@ public: const SkRect& bounds() const { return fBounds; } + + static sk_sp<SkVertices> Decode(const void*, size_t); + sk_sp<SkData> encode() const; + private: SkVertices() {} diff --git a/src/core/SkVertices.cpp b/src/core/SkVertices.cpp index 5ae0d34de4..f2a63b9a73 100644 --- a/src/core/SkVertices.cpp +++ b/src/core/SkVertices.cpp @@ -6,36 +6,40 @@ */ #include "SkVertices.h" +#include "SkData.h" +#include "SkReader32.h" +#include "SkWriter32.h" -SkVertices::Builder::Builder(SkCanvas::VertexMode mode, int vertexCount, int indexCount, - uint32_t flags) { - fPositions = nullptr; // signal that we have nothing to cleanup - fColors = nullptr; - fTexs = nullptr; - fIndices = nullptr; - fVertexCnt = 0; - fIndexCnt = 0; - - // If we public merge drawPoints and drawVertices to share this object, we can perform - // meaningful checks on counts based on mode. -#if 0 - if (vertexCount <= 2) { - return; - } - if (indexCount && indexCount <= 2) { - return; +static size_t compute_arrays_size(int vertexCount, int indexCount, uint32_t builderFlags) { + if (vertexCount < 0 || indexCount < 0) { + return 0; // signal error } -#endif uint64_t size = vertexCount * sizeof(SkPoint); - if (flags & kHasTexs_Flag) { + if (builderFlags & SkVertices::kHasTexs_Flag) { size += vertexCount * sizeof(SkPoint); } - if (flags & kHasColors_Flag) { + if (builderFlags & SkVertices::kHasColors_Flag) { size += vertexCount * sizeof(SkColor); } size += indexCount * sizeof(uint16_t); if (!sk_64_isS32(size)) { + return 0; // signal error + } + return (size_t)size; +} + +SkVertices::Builder::Builder(SkCanvas::VertexMode mode, int vertexCount, int indexCount, + uint32_t flags) { + fPositions = nullptr; // signal that we have nothing to cleanup + fColors = nullptr; + fTexs = nullptr; + fIndices = nullptr; + fVertexCnt = 0; + fIndexCnt = 0; + + size_t size = compute_arrays_size(vertexCount, indexCount, flags); + if (0 == size) { return; } @@ -112,3 +116,95 @@ sk_sp<SkVertices> SkVertices::MakeCopy(SkCanvas::VertexMode mode, int vertexCoun } return builder.detach(); } + +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// storage = flags | vertex_count | index_count | pos[] | texs[] | colors[] | indices[] + +#define kMode_Mask 0x0FF +#define kHasTexs_Mask 0x100 +#define kHasColors_Mask 0x200 + +sk_sp<SkData> SkVertices::encode() const { + uint32_t flags = static_cast<uint32_t>(fMode); + SkASSERT((flags & ~kMode_Mask) == 0); + if (fTexs) { + flags |= kHasTexs_Mask; + } + if (fColors) { + flags |= kHasColors_Mask; + } + + size_t size = sizeof(uint32_t) * 3; // flags | verts_count | indices_count + size += fVertexCnt * sizeof(SkPoint); + if (fTexs) { + size += fVertexCnt * sizeof(SkPoint); + } + if (fColors) { + size += fVertexCnt * sizeof(SkColor); + } + size += fIndexCnt * sizeof(uint16_t); + + sk_sp<SkData> data = SkData::MakeUninitialized(size); + SkWriter32 writer(data->writable_data(), data->size()); + + writer.write32(flags); + writer.write32(fVertexCnt); + writer.write32(fIndexCnt); + writer.write(fPositions, fVertexCnt * sizeof(SkPoint)); + if (fTexs) { + writer.write(fTexs, fVertexCnt * sizeof(SkPoint)); + } + if (fColors) { + writer.write(fColors, fVertexCnt * sizeof(SkColor)); + } + writer.write(fIndices, fIndexCnt * sizeof(uint16_t)); + + return data; +} + +sk_sp<SkVertices> SkVertices::Decode(const void* data, size_t length) { + if (length < 3 * sizeof(uint32_t)) { + return nullptr; // buffer too small + } + + SkReader32 reader(data, length); + + uint32_t storageFlags = reader.readInt(); + SkCanvas::VertexMode mode = static_cast<SkCanvas::VertexMode>(storageFlags & kMode_Mask); + int vertexCount = reader.readInt(); + int indexCount = reader.readInt(); + uint32_t builderFlags = 0; + if (storageFlags & kHasTexs_Mask) { + builderFlags |= SkVertices::kHasTexs_Flag; + } + if (storageFlags & kHasColors_Mask) { + builderFlags |= SkVertices::kHasColors_Flag; + } + + size_t size = compute_arrays_size(vertexCount, indexCount, builderFlags); + if (0 == size) { + return nullptr; + } + + length -= 3 * sizeof(uint32_t); // already read the header + if (length < size) { // buffer too small + return nullptr; + } + + Builder builder(mode, vertexCount, indexCount, builderFlags); + if (!builder.isValid()) { + return nullptr; + } + + reader.read(builder.positions(), vertexCount * sizeof(SkPoint)); + if (builderFlags & SkVertices::kHasTexs_Flag) { + reader.read(builder.texCoords(), vertexCount * sizeof(SkPoint)); + } + if (builderFlags & SkVertices::kHasColors_Flag) { + reader.read(builder.colors(), vertexCount * sizeof(SkColor)); + } + reader.read(builder.indices(), indexCount * sizeof(uint16_t)); + + return builder.detach(); +} diff --git a/tests/VerticesTest.cpp b/tests/VerticesTest.cpp new file mode 100644 index 0000000000..9c433baf86 --- /dev/null +++ b/tests/VerticesTest.cpp @@ -0,0 +1,85 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkVertices.h" +#include "Test.h" + +static bool equal(const SkVertices* v0, const SkVertices* v1) { + if (v0->mode() != v1->mode()) { + return false; + } + if (v0->vertexCount() != v1->vertexCount()) { + return false; + } + if (v0->indexCount() != v1->indexCount()) { + return false; + } + + if (!!v0->texCoords() != !!v1->texCoords()) { + return false; + } + if (!!v0->colors() != !!v1->colors()) { + return false; + } + + for (int i = 0; i < v0->vertexCount(); ++i) { + if (v0->positions()[i] != v1->positions()[i]) { + return false; + } + if (v0->texCoords()) { + if (v0->texCoords()[i] != v1->texCoords()[i]) { + return false; + } + } + if (v0->colors()) { + if (v0->colors()[i] != v1->colors()[i]) { + return false; + } + } + } + for (int i = 0; i < v0->indexCount(); ++i) { + if (v0->indices()[i] != v1->indices()[i]) { + return false; + } + } + return true; +} + +DEF_TEST(Vertices, reporter) { + int vCount = 4; + int iCount = 6; + + const uint32_t texFlags[] = { 0, SkVertices::kHasTexs_Flag }; + const uint32_t colFlags[] = { 0, SkVertices::kHasColors_Flag }; + for (auto texF : texFlags) { + for (auto colF : colFlags) { + uint32_t flags = texF | colF; + + SkVertices::Builder builder(SkCanvas::kTriangles_VertexMode, vCount, iCount, flags); + + for (int i = 0; i < vCount; ++i) { + float x = (float)i; + builder.positions()[i].set(x, 1); + if (builder.texCoords()) { + builder.texCoords()[i].set(x, 2); + } + if (builder.colors()) { + builder.colors()[i] = SkColorSetARGB(0xFF, i, 0x80, 0); + } + } + for (int i = 0; i < builder.indexCount(); ++i) { + builder.indices()[i] = i % vCount; + } + + sk_sp<SkVertices> v0 = builder.detach(); + sk_sp<SkData> data = v0->encode(); + sk_sp<SkVertices> v1 = SkVertices::Decode(data->data(), data->size()); + + REPORTER_ASSERT(reporter, equal(v0.get(), v1.get())); + } + } +} |