1/* 2 * Copyright 2019 Google LLC 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 "tests/Test.h" 9 10#include "src/gpu/geometry/GrQuadBuffer.h" 11 12#include <vector> 13 14#define ASSERT(cond) REPORTER_ASSERT(r, cond) 15#define ASSERTF(cond, ...) REPORTER_ASSERT(r, cond, __VA_ARGS__) 16#define TEST(name) DEF_TEST(GrQuadBuffer##name, r) 17 18struct TestData { 19 int fItem1; 20 float fItem2; 21}; 22 23static void assert_quad_eq(skiatest::Reporter* r, const GrQuad& expected, const GrQuad& actual) { 24 ASSERTF(expected.quadType() == actual.quadType(), "Expected type %d, got %d", 25 (int) expected.quadType(), (int) actual.quadType()); 26 for (int i = 0; i < 4; ++i) { 27 ASSERTF(expected.x(i) == actual.x(i), "Expected x(%d) = %f, got %f", 28 i, expected.x(i), actual.x(i)); 29 ASSERTF(expected.y(i) == actual.y(i), "Expected y(%d) = %f, got %f", 30 i, expected.y(i), actual.y(i)); 31 ASSERTF(expected.w(i) == actual.w(i), "Expected w(%d) = %f, got %f", 32 i, expected.w(i), actual.w(i)); 33 } 34} 35 36static void assert_metadata_eq(skiatest::Reporter* r, const TestData& expected, 37 const TestData& actual) { 38 ASSERTF(expected.fItem1 == actual.fItem1 && expected.fItem2 == actual.fItem2, 39 "Expected { %d, %f } for metadata, got: { %d %f }", 40 expected.fItem1, expected.fItem2, actual.fItem1, actual.fItem2); 41} 42 43static std::vector<GrQuad> generate_quads(float seed, int cnt, const GrQuad::Type types[]) { 44 // For convenience use matrix to derive each quad type, rely on different seed values to 45 // differentiate between quads of the same type 46 SkMatrix rotate; 47 rotate.setRotate(45.f); 48 SkMatrix skew; 49 skew.setSkew(0.5f, 0.5f); 50 SkMatrix perspective; 51 perspective.setPerspX(0.01f); 52 perspective.setPerspY(0.001f); 53 54 std::vector<GrQuad> quads; 55 SkRect rect = SkRect::MakeXYWH(seed, 2.f * seed, 2.f * seed, seed); 56 for (int i = 0; i < cnt; ++i) { 57 GrQuad quad; 58 switch(types[i]) { 59 case GrQuad::Type::kAxisAligned: 60 quad = GrQuad(rect); 61 break; 62 case GrQuad::Type::kRectilinear: 63 quad = GrQuad::MakeFromRect(rect, rotate); 64 break; 65 case GrQuad::Type::kGeneral: 66 quad = GrQuad::MakeFromRect(rect, skew); 67 break; 68 default: 69 SkASSERT(types[i] == GrQuad::Type::kPerspective); 70 quad = GrQuad::MakeFromRect(rect, perspective); 71 break; 72 } 73 74 SkASSERT(quad.quadType() == types[i]); 75 quads.push_back(quad); 76 } 77 return quads; 78} 79 80TEST(Append) { 81 // Generate test data, which includes all quad types out of enum-order and duplicates 82 static const int kQuadCount = 6; 83 static const GrQuad::Type kDeviceTypes[] = { 84 GrQuad::Type::kAxisAligned, GrQuad::Type::kRectilinear, GrQuad::Type::kGeneral, 85 GrQuad::Type::kPerspective, GrQuad::Type::kRectilinear, GrQuad::Type::kAxisAligned 86 }; 87 // Odd indexed quads will be ignored and not stored in the buffer 88 static const GrQuad::Type kLocalTypes[] = { 89 GrQuad::Type::kGeneral, GrQuad::Type::kGeneral, GrQuad::Type::kRectilinear, 90 GrQuad::Type::kRectilinear, GrQuad::Type::kAxisAligned, GrQuad::Type::kAxisAligned 91 }; 92 static_assert(SK_ARRAY_COUNT(kDeviceTypes) == kQuadCount, "device quad count"); 93 static_assert(SK_ARRAY_COUNT(kLocalTypes) == kQuadCount, "local quad count"); 94 95 std::vector<GrQuad> expectedDeviceQuads = generate_quads(1.f, kQuadCount, kDeviceTypes); 96 std::vector<GrQuad> expectedLocalQuads = generate_quads(2.f, kQuadCount, kLocalTypes); 97 98 // Fill in the buffer with the device quads, and a local quad if the index is even 99 GrQuadBuffer<TestData> buffer; 100 for (int i = 0; i < kQuadCount; ++i) { 101 buffer.append(expectedDeviceQuads[i], // device quad 102 { 2 * i, 3.f * i }, // metadata 103 i % 2 == 0 ? &expectedLocalQuads[i] : nullptr); // optional local quad 104 } 105 106 // Confirm the state of the buffer 107 ASSERT(kQuadCount == buffer.count()); 108 ASSERT(GrQuad::Type::kPerspective == buffer.deviceQuadType()); 109 ASSERT(GrQuad::Type::kGeneral == buffer.localQuadType()); 110 111 int i = 0; 112 auto iter = buffer.iterator(); 113 while(iter.next()) { 114 // Each entry always has the device quad 115 assert_quad_eq(r, expectedDeviceQuads[i], *iter.deviceQuad()); 116 assert_metadata_eq(r, {2 * i, 3.f * i}, iter.metadata()); 117 118 if (i % 2 == 0) { 119 // Confirm local quads included on even entries 120 ASSERT(iter.isLocalValid()); 121 assert_quad_eq(r, expectedLocalQuads[i], *iter.localQuad()); 122 } else { 123 // Should not have locals 124 ASSERT(!iter.isLocalValid()); 125 ASSERT(!iter.localQuad()); 126 } 127 128 i++; 129 } 130 ASSERTF(i == kQuadCount, "Expected %d iterations, got: %d", kQuadCount, i); 131} 132 133TEST(Concat) { 134 static const int kQuadCount = 2; 135 static const GrQuad::Type kTypesA[] = { GrQuad::Type::kAxisAligned, GrQuad::Type::kRectilinear }; 136 static const GrQuad::Type kTypesB[] = { GrQuad::Type::kGeneral, GrQuad::Type::kPerspective }; 137 static_assert(SK_ARRAY_COUNT(kTypesA) == kQuadCount, "quadsA count"); 138 static_assert(SK_ARRAY_COUNT(kTypesB) == kQuadCount, "quadsB count"); 139 140 std::vector<GrQuad> quadsA = generate_quads(1.f, kQuadCount, kTypesA); 141 std::vector<GrQuad> quadsB = generate_quads(2.f, kQuadCount, kTypesB); 142 // Make two buffers, the first uses 'quadsA' for device quads and 'quadsB' for local quads 143 // on even indices. The second uses 'quadsB' for device quads and 'quadsA' for local quads 144 // on odd indices. 145 GrQuadBuffer<TestData> buffer1; 146 GrQuadBuffer<TestData> buffer2; 147 for (int i = 0; i < kQuadCount; ++i) { 148 buffer1.append(quadsA[i], {i, 2.f * i}, i % 2 == 0 ? &quadsB[i] : nullptr); 149 buffer2.append(quadsB[i], {2 * i, 0.5f * i}, i % 2 == 0 ? nullptr : &quadsA[i]); 150 } 151 152 ASSERT(kQuadCount == buffer1.count()); 153 ASSERT(kQuadCount == buffer2.count()); 154 155 // Perform the concatenation and then confirm the new state of buffer1 156 buffer1.concat(buffer2); 157 158 ASSERT(2 * kQuadCount == buffer1.count()); 159 int i = 0; 160 auto iter = buffer1.iterator(); 161 while(iter.next()) { 162 if (i < kQuadCount) { 163 // First half should match original buffer1 164 assert_quad_eq(r, quadsA[i], *iter.deviceQuad()); 165 assert_metadata_eq(r, {i, 2.f * i}, iter.metadata()); 166 if (i % 2 == 0) { 167 ASSERT(iter.isLocalValid()); 168 assert_quad_eq(r, quadsB[i], *iter.localQuad()); 169 } else { 170 ASSERT(!iter.isLocalValid()); 171 ASSERT(!iter.localQuad()); 172 } 173 174 } else { 175 // Second half should match buffer2 176 int j = i - kQuadCount; 177 assert_quad_eq(r, quadsB[j], *iter.deviceQuad()); 178 assert_metadata_eq(r, {2 * j, 0.5f * j}, iter.metadata()); 179 if (j % 2 == 0) { 180 ASSERT(!iter.isLocalValid()); 181 ASSERT(!iter.localQuad()); 182 } else { 183 ASSERT(iter.isLocalValid()); 184 assert_quad_eq(r, quadsA[j], *iter.localQuad()); 185 } 186 } 187 188 i++; 189 } 190 ASSERTF(i == 2 * kQuadCount, "Expected %d iterations, got: %d",2 * kQuadCount, i); 191} 192 193TEST(Metadata) { 194 static const int kQuadCount = 3; 195 196 // This test doesn't really care about the quad coordinates (except that they aren't modified 197 // when mutating the metadata) 198 GrQuad quad(SkRect::MakeLTRB(1.f, 2.f, 3.f, 4.f)); 199 200 GrQuadBuffer<TestData> buffer; 201 for (int i = 0; i < kQuadCount; ++i) { 202 buffer.append(quad, {i, 2.f * i}, i % 2 == 0 ? &quad : nullptr); 203 } 204 205 // Iterate once using the metadata iterator, confirm the test data and rewrite 206 int i = 0; 207 auto meta = buffer.metadata(); 208 while(meta.next()) { 209 // Confirm initial state 210 assert_metadata_eq(r, {i, 2.f * i}, *meta); 211 // Rewrite 212 *meta = {2 * i, 0.5f * i}; 213 i++; 214 } 215 ASSERTF(i == kQuadCount, "Expected %d iterations, got: %d", kQuadCount, i); 216 217 // Now that all metadata has been touched, read with regular iterator and confirm updated state 218 // and that no quad coordinates have been changed. 219 i = 0; 220 auto iter = buffer.iterator(); 221 while(iter.next()) { 222 // New metadata 223 assert_metadata_eq(r, {2 * i, 0.5f * i}, iter.metadata()); 224 225 // Quad coordinates are unchanged 226 assert_quad_eq(r, quad, *iter.deviceQuad()); 227 if (i % 2 == 0) { 228 ASSERT(iter.isLocalValid()); 229 assert_quad_eq(r, quad, *iter.localQuad()); 230 } else { 231 ASSERT(!iter.isLocalValid()); 232 ASSERT(!iter.localQuad()); 233 } 234 i++; 235 } 236 ASSERTF(i == kQuadCount, "Expected %d iterations, got: %d", kQuadCount, i); 237} 238