ARM NEON Compositor  master
Fast SIMD alpha overlay and blending for ARM
test-overlay_alpha.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
2 
3 #include "../src/rescale.hpp"
5 
6 #include <algorithm>
7 #include <cmath>
8 #include <limits>
9 #include <numeric>
10 #include <vector>
11 
12 #if ENABLE_NEON
13 
14 TEST(overlay_alpha, rescale_div256_floor) {
15  std::vector<uint16_t> in(1ul << 16);
16  std::iota(std::begin(in), std::end(in),
17  std::numeric_limits<uint16_t>::min());
18  std::vector<uint8_t> expected(in.size());
19  std::vector<uint8_t> result(in.size());
20 
21  for (size_t i = 0; i < in.size(); i += 8) {
22  vst1_u8(&result[i], div256_floor(vld1q_u16(&in[i])));
23  for (size_t j = 0; j < 8; ++j) {
24  expected[i + j] = in[i + j] / 256;
25  }
26  }
27  EXPECT_EQ(result, expected);
28 }
29 
30 TEST(overlay_alpha, rescale_div256_round) {
31  std::vector<uint16_t> in(1ul << 16);
32  std::iota(std::begin(in), std::end(in),
33  std::numeric_limits<uint16_t>::min());
34  std::vector<uint8_t> expected(in.size());
35  std::vector<uint8_t> result(in.size());
36 
37  for (size_t i = 0; i < in.size(); i += 8) {
38  vst1_u8(&result[i], div256_round(vld1q_u16(&in[i])));
39  for (size_t j = 0; j < 8; ++j) {
40  expected[i + j] = std::round(in[i + j] / 256.);
41  }
42  }
43  EXPECT_EQ(result, expected);
44 }
45 
46 TEST(overlay_alpha, rescale_div255_floor) {
47  std::vector<uint16_t> in(1ul << 16);
48  std::iota(std::begin(in), std::end(in),
49  std::numeric_limits<uint16_t>::min());
50  std::vector<uint8_t> expected(in.size());
51  std::vector<uint8_t> result(in.size());
52 
53  for (size_t i = 0; i < in.size(); i += 8) {
54  vst1_u8(&result[i], div255_floor(vld1q_u16(&in[i])));
55  for (size_t j = 0; j < 8; ++j) {
56  expected[i + j] = in[i + j] / 255;
57  }
58  }
59  EXPECT_EQ(result, expected);
60 }
61 
62 TEST(overlay_alpha, rescale_div255_round) {
63  std::vector<uint16_t> in((1ul << 16) - 128);
64  std::iota(std::begin(in), std::end(in),
65  std::numeric_limits<uint16_t>::min());
66  std::vector<uint8_t> expected(in.size());
67  std::vector<uint8_t> result(in.size());
68 
69  for (size_t i = 0; i < in.size(); i += 8) {
70  vst1_u8(&result[i], div255_round(vld1q_u16(&in[i])));
71  for (size_t j = 0; j < 8; ++j) {
72  expected[i + j] = std::round(in[i + j] / 255.);
73  }
74  }
75  EXPECT_EQ(result, expected);
76 }
77 
78 TEST(overlay_alpha, rescale_div255_round_approx) {
79  std::vector<uint16_t> in(1ul << 16);
80  std::iota(std::begin(in), std::end(in),
81  std::numeric_limits<uint16_t>::min());
82  std::vector<uint8_t> expected(in.size());
83  std::vector<uint8_t> result(in.size());
84 
85  for (size_t i = 0; i < in.size(); i += 8) {
86  vst1_u8(&result[i], div255_round_approx(vld1q_u16(&in[i])));
87  for (size_t j = 0; j < 8; ++j) {
88  expected[i + j] = std::round(in[i + j] / 255.);
89  }
90  }
91  std::vector<int8_t> differences(in.size());
92  std::transform(std::begin(expected), std::end(expected), std::begin(result),
93  differences.begin(), std::minus<>());
94  auto errors = std::count_if(differences.begin(), differences.end(),
95  [](int8_t d) { return d != 0; });
96  EXPECT_LE(errors, 127);
97  EXPECT_LE(*std::max_element(differences.begin(), differences.end()), 0);
98  EXPECT_GE(*std::min_element(differences.begin(), differences.end()), -1);
99 }
100 
101 #endif
102 
103 TEST(overlay_alpha, rescale_div256_floor_1) {
104  std::vector<uint16_t> in(1ul << 16);
105  std::iota(std::begin(in), std::end(in),
106  std::numeric_limits<uint16_t>::min());
107  std::vector<uint8_t> expected(in.size());
108  std::vector<uint8_t> result(in.size());
109 
110  for (size_t i = 0; i < in.size(); i += 1) {
111  result[i] = div256_floor(in[i]);
112  expected[i] = in[i] / 256;
113  }
114  EXPECT_EQ(result, expected);
115 }
116 
117 TEST(overlay_alpha, rescale_div256_round_1) {
118  std::vector<uint16_t> in((1ul << 16) - 128);
119  std::iota(std::begin(in), std::end(in),
120  std::numeric_limits<uint16_t>::min());
121  std::vector<uint8_t> expected(in.size());
122  std::vector<uint8_t> result(in.size());
123 
124  for (size_t i = 0; i < in.size(); i += 1) {
125  result[i] = div256_round(in[i]);
126  expected[i] = std::round(in[i] / 256.);
127  }
128  EXPECT_EQ(result, expected);
129 }
130 
131 TEST(overlay_alpha, rescale_div255_floor_1) {
132  std::vector<uint16_t> in(1ul << 16);
133  std::iota(std::begin(in), std::end(in),
134  std::numeric_limits<uint16_t>::min());
135  std::vector<uint8_t> expected(in.size());
136  std::vector<uint8_t> result(in.size());
137 
138  for (size_t i = 0; i < in.size(); i += 1) {
139  result[i] = div255_floor(in[i]);
140  expected[i] = in[i] / 255;
141  }
142  EXPECT_EQ(result, expected);
143 }
144 
145 TEST(overlay_alpha, rescale_div255_round_1) {
146  std::vector<uint16_t> in((1ul << 16) - 128);
147  std::iota(std::begin(in), std::end(in),
148  std::numeric_limits<uint16_t>::min());
149  std::vector<uint8_t> expected(in.size());
150  std::vector<uint8_t> result(in.size());
151 
152  for (size_t i = 0; i < in.size(); i += 1) {
153  result[i] = div255_round(in[i]);
154  expected[i] = std::round(in[i] / 255.);
155  }
156  EXPECT_EQ(result, expected);
157 }
158 
159 TEST(overlay_alpha, rescale_div255_round_approx_1) {
160  std::vector<uint16_t> in((1ul << 16) - 128);
161  std::iota(std::begin(in), std::end(in),
162  std::numeric_limits<uint16_t>::min());
163  std::vector<uint8_t> expected(in.size());
164  std::vector<uint8_t> result(in.size());
165 
166  for (size_t i = 0; i < in.size(); i += 1) {
167  result[i] = div255_round_approx(in[i]);
168  expected[i] = std::round(in[i] / 255.);
169  }
170  std::vector<int8_t> differences(in.size());
171  std::transform(std::begin(expected), std::end(expected), std::begin(result),
172  differences.begin(), std::minus<>());
173  auto errors = std::count_if(differences.begin(), differences.end(),
174  [](int8_t d) { return d != 0; });
175  EXPECT_LE(errors, 127);
176  EXPECT_LE(*std::max_element(differences.begin(), differences.end()), 0);
177  EXPECT_GE(*std::min_element(differences.begin(), differences.end()), -1);
178 }
TEST
TEST(overlay_alpha, rescale_div256_floor)
Definition: test-overlay_alpha.cpp:14
div255_floor
uint8x8_t div255_floor(uint16x8_t x)
This is an exact flooring division by 255, this is the correct divisor, but requires a little bit mor...
Definition: rescale.hpp:37
overlay_alpha.hpp
div256_round
uint8x8_t div256_round(uint16x8_t x)
This is a rounding division by 256, which is close enough to 255, but the result may be one bit too s...
Definition: rescale.hpp:22
div256_floor
uint8x8_t div256_floor(uint16x8_t x)
This is a flooring division by 256, which is close enough to 255, but the result may be one bit too s...
Definition: rescale.hpp:16
perf_test.overlay_alpha
overlay_alpha
Definition: perf_test.py:91
div255_round
uint8x8_t div255_round(uint16x8_t x)
This is an exact rounding division by 255, this is the correct divisor, and the result is rounded cor...
Definition: rescale.hpp:76
div255_round_approx
uint8x8_t div255_round_approx(uint16x8_t x)
This is an approximation of a rounding division by 255, this is the correct divisor,...
Definition: rescale.hpp:57