Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 8 | #include "include/core/SkCanvas.h" |
| 9 | #include "include/core/SkSurface.h" |
| 10 | #include "include/core/SkVertices.h" |
Mike Reed | ba96256 | 2020-03-12 20:33:21 -0400 | [diff] [blame] | 11 | #include "src/core/SkVerticesPriv.h" |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 12 | #include "tests/Test.h" |
| 13 | #include "tools/ToolUtils.h" |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 14 | |
Mike Reed | ba96256 | 2020-03-12 20:33:21 -0400 | [diff] [blame] | 15 | static bool equal(const SkVertices* vert0, const SkVertices* vert1) { |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 16 | SkVerticesPriv v0(vert0->priv()), v1(vert1->priv()); |
Mike Reed | ba96256 | 2020-03-12 20:33:21 -0400 | [diff] [blame] | 17 | |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 18 | if (v0.mode() != v1.mode()) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 19 | return false; |
| 20 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 21 | if (v0.vertexCount() != v1.vertexCount()) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 22 | return false; |
| 23 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 24 | if (v0.indexCount() != v1.indexCount()) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 25 | return false; |
| 26 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 27 | if (v0.attributeCount() != v1.attributeCount()) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 28 | return false; |
| 29 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 30 | for (int i = 0; i < v0.attributeCount(); ++i) { |
| 31 | if (v0.attributes()[i] != v1.attributes()[i]) { |
| 32 | return false; |
| 33 | } |
| 34 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 35 | |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 36 | if (!!v0.customData() != !!v1.customData()) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 37 | return false; |
| 38 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 39 | if (!!v0.texCoords() != !!v1.texCoords()) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 40 | return false; |
| 41 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 42 | if (!!v0.colors() != !!v1.colors()) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 43 | return false; |
| 44 | } |
| 45 | |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 46 | for (int i = 0; i < v0.vertexCount(); ++i) { |
| 47 | if (v0.positions()[i] != v1.positions()[i]) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 48 | return false; |
| 49 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 50 | if (v0.texCoords()) { |
| 51 | if (v0.texCoords()[i] != v1.texCoords()[i]) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 52 | return false; |
| 53 | } |
| 54 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 55 | if (v0.colors()) { |
| 56 | if (v0.colors()[i] != v1.colors()[i]) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 57 | return false; |
| 58 | } |
| 59 | } |
| 60 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 61 | size_t totalCustomDataSize = v0.vertexCount() * v0.customDataSize(); |
| 62 | if (totalCustomDataSize) { |
| 63 | if (memcmp(v0.customData(), v1.customData(), totalCustomDataSize) != 0) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 64 | return false; |
| 65 | } |
| 66 | } |
Brian Osman | 8cbedf9 | 2020-03-31 10:38:31 -0400 | [diff] [blame] | 67 | for (int i = 0; i < v0.indexCount(); ++i) { |
| 68 | if (v0.indices()[i] != v1.indices()[i]) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 69 | return false; |
| 70 | } |
| 71 | } |
| 72 | return true; |
| 73 | } |
| 74 | |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 75 | static void self_test(sk_sp<SkVertices> v0, skiatest::Reporter* reporter) { |
| 76 | sk_sp<SkData> data = v0->encode(); |
| 77 | sk_sp<SkVertices> v1 = SkVertices::Decode(data->data(), data->size()); |
| 78 | |
| 79 | REPORTER_ASSERT(reporter, v0->uniqueID() != 0); |
| 80 | REPORTER_ASSERT(reporter, v1->uniqueID() != 0); |
| 81 | REPORTER_ASSERT(reporter, v0->uniqueID() != v1->uniqueID()); |
| 82 | REPORTER_ASSERT(reporter, equal(v0.get(), v1.get())); |
| 83 | } |
| 84 | |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 85 | DEF_TEST(Vertices, reporter) { |
Mike Reed | 6ff6af9 | 2017-04-05 17:05:16 -0400 | [diff] [blame] | 86 | int vCount = 5; |
| 87 | int iCount = 9; // odd value exercises padding logic in encode() |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 88 | |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 89 | // color-tex tests |
Mike Reed | aa9e332 | 2017-03-16 14:38:48 -0400 | [diff] [blame] | 90 | const uint32_t texFlags[] = { 0, SkVertices::kHasTexCoords_BuilderFlag }; |
| 91 | const uint32_t colFlags[] = { 0, SkVertices::kHasColors_BuilderFlag }; |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 92 | for (auto texF : texFlags) { |
| 93 | for (auto colF : colFlags) { |
| 94 | uint32_t flags = texF | colF; |
| 95 | |
Mike Reed | 887cdf1 | 2017-04-03 11:11:09 -0400 | [diff] [blame] | 96 | SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vCount, iCount, flags); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 97 | |
| 98 | for (int i = 0; i < vCount; ++i) { |
| 99 | float x = (float)i; |
| 100 | builder.positions()[i].set(x, 1); |
| 101 | if (builder.texCoords()) { |
| 102 | builder.texCoords()[i].set(x, 2); |
| 103 | } |
| 104 | if (builder.colors()) { |
| 105 | builder.colors()[i] = SkColorSetARGB(0xFF, i, 0x80, 0); |
| 106 | } |
| 107 | } |
Brian Osman | 46aacc7 | 2020-04-01 15:48:53 -0400 | [diff] [blame] | 108 | for (int i = 0; i < iCount; ++i) { |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 109 | builder.indices()[i] = i % vCount; |
| 110 | } |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 111 | self_test(builder.detach(), reporter); |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 112 | } |
| 113 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 114 | |
| 115 | // custom data tests |
| 116 | using AttrType = SkVertices::Attribute::Type; |
| 117 | struct { |
| 118 | int count; |
| 119 | size_t expected_size; |
| 120 | SkVertices::Attribute attrs[4]; |
| 121 | } attrTests[] = { |
| 122 | { 1, 4, { AttrType::kFloat } }, |
| 123 | { 1, 8, { AttrType::kFloat2 } }, |
| 124 | { 1, 12, { AttrType::kFloat3 } }, |
| 125 | { 1, 16, { AttrType::kFloat4 } }, |
| 126 | { 1, 4, { AttrType::kByte4_unorm } }, |
| 127 | { 4, 16, { AttrType::kFloat, AttrType::kFloat, AttrType::kFloat, AttrType::kFloat } }, |
| 128 | { 2, 12, { AttrType::kFloat2, AttrType::kByte4_unorm } }, |
| 129 | { 2, 12, { AttrType::kByte4_unorm, AttrType::kFloat2 } }, |
| 130 | }; |
| 131 | |
| 132 | for (const auto& test : attrTests) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 133 | SkVertices::Builder builder(SkVertices::kTriangles_VertexMode, vCount, iCount, |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 134 | test.attrs, test.count); |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 135 | |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 136 | float* customData = (float*)builder.customData(); |
| 137 | int customDataCount = test.expected_size / sizeof(float); |
Brian Osman | 46aacc7 | 2020-04-01 15:48:53 -0400 | [diff] [blame] | 138 | for (int i = 0; i < vCount; ++i) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 139 | builder.positions()[i].set((float)i, 1); |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 140 | for (int j = 0; j < customDataCount; ++j) { |
| 141 | customData[i * customDataCount + j] = (float)j; |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 142 | } |
| 143 | } |
Brian Osman | 46aacc7 | 2020-04-01 15:48:53 -0400 | [diff] [blame] | 144 | for (int i = 0; i < iCount; ++i) { |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 145 | builder.indices()[i] = i % vCount; |
| 146 | } |
| 147 | self_test(builder.detach(), reporter); |
| 148 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 149 | |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 150 | { |
| 151 | // This has the maximum number of vertices to be rewritten as indexed triangles without |
| 152 | // overflowing a 16bit index. |
Ben Wagner | b089765 | 2018-06-15 15:37:57 +0000 | [diff] [blame] | 153 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, UINT16_MAX + 1, 0, |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 154 | SkVertices::kHasColors_BuilderFlag); |
| 155 | REPORTER_ASSERT(reporter, builder.isValid()); |
| 156 | } |
| 157 | { |
| 158 | // This has too many to be rewritten. |
Ben Wagner | b089765 | 2018-06-15 15:37:57 +0000 | [diff] [blame] | 159 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, UINT16_MAX + 2, 0, |
Brian Salomon | cccafe8 | 2018-04-28 16:13:08 -0400 | [diff] [blame] | 160 | SkVertices::kHasColors_BuilderFlag); |
| 161 | REPORTER_ASSERT(reporter, !builder.isValid()); |
| 162 | } |
| 163 | { |
| 164 | // Only two vertices - can't be rewritten. |
| 165 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 2, 0, |
| 166 | SkVertices::kHasColors_BuilderFlag); |
| 167 | REPORTER_ASSERT(reporter, !builder.isValid()); |
| 168 | } |
| 169 | { |
| 170 | // Minimum number of indices to be rewritten. |
| 171 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 3, |
| 172 | SkVertices::kHasColors_BuilderFlag); |
| 173 | REPORTER_ASSERT(reporter, builder.isValid()); |
| 174 | } |
| 175 | { |
| 176 | // Too few indices to be rewritten. |
| 177 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 2, |
| 178 | SkVertices::kHasColors_BuilderFlag); |
| 179 | REPORTER_ASSERT(reporter, !builder.isValid()); |
| 180 | } |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 181 | |
| 182 | // validity tests for per-vertex-data |
| 183 | |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 184 | // Check that invalid counts fail to initialize the builder |
| 185 | for (int attrCount : {-1, 0, SkVertices::kMaxCustomAttributes + 1}) { |
| 186 | SkVertices::Attribute attrs[] = { AttrType::kFloat }; |
| 187 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 0, attrs, attrCount); |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 188 | REPORTER_ASSERT(reporter, !builder.isValid()); |
| 189 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 190 | { // nullptr is definitely bad |
| 191 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 0, nullptr, 4); |
| 192 | REPORTER_ASSERT(reporter, !builder.isValid()); |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 193 | } |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 194 | { // "normal" number of per-vertex-data (all floats) |
| 195 | SkVertices::Attribute attrs[] = {AttrType::kFloat2, AttrType::kFloat2}; |
| 196 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 0, attrs, 2); |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 197 | REPORTER_ASSERT(reporter, builder.isValid()); |
Brian Osman | ffd11f4a | 2020-03-30 09:57:53 -0400 | [diff] [blame] | 198 | REPORTER_ASSERT(reporter, builder.customData() != nullptr); |
| 199 | } |
| 200 | { // "normal" number of per-vertex-data (with packed bytes) |
| 201 | SkVertices::Attribute attrs[] = {AttrType::kFloat2, AttrType::kByte4_unorm}; |
| 202 | SkVertices::Builder builder(SkVertices::kTriangleFan_VertexMode, 10, 0, attrs, 2); |
| 203 | REPORTER_ASSERT(reporter, builder.isValid()); |
| 204 | REPORTER_ASSERT(reporter, builder.customData() != nullptr); |
Mike Reed | 50c64ab | 2020-03-05 13:01:00 -0500 | [diff] [blame] | 205 | } |
Mike Reed | bdce9c2 | 2017-03-14 14:10:54 -0400 | [diff] [blame] | 206 | } |
Mike Reed | 63227ca | 2018-01-30 10:12:22 -0500 | [diff] [blame] | 207 | |
| 208 | static void fill_triangle(SkCanvas* canvas, const SkPoint pts[], SkColor c) { |
| 209 | SkColor colors[] = { c, c, c }; |
| 210 | auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, 3, pts, nullptr, colors); |
| 211 | canvas->drawVertices(verts, SkBlendMode::kSrc, SkPaint()); |
| 212 | } |
| 213 | |
| 214 | DEF_TEST(Vertices_clipping, reporter) { |
| 215 | // A very large triangle has to be geometrically clipped (since its "fast" clipping is |
| 216 | // normally done in after building SkFixed coordinates). Check that we handle this. |
| 217 | // (and don't assert). |
| 218 | auto surf = SkSurface::MakeRasterN32Premul(3, 3); |
| 219 | |
| 220 | SkPoint pts[] = { { -10, 1 }, { -10, 2 }, { 1e9f, 1.5f } }; |
| 221 | fill_triangle(surf->getCanvas(), pts, SK_ColorBLACK); |
| 222 | |
Mike Klein | ea3f014 | 2019-03-20 11:12:10 -0500 | [diff] [blame] | 223 | ToolUtils::PixelIter iter(surf.get()); |
Mike Reed | 63227ca | 2018-01-30 10:12:22 -0500 | [diff] [blame] | 224 | SkIPoint loc; |
| 225 | while (void* addr = iter.next(&loc)) { |
| 226 | SkPMColor c = *(SkPMColor*)addr; |
| 227 | if (loc.fY == 1) { |
| 228 | REPORTER_ASSERT(reporter, c == 0xFF000000); |
| 229 | } else { |
| 230 | REPORTER_ASSERT(reporter, c == 0); |
| 231 | } |
| 232 | } |
| 233 | } |