OLD | NEW |
| (Empty) |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/timer/elapsed_timer.h" | |
6 #include "platform/image-encoders/RGBAtoRGB.h" | |
7 #include "platform/wtf/build_config.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 | |
10 namespace blink { | |
11 | |
12 class RGBAtoRGBTest : public ::testing::Test { | |
13 public: | |
14 RGBAtoRGBTest() {} | |
15 }; | |
16 | |
17 static const size_t kChannelsRGBA = 4; | |
18 static const size_t kChannelsRGB = 3; | |
19 | |
20 inline size_t CalculateRGBAPixels(size_t input_buffer_size) { | |
21 size_t pixels = input_buffer_size / kChannelsRGBA; | |
22 return pixels; | |
23 } | |
24 | |
25 inline size_t CalculateRGBOutputSize(size_t input_buffer_size) { | |
26 size_t pixels = CalculateRGBAPixels(input_buffer_size); | |
27 pixels *= kChannelsRGB; | |
28 return pixels; | |
29 } | |
30 | |
31 TEST_F(RGBAtoRGBTest, testOpaqueCaseEven8pixels) { | |
32 unsigned char canvas[] = {255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, | |
33 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 255, | |
34 0, 255, 0, 255, 0, 255, 0, 255, 0, 255}; | |
35 | |
36 unsigned char expected[] = {255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 0, | |
37 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0}; | |
38 // TODO(dcheng): Make this all constexpr. | |
39 #if OS(WIN) | |
40 // Windows release bot can't be reasoned with (compiler error C2131). | |
41 static const constexpr size_t pixels = sizeof(canvas) / kChannelsRGBA; | |
42 static const constexpr size_t rgb_size = pixels * kChannelsRGB; | |
43 #else | |
44 const size_t pixels = CalculateRGBAPixels(sizeof(canvas)); | |
45 const size_t rgb_size = CalculateRGBOutputSize(sizeof(canvas)); | |
46 #endif | |
47 | |
48 unsigned char output[rgb_size]; | |
49 memset(output, 0, rgb_size); | |
50 | |
51 blink::RGBAtoRGB(canvas, static_cast<unsigned>(pixels), output); | |
52 | |
53 EXPECT_EQ(memcmp(expected, output, rgb_size), 0); | |
54 } | |
55 | |
56 #ifdef __ARM_NEON__ | |
57 TEST_F(RGBAtoRGBTest, testCaseEven16pixels) { | |
58 unsigned char canvas[] = { | |
59 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, | |
60 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, | |
61 0, 255, 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, | |
62 128, 0, 0, 255, 128, 0, 0, 255, 128, 128, 128, 128, 128, | |
63 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}; | |
64 | |
65 const size_t pixels = CalculateRGBAPixels(sizeof(canvas)); | |
66 const size_t rgb_size = CalculateRGBOutputSize(sizeof(canvas)); | |
67 unsigned char output[rgb_size]; | |
68 unsigned char expected[rgb_size]; | |
69 memset(output, 0, rgb_size); | |
70 memset(expected, 0, rgb_size); | |
71 | |
72 blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); | |
73 blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); | |
74 | |
75 EXPECT_EQ(memcmp(expected, output, rgb_size), 0); | |
76 } | |
77 | |
78 TEST_F(RGBAtoRGBTest, testCaseOdd17pixels) { | |
79 unsigned char canvas[] = { | |
80 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, | |
81 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, | |
82 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, 0, 0, | |
83 255, 128, 0, 0, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
84 128, 128, 128, 128, 128, 128, 128, 128, 10, 10, 10, 100}; | |
85 | |
86 const size_t pixels = CalculateRGBAPixels(sizeof(canvas)); | |
87 const size_t rgb_size = CalculateRGBOutputSize(sizeof(canvas)); | |
88 unsigned char output[rgb_size]; | |
89 unsigned char expected[rgb_size]; | |
90 memset(output, 0, rgb_size); | |
91 memset(expected, 0, rgb_size); | |
92 | |
93 blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); | |
94 blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); | |
95 | |
96 EXPECT_EQ(memcmp(expected, output, rgb_size), 0); | |
97 } | |
98 | |
99 TEST_F(RGBAtoRGBTest, testCaseEven32pixels) { | |
100 unsigned char canvas[] = { | |
101 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, | |
102 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, | |
103 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, 0, 0, 255, 128, 0, | |
104 0, 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, | |
105 128, 128, 128, 128, 128, 128, 128, 255, 128, 128, 128, 255, 128, 128, 128, | |
106 255, 128, 128, 128, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, | |
107 0, 255, 255, 0, 0, 255, 0, 255, 0, 255, 0, 255, 0, 255, 0, | |
108 255, 0, 255, 0, 255, 0, 255, 0, 0, 255, 128, 0, 0, 255, 128, | |
109 0, 0, 255, 128, 0, 0, 255, 128}; | |
110 | |
111 const size_t pixels = CalculateRGBAPixels(sizeof(canvas)); | |
112 const size_t rgb_size = CalculateRGBOutputSize(sizeof(canvas)); | |
113 unsigned char output[rgb_size]; | |
114 unsigned char expected[rgb_size]; | |
115 memset(output, 0, rgb_size); | |
116 memset(expected, 0, rgb_size); | |
117 | |
118 blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); | |
119 blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); | |
120 | |
121 EXPECT_EQ(memcmp(expected, output, rgb_size), 0); | |
122 } | |
123 | |
124 static base::TimeDelta TestNpixels(bool fast_path = true, | |
125 const size_t width = 1024, | |
126 const size_t height = 1024, | |
127 bool set_alpha = true) { | |
128 const size_t pixels = width * height; | |
129 const size_t canvas_len = kChannelsRGBA * width * height; | |
130 const size_t output_len = kChannelsRGB * width * height; | |
131 unsigned char* canvas = new unsigned char[canvas_len]; | |
132 unsigned char* output = new unsigned char[output_len]; | |
133 | |
134 auto cleanup = [&]() { | |
135 if (canvas) | |
136 delete[] canvas; | |
137 if (output) | |
138 delete[] output; | |
139 }; | |
140 | |
141 if (!canvas || !output) { | |
142 cleanup(); | |
143 return base::TimeDelta(); | |
144 } | |
145 | |
146 if (set_alpha) { | |
147 memset(canvas, 128, canvas_len); | |
148 } else { | |
149 memset(canvas, 200, canvas_len); | |
150 } | |
151 | |
152 base::ElapsedTimer run_time; | |
153 if (fast_path) { | |
154 blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); | |
155 } else { | |
156 blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), output); | |
157 } | |
158 | |
159 auto result = run_time.Elapsed(); | |
160 cleanup(); | |
161 return result; | |
162 } | |
163 | |
164 TEST_F(RGBAtoRGBTest, testPerf1k) { | |
165 auto neon_elapsed = TestNpixels(); | |
166 auto scalar_elapsed = TestNpixels(false); | |
167 | |
168 EXPECT_TRUE(neon_elapsed < scalar_elapsed) | |
169 << "Neon: " << neon_elapsed << "\tScalar: " << scalar_elapsed | |
170 << std::endl; | |
171 } | |
172 | |
173 TEST_F(RGBAtoRGBTest, testPerf4k) { | |
174 auto neon_elapsed = TestNpixels(true, 4000, 4000); | |
175 auto scalar_elapsed = TestNpixels(false, 4000, 4000); | |
176 | |
177 EXPECT_TRUE(neon_elapsed < scalar_elapsed) | |
178 << "Neon: " << neon_elapsed << "\tScalar: " << scalar_elapsed | |
179 << std::endl; | |
180 } | |
181 | |
182 // This width will force the tail case, cause width = (16 * 64) + 15. | |
183 static bool TestRandNpixels(const size_t width = 1039, | |
184 const size_t height = 1024, | |
185 bool set_alpha = true) { | |
186 const size_t pixels = width * height; | |
187 const size_t canvas_len = kChannelsRGBA * pixels; | |
188 const size_t output_len = kChannelsRGB * pixels; | |
189 unsigned char* canvas = new unsigned char[canvas_len]; | |
190 unsigned char* expected = new unsigned char[output_len]; | |
191 unsigned char* output = new unsigned char[output_len]; | |
192 | |
193 auto cleanup = [&]() { | |
194 if (canvas) | |
195 delete[] canvas; | |
196 if (expected) | |
197 delete[] expected; | |
198 if (output) | |
199 delete[] output; | |
200 }; | |
201 | |
202 if (!canvas || !output || !expected) { | |
203 cleanup(); | |
204 return false; | |
205 } | |
206 | |
207 if (set_alpha) { | |
208 memset(canvas, 128, canvas_len); | |
209 } else { | |
210 memset(canvas, 200, canvas_len); | |
211 } | |
212 | |
213 srand(time(0)); | |
214 unsigned char* ptr = canvas; | |
215 for (size_t i = 0; i < pixels; ++i) { | |
216 *ptr++ = static_cast<unsigned char>(rand() % 255); | |
217 *ptr++ = static_cast<unsigned char>(rand() % 255); | |
218 *ptr++ = static_cast<unsigned char>(rand() % 255); | |
219 *ptr++ = static_cast<unsigned char>(rand() % 255); | |
220 } | |
221 | |
222 blink::RGBAtoRGBScalar(canvas, static_cast<unsigned>(pixels), expected); | |
223 blink::RGBAtoRGBNeon(canvas, static_cast<unsigned>(pixels), output); | |
224 | |
225 bool result = memcmp(expected, output, output_len) == 0; | |
226 | |
227 cleanup(); | |
228 return result; | |
229 } | |
230 | |
231 TEST_F(RGBAtoRGBTest, randomPixels) { | |
232 EXPECT_TRUE(TestRandNpixels()); | |
233 } | |
234 | |
235 #endif | |
236 } // namespace blink | |
OLD | NEW |