| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "Sk4px.h" | 8 #include "Sk4px.h" |
| 9 #include "SkNx.h" | 9 #include "SkNx.h" |
| 10 #include "SkRandom.h" | 10 #include "SkRandom.h" |
| 11 #include "Test.h" | 11 #include "Test.h" |
| 12 | 12 |
| 13 template <int N> | 13 template <int N> |
| 14 static void test_Nf(skiatest::Reporter* r) { | 14 static void test_Nf(skiatest::Reporter* r) { |
| 15 | 15 |
| 16 auto assert_nearly_eq = [&](float eps, const SkNx<N, float>& v, | 16 auto assert_nearly_eq = [&](float eps, const SkNx<N, float>& v, |
| 17 float a, float b, float c, float d) { | 17 float a, float b, float c, float d) { |
| 18 auto close = [=](float a, float b) { return fabsf(a-b) <= eps; }; | 18 auto close = [=](float a, float b) { return fabsf(a-b) <= eps; }; |
| 19 float vals[4]; | 19 float vals[4]; |
| 20 v.store(vals); | 20 v.store(vals); |
| 21 bool ok = close(vals[0], a) && close(vals[1], b) | 21 bool ok = close(vals[0], a) && close(vals[1], b) |
| 22 && close(v.template kth<0>(), a) && close(v.template kth<1>(), b)
; | 22 && close( v[0], a) && close( v[1], b); |
| 23 REPORTER_ASSERT(r, ok); | 23 REPORTER_ASSERT(r, ok); |
| 24 if (N == 4) { | 24 if (N == 4) { |
| 25 ok = close(vals[2], c) && close(vals[3], d) | 25 ok = close(vals[2], c) && close(vals[3], d) |
| 26 && close(v.template kth<2>(), c) && close(v.template kth<3>(), d); | 26 && close( v[2], c) && close( v[3], d); |
| 27 REPORTER_ASSERT(r, ok); | 27 REPORTER_ASSERT(r, ok); |
| 28 } | 28 } |
| 29 }; | 29 }; |
| 30 auto assert_eq = [&](const SkNx<N, float>& v, float a, float b, float c, flo
at d) { | 30 auto assert_eq = [&](const SkNx<N, float>& v, float a, float b, float c, flo
at d) { |
| 31 return assert_nearly_eq(0, v, a,b,c,d); | 31 return assert_nearly_eq(0, v, a,b,c,d); |
| 32 }; | 32 }; |
| 33 | 33 |
| 34 float vals[] = {3, 4, 5, 6}; | 34 float vals[] = {3, 4, 5, 6}; |
| 35 SkNx<N,float> a = SkNx<N,float>::Load(vals), | 35 SkNx<N,float> a = SkNx<N,float>::Load(vals), |
| 36 b(a), | 36 b(a), |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 auto assert_eq = [&](const SkNx<N,T>& v, T a, T b, T c, T d, T e, T f, T g,
T h) { | 85 auto assert_eq = [&](const SkNx<N,T>& v, T a, T b, T c, T d, T e, T f, T g,
T h) { |
| 86 T vals[8]; | 86 T vals[8]; |
| 87 v.store(vals); | 87 v.store(vals); |
| 88 | 88 |
| 89 switch (N) { | 89 switch (N) { |
| 90 case 8: REPORTER_ASSERT(r, vals[4] == e && vals[5] == f && vals[6] ==
g && vals[7] == h); | 90 case 8: REPORTER_ASSERT(r, vals[4] == e && vals[5] == f && vals[6] ==
g && vals[7] == h); |
| 91 case 4: REPORTER_ASSERT(r, vals[2] == c && vals[3] == d); | 91 case 4: REPORTER_ASSERT(r, vals[2] == c && vals[3] == d); |
| 92 case 2: REPORTER_ASSERT(r, vals[0] == a && vals[1] == b); | 92 case 2: REPORTER_ASSERT(r, vals[0] == a && vals[1] == b); |
| 93 } | 93 } |
| 94 switch (N) { | 94 switch (N) { |
| 95 case 8: REPORTER_ASSERT(r, v.template kth<4>() == e && v.template kth<
5>() == f && | 95 case 8: REPORTER_ASSERT(r, v[4] == e && v[5] == f && |
| 96 v.template kth<6>() == g && v.template kth<
7>() == h); | 96 v[6] == g && v[7] == h); |
| 97 case 4: REPORTER_ASSERT(r, v.template kth<2>() == c && v.template kth<
3>() == d); | 97 case 4: REPORTER_ASSERT(r, v[2] == c && v[3] == d); |
| 98 case 2: REPORTER_ASSERT(r, v.template kth<0>() == a && v.template kth<
1>() == b); | 98 case 2: REPORTER_ASSERT(r, v[0] == a && v[1] == b); |
| 99 } | 99 } |
| 100 }; | 100 }; |
| 101 | 101 |
| 102 T vals[] = { 1,2,3,4,5,6,7,8 }; | 102 T vals[] = { 1,2,3,4,5,6,7,8 }; |
| 103 SkNx<N,T> a = SkNx<N,T>::Load(vals), | 103 SkNx<N,T> a = SkNx<N,T>::Load(vals), |
| 104 b(a), | 104 b(a), |
| 105 c = a; | 105 c = a; |
| 106 SkNx<N,T> d; | 106 SkNx<N,T> d; |
| 107 d = a; | 107 d = a; |
| 108 | 108 |
| 109 assert_eq(a, 1,2,3,4,5,6,7,8); | 109 assert_eq(a, 1,2,3,4,5,6,7,8); |
| 110 assert_eq(b, 1,2,3,4,5,6,7,8); | 110 assert_eq(b, 1,2,3,4,5,6,7,8); |
| 111 assert_eq(c, 1,2,3,4,5,6,7,8); | 111 assert_eq(c, 1,2,3,4,5,6,7,8); |
| 112 assert_eq(d, 1,2,3,4,5,6,7,8); | 112 assert_eq(d, 1,2,3,4,5,6,7,8); |
| 113 | 113 |
| 114 assert_eq(a+a, 2,4,6,8,10,12,14,16); | 114 assert_eq(a+a, 2,4,6,8,10,12,14,16); |
| 115 assert_eq(a*a, 1,4,9,16,25,36,49,64); | 115 assert_eq(a*a, 1,4,9,16,25,36,49,64); |
| 116 assert_eq(a*a-a, 0,2,6,12,20,30,42,56); | 116 assert_eq(a*a-a, 0,2,6,12,20,30,42,56); |
| 117 | 117 |
| 118 assert_eq(a >> 2, 0,0,0,1,1,1,1,2); | 118 assert_eq(a >> 2, 0,0,0,1,1,1,1,2); |
| 119 assert_eq(a << 1, 2,4,6,8,10,12,14,16); | 119 assert_eq(a << 1, 2,4,6,8,10,12,14,16); |
| 120 | 120 |
| 121 REPORTER_ASSERT(r, a.template kth<1>() == 2); | 121 REPORTER_ASSERT(r, a[1] == 2); |
| 122 } | 122 } |
| 123 | 123 |
| 124 DEF_TEST(SkNx, r) { | 124 DEF_TEST(SkNx, r) { |
| 125 test_Ni<2, uint16_t>(r); | 125 test_Ni<2, uint16_t>(r); |
| 126 test_Ni<4, uint16_t>(r); | 126 test_Ni<4, uint16_t>(r); |
| 127 test_Ni<8, uint16_t>(r); | 127 test_Ni<8, uint16_t>(r); |
| 128 | 128 |
| 129 test_Ni<2, int>(r); | 129 test_Ni<2, int>(r); |
| 130 test_Ni<4, int>(r); | 130 test_Ni<4, int>(r); |
| 131 test_Ni<8, int>(r); | 131 test_Ni<8, int>(r); |
| 132 } | 132 } |
| 133 | 133 |
| 134 DEF_TEST(SkNi_min_lt, r) { | 134 DEF_TEST(SkNi_min_lt, r) { |
| 135 // Exhaustively check the 8x8 bit space. | 135 // Exhaustively check the 8x8 bit space. |
| 136 for (int a = 0; a < (1<<8); a++) { | 136 for (int a = 0; a < (1<<8); a++) { |
| 137 for (int b = 0; b < (1<<8); b++) { | 137 for (int b = 0; b < (1<<8); b++) { |
| 138 Sk16b aw(a), bw(b); | 138 Sk16b aw(a), bw(b); |
| 139 REPORTER_ASSERT(r, Sk16b::Min(aw, bw).kth<0>() == SkTMin(a, b)); | 139 REPORTER_ASSERT(r, Sk16b::Min(aw, bw)[0] == SkTMin(a, b)); |
| 140 REPORTER_ASSERT(r, !(aw < bw).kth<0>() == !(a < b)); | 140 REPORTER_ASSERT(r, !(aw < bw)[0] == !(a < b)); |
| 141 }} | 141 }} |
| 142 | 142 |
| 143 // Exhausting the 16x16 bit space is kind of slow, so only do that in releas
e builds. | 143 // Exhausting the 16x16 bit space is kind of slow, so only do that in releas
e builds. |
| 144 #ifdef SK_DEBUG | 144 #ifdef SK_DEBUG |
| 145 SkRandom rand; | 145 SkRandom rand; |
| 146 for (int i = 0; i < (1<<16); i++) { | 146 for (int i = 0; i < (1<<16); i++) { |
| 147 uint16_t a = rand.nextU() >> 16, | 147 uint16_t a = rand.nextU() >> 16, |
| 148 b = rand.nextU() >> 16; | 148 b = rand.nextU() >> 16; |
| 149 REPORTER_ASSERT(r, Sk16h::Min(Sk16h(a), Sk16h(b)).kth<0>() == SkTMin(a,
b)); | 149 REPORTER_ASSERT(r, Sk16h::Min(Sk16h(a), Sk16h(b))[0] == SkTMin(a, b)); |
| 150 } | 150 } |
| 151 #else | 151 #else |
| 152 for (int a = 0; a < (1<<16); a++) { | 152 for (int a = 0; a < (1<<16); a++) { |
| 153 for (int b = 0; b < (1<<16); b++) { | 153 for (int b = 0; b < (1<<16); b++) { |
| 154 REPORTER_ASSERT(r, Sk16h::Min(Sk16h(a), Sk16h(b)).kth<0>() == SkTMin(a,
b)); | 154 REPORTER_ASSERT(r, Sk16h::Min(Sk16h(a), Sk16h(b))[0] == SkTMin(a, b)); |
| 155 }} | 155 }} |
| 156 #endif | 156 #endif |
| 157 } | 157 } |
| 158 | 158 |
| 159 DEF_TEST(SkNi_saturatedAdd, r) { | 159 DEF_TEST(SkNi_saturatedAdd, r) { |
| 160 for (int a = 0; a < (1<<8); a++) { | 160 for (int a = 0; a < (1<<8); a++) { |
| 161 for (int b = 0; b < (1<<8); b++) { | 161 for (int b = 0; b < (1<<8); b++) { |
| 162 int exact = a+b; | 162 int exact = a+b; |
| 163 if (exact > 255) { exact = 255; } | 163 if (exact > 255) { exact = 255; } |
| 164 if (exact < 0) { exact = 0; } | 164 if (exact < 0) { exact = 0; } |
| 165 | 165 |
| 166 REPORTER_ASSERT(r, Sk16b(a).saturatedAdd(Sk16b(b)).kth<0>() == exact); | 166 REPORTER_ASSERT(r, Sk16b(a).saturatedAdd(Sk16b(b))[0] == exact); |
| 167 } | 167 } |
| 168 } | 168 } |
| 169 } | 169 } |
| 170 | 170 |
| 171 DEF_TEST(Sk4px_muldiv255round, r) { | 171 DEF_TEST(Sk4px_muldiv255round, r) { |
| 172 for (int a = 0; a < (1<<8); a++) { | 172 for (int a = 0; a < (1<<8); a++) { |
| 173 for (int b = 0; b < (1<<8); b++) { | 173 for (int b = 0; b < (1<<8); b++) { |
| 174 int exact = (a*b+127)/255; | 174 int exact = (a*b+127)/255; |
| 175 | 175 |
| 176 // Duplicate a and b 16x each. | 176 // Duplicate a and b 16x each. |
| 177 auto av = Sk4px::DupAlpha(a), | 177 auto av = Sk4px::DupAlpha(a), |
| 178 bv = Sk4px::DupAlpha(b); | 178 bv = Sk4px::DupAlpha(b); |
| 179 | 179 |
| 180 // This way should always be exactly correct. | 180 // This way should always be exactly correct. |
| 181 int correct = (av * bv).div255().kth<0>(); | 181 int correct = (av * bv).div255()[0]; |
| 182 REPORTER_ASSERT(r, correct == exact); | 182 REPORTER_ASSERT(r, correct == exact); |
| 183 | 183 |
| 184 // We're a bit more flexible on this method: correct for 0 or 255, other
wise off by <=1. | 184 // We're a bit more flexible on this method: correct for 0 or 255, other
wise off by <=1. |
| 185 int fast = av.approxMulDiv255(bv).kth<0>(); | 185 int fast = av.approxMulDiv255(bv)[0]; |
| 186 REPORTER_ASSERT(r, fast-exact >= -1 && fast-exact <= 1); | 186 REPORTER_ASSERT(r, fast-exact >= -1 && fast-exact <= 1); |
| 187 if (a == 0 || a == 255 || b == 0 || b == 255) { | 187 if (a == 0 || a == 255 || b == 0 || b == 255) { |
| 188 REPORTER_ASSERT(r, fast == exact); | 188 REPORTER_ASSERT(r, fast == exact); |
| 189 } | 189 } |
| 190 } | 190 } |
| 191 } | 191 } |
| 192 } | 192 } |
| 193 | 193 |
| 194 DEF_TEST(Sk4px_widening, r) { | 194 DEF_TEST(Sk4px_widening, r) { |
| 195 SkPMColor colors[] = { | 195 SkPMColor colors[] = { |
| 196 SkPreMultiplyColor(0xff00ff00), | 196 SkPreMultiplyColor(0xff00ff00), |
| 197 SkPreMultiplyColor(0x40008000), | 197 SkPreMultiplyColor(0x40008000), |
| 198 SkPreMultiplyColor(0x7f020406), | 198 SkPreMultiplyColor(0x7f020406), |
| 199 SkPreMultiplyColor(0x00000000), | 199 SkPreMultiplyColor(0x00000000), |
| 200 }; | 200 }; |
| 201 auto packed = Sk4px::Load4(colors); | 201 auto packed = Sk4px::Load4(colors); |
| 202 | 202 |
| 203 auto wideLo = packed.widenLo(), | 203 auto wideLo = packed.widenLo(), |
| 204 wideHi = packed.widenHi(), | 204 wideHi = packed.widenHi(), |
| 205 wideLoHi = packed.widenLoHi(), | 205 wideLoHi = packed.widenLoHi(), |
| 206 wideLoHiAlt = wideLo + wideHi; | 206 wideLoHiAlt = wideLo + wideHi; |
| 207 REPORTER_ASSERT(r, 0 == memcmp(&wideLoHi, &wideLoHiAlt, sizeof(wideLoHi))); | 207 REPORTER_ASSERT(r, 0 == memcmp(&wideLoHi, &wideLoHiAlt, sizeof(wideLoHi))); |
| 208 } | 208 } |
| 209 | 209 |
| 210 DEF_TEST(SkNx_abs, r) { | 210 DEF_TEST(SkNx_abs, r) { |
| 211 auto fs = Sk4f(0.0f, -0.0f, 2.0f, -4.0f).abs(); | 211 auto fs = Sk4f(0.0f, -0.0f, 2.0f, -4.0f).abs(); |
| 212 REPORTER_ASSERT(r, fs.kth<0>() == 0.0f); | 212 REPORTER_ASSERT(r, fs[0] == 0.0f); |
| 213 REPORTER_ASSERT(r, fs.kth<1>() == 0.0f); | 213 REPORTER_ASSERT(r, fs[1] == 0.0f); |
| 214 REPORTER_ASSERT(r, fs.kth<2>() == 2.0f); | 214 REPORTER_ASSERT(r, fs[2] == 2.0f); |
| 215 REPORTER_ASSERT(r, fs.kth<3>() == 4.0f); | 215 REPORTER_ASSERT(r, fs[3] == 4.0f); |
| 216 } | 216 } |
| 217 | 217 |
| 218 DEF_TEST(SkNx_floor, r) { | 218 DEF_TEST(SkNx_floor, r) { |
| 219 auto fs = Sk4f(0.4f, -0.4f, 0.6f, -0.6f).floor(); | 219 auto fs = Sk4f(0.4f, -0.4f, 0.6f, -0.6f).floor(); |
| 220 REPORTER_ASSERT(r, fs.kth<0>() == 0.0f); | 220 REPORTER_ASSERT(r, fs[0] == 0.0f); |
| 221 REPORTER_ASSERT(r, fs.kth<1>() == -1.0f); | 221 REPORTER_ASSERT(r, fs[1] == -1.0f); |
| 222 REPORTER_ASSERT(r, fs.kth<2>() == 0.0f); | 222 REPORTER_ASSERT(r, fs[2] == 0.0f); |
| 223 REPORTER_ASSERT(r, fs.kth<3>() == -1.0f); | 223 REPORTER_ASSERT(r, fs[3] == -1.0f); |
| 224 } | 224 } |
| 225 | 225 |
| 226 DEF_TEST(SkNx_shuffle, r) { | 226 DEF_TEST(SkNx_shuffle, r) { |
| 227 Sk4f f4(0,10,20,30); | 227 Sk4f f4(0,10,20,30); |
| 228 | 228 |
| 229 Sk2f f2 = SkNx_shuffle<2,1>(f4); | 229 Sk2f f2 = SkNx_shuffle<2,1>(f4); |
| 230 REPORTER_ASSERT(r, f2[0] == 20); | 230 REPORTER_ASSERT(r, f2[0] == 20); |
| 231 REPORTER_ASSERT(r, f2[1] == 10); | 231 REPORTER_ASSERT(r, f2[1] == 10); |
| 232 | 232 |
| 233 f4 = SkNx_shuffle<0,1,1,0>(f2); | 233 f4 = SkNx_shuffle<0,1,1,0>(f2); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 253 REPORTER_ASSERT(r, f[3] == 0.0f); | 253 REPORTER_ASSERT(r, f[3] == 0.0f); |
| 254 } | 254 } |
| 255 | 255 |
| 256 #include "SkRandom.h" | 256 #include "SkRandom.h" |
| 257 | 257 |
| 258 DEF_TEST(SkNx_u16_float, r) { | 258 DEF_TEST(SkNx_u16_float, r) { |
| 259 { | 259 { |
| 260 // u16 --> float | 260 // u16 --> float |
| 261 auto h4 = Sk4h(15, 17, 257, 65535); | 261 auto h4 = Sk4h(15, 17, 257, 65535); |
| 262 auto f4 = SkNx_cast<float>(h4); | 262 auto f4 = SkNx_cast<float>(h4); |
| 263 REPORTER_ASSERT(r, f4.kth<0>() == 15.0f); | 263 REPORTER_ASSERT(r, f4[0] == 15.0f); |
| 264 REPORTER_ASSERT(r, f4.kth<1>() == 17.0f); | 264 REPORTER_ASSERT(r, f4[1] == 17.0f); |
| 265 REPORTER_ASSERT(r, f4.kth<2>() == 257.0f); | 265 REPORTER_ASSERT(r, f4[2] == 257.0f); |
| 266 REPORTER_ASSERT(r, f4.kth<3>() == 65535.0f); | 266 REPORTER_ASSERT(r, f4[3] == 65535.0f); |
| 267 } | 267 } |
| 268 { | 268 { |
| 269 // float -> u16 | 269 // float -> u16 |
| 270 auto f4 = Sk4f(15, 17, 257, 65535); | 270 auto f4 = Sk4f(15, 17, 257, 65535); |
| 271 auto h4 = SkNx_cast<uint16_t>(f4); | 271 auto h4 = SkNx_cast<uint16_t>(f4); |
| 272 REPORTER_ASSERT(r, h4.kth<0>() == 15); | 272 REPORTER_ASSERT(r, h4[0] == 15); |
| 273 REPORTER_ASSERT(r, h4.kth<1>() == 17); | 273 REPORTER_ASSERT(r, h4[1] == 17); |
| 274 REPORTER_ASSERT(r, h4.kth<2>() == 257); | 274 REPORTER_ASSERT(r, h4[2] == 257); |
| 275 REPORTER_ASSERT(r, h4.kth<3>() == 65535); | 275 REPORTER_ASSERT(r, h4[3] == 65535); |
| 276 } | 276 } |
| 277 | 277 |
| 278 // starting with any u16 value, we should be able to have a perfect round-tr
ip in/out of floats | 278 // starting with any u16 value, we should be able to have a perfect round-tr
ip in/out of floats |
| 279 // | 279 // |
| 280 SkRandom rand; | 280 SkRandom rand; |
| 281 for (int i = 0; i < 10000; ++i) { | 281 for (int i = 0; i < 10000; ++i) { |
| 282 const uint16_t s16[4] { | 282 const uint16_t s16[4] { |
| 283 (uint16_t)rand.nextU16(), (uint16_t)rand.nextU16(), | 283 (uint16_t)rand.nextU16(), (uint16_t)rand.nextU16(), |
| 284 (uint16_t)rand.nextU16(), (uint16_t)rand.nextU16(), | 284 (uint16_t)rand.nextU16(), (uint16_t)rand.nextU16(), |
| 285 }; | 285 }; |
| 286 auto u4_0 = Sk4h::Load(s16); | 286 auto u4_0 = Sk4h::Load(s16); |
| 287 auto f4 = SkNx_cast<float>(u4_0); | 287 auto f4 = SkNx_cast<float>(u4_0); |
| 288 auto u4_1 = SkNx_cast<uint16_t>(f4); | 288 auto u4_1 = SkNx_cast<uint16_t>(f4); |
| 289 uint16_t d16[4]; | 289 uint16_t d16[4]; |
| 290 u4_1.store(d16); | 290 u4_1.store(d16); |
| 291 REPORTER_ASSERT(r, !memcmp(s16, d16, sizeof(s16))); | 291 REPORTER_ASSERT(r, !memcmp(s16, d16, sizeof(s16))); |
| 292 } | 292 } |
| 293 } | 293 } |
| OLD | NEW |