Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(257)

Side by Side Diff: remoting/host/differ_unittest.cc

Issue 2714007: Initial code for screen differ that divides screen into blocks and calculate... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « remoting/host/differ.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright (c) 2010 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/scoped_ptr.h"
6 #include "remoting/host/differ.h"
7 #include "testing/gmock/include/gmock/gmock.h"
8
9 namespace remoting {
10
11 // 96x96 screen gives a 3x3 grid of blocks.
12 const int kScreenWidth = 96;
13 const int kScreenHeight = 96;
14 const int kBytesPerPixel = 3;
15
16 class DifferTest : public testing::Test {
17 public:
18 DifferTest() {
19 }
20
21 protected:
22 virtual void SetUp() {
23 InitDiffer(kScreenWidth, kScreenHeight, kBytesPerPixel);
24 }
25
26 void InitDiffer(int width, int height, int bpp) {
27 width_ = width;
28 height_ = height;
29 bytes_per_pixel_ = bpp;
30
31 stride_ = width_ * bytes_per_pixel_;
32 buffer_size_ = width_ * height_ * bytes_per_pixel_;
33
34 differ_.reset(new Differ(width_, height_, bytes_per_pixel_));
35
36 prev_.reset(new uint8[buffer_size_]);
37 memset(prev_.get(), 0, buffer_size_);
38
39 curr_.reset(new uint8[buffer_size_]);
40 memset(curr_.get(), 0, buffer_size_);
41 }
42
43 void ClearBuffer(uint8* buffer) {
44 memset(buffer, 0, buffer_size_);
45 }
46
47 // Convenience wrapper for Differ's DiffBlock that calculates the appropriate
48 // offset to the start of the desired block.
49 DiffInfo DiffBlock(int block_x, int block_y) {
50 // Offset from upper-left of buffer to upper-left of requested block.
51 int block_offset = ((block_y * stride_) + (block_x * bytes_per_pixel_))
52 * kBlockSize;
53 differ_->DiffBlock(prev_.get() + block_offset,
54 curr_.get() + block_offset,
55 stride_);
56 }
57
58 // Write the pixel |value| into the specified block in the |buffer|.
59 // This is a convenience wrapper around WritePixel().
60 void WriteBlockPixel(uint8* buffer, int block_x, int block_y,
61 int pixel_x, int pixel_y, uint32 value) {
62 WritePixel(buffer, (block_x * kBlockSize) + pixel_x,
63 (block_y * kBlockSize) + pixel_y, value);
64 }
65
66 // Write the test pixel |value| into the |buffer| at the specified |x|,|y|
67 // location.
68 // Only the low-order bytes from |value| are written (assuming little-endian).
69 // So, for |value| = 0xaabbccdd:
70 // If bytes_per_pixel = 4, then ddccbbaa will be written as the pixel value.
71 // If = 3, ddccbb
72 // If = 2, ddcc
73 // If = 1, dd
74 void WritePixel(uint8* buffer, int x, int y, uint32 value) {
75 uint8* pixel = reinterpret_cast<uint8*>(&value);
76 buffer += (y * stride_) + (x * bytes_per_pixel_);
77 for (int b = bytes_per_pixel_ - 1; b >= 0; b--) {
78 *buffer++ = pixel[b];
79 }
80 }
81
82 // DiffInfo utility routines.
83 // These are here so that we don't have to make each DifferText_Xxx_Test
84 // class a friend class to Differ.
85
86 // Clear out the entire |diff_info_| buffer.
87 void ClearDiffInfo() {
88 memset(differ_->diff_info_.get(), 0, differ_->diff_info_size_);
89 }
90
91 // Get the value in the |diff_info_| array at (x,y).
92 DiffInfo GetDiffInfo(int x, int y) {
93 DiffInfo* diff_info = differ_->diff_info_.get();
94 return diff_info[(y * GetDiffInfoWidth()) + x];
95 }
96
97 // Width of |diff_info_| array.
98 int GetDiffInfoWidth() {
99 return differ_->diff_info_width_;
100 }
101
102 // Height of |diff_info_| array.
103 int GetDiffInfoHeight() {
104 return differ_->diff_info_height_;
105 }
106
107 // Size of |diff_info_| array.
108 int GetDiffInfoSize() {
109 return differ_->diff_info_size_;
110 }
111
112 void SetDiffInfo(int x, int y, const DiffInfo& value) {
113 DiffInfo* diff_info = differ_->diff_info_.get();
114 diff_info[(y * GetDiffInfoWidth()) + x] = value;
115 }
116
117 // Mark the range of blocks specified.
118 void MarkBlocks(int x_origin, int y_origin, int width, int height) {
119 for (int y = 0; y < height; y++) {
120 for (int x = 0; x < width; x++) {
121 SetDiffInfo(x_origin + x, y_origin + y, 1);
122 }
123 }
124 }
125
126 // Verify that the given dirty rect matches the expected |x|, |y|, |width|
127 // and |height|.
128 // |x|, |y|, |width| and |height| are specified in block (not pixel) units.
129 void CheckDirtyRect(const gfx::Rect& rect, int x, int y,
130 int width, int height) {
131 EXPECT_EQ(x * kBlockSize, rect.x());
132 EXPECT_EQ(y * kBlockSize, rect.y());
133 EXPECT_EQ(width * kBlockSize, rect.width());
134 EXPECT_EQ(height * kBlockSize, rect.height());
135 }
136
137 // Mark the range of blocks specified and then verify that they are
138 // merged correctly.
139 // Only one rectangular region of blocks can be checked with this routine.
140 void MarkBlocksAndCheckMerge(int x_origin, int y_origin,
141 int width, int height) {
142 ClearDiffInfo();
143 MarkBlocks(x_origin, y_origin, width, height);
144
145 DirtyRects* dirty = new DirtyRects();
146 differ_->MergeBlocks(dirty);
147
148 ASSERT_EQ(1, dirty->size());
149 CheckDirtyRect(dirty->at(0), x_origin, y_origin, width, height);
150 }
151
152 // The differ class we're testing.
153 scoped_ptr<Differ> differ_;
154
155 // Screen/buffer info.
156 int width_;
157 int height_;
158 int bytes_per_pixel_;
159 int stride_;
160
161 // Size of each screen buffer.
162 int buffer_size_;
163
164 // Previous and current screen buffers.
165 scoped_ptr<uint8> prev_;
166 scoped_ptr<uint8> curr_;
167
168 private:
169 DISALLOW_COPY_AND_ASSIGN(DifferTest);
170 };
171
172 TEST_F(DifferTest, Setup) {
173 // 96x96 pixels results in 3x3 array. Add 1 to each dimension as boundary.
174 // +---+---+---+---+
175 // | o | o | o | _ |
176 // +---+---+---+---+ o = blocks mapped to screen pixels
177 // | o | o | o | _ |
178 // +---+---+---+---+ _ = boundary blocks
179 // | o | o | o | _ |
180 // +---+---+---+---+
181 // | _ | _ | _ | _ |
182 // +---+---+---+---+
183 EXPECT_EQ(4, GetDiffInfoWidth());
184 EXPECT_EQ(4, GetDiffInfoHeight());
185 EXPECT_EQ(16, GetDiffInfoSize());
186 }
187
188 TEST_F(DifferTest, MarkDirtyBlocks_All) {
189 ClearDiffInfo();
190
191 // Update a pixel in each block.
192 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
193 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
194 WriteBlockPixel(curr_.get(), x, y, 10, 10, 0xff00ff);
195 }
196 }
197
198 differ_->MarkDirtyBlocks(prev_.get(), curr_.get());
199
200 // Make sure each block is marked as dirty.
201 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
202 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
203 EXPECT_EQ(1, GetDiffInfo(x, y))
204 << "when x = " << x << ", and y = " << y;
205 }
206 }
207 }
208
209 TEST_F(DifferTest, MarkDirtyBlocks_Sampling) {
210 ClearDiffInfo();
211
212 // Update some pixels in image.
213 WriteBlockPixel(curr_.get(), 1, 0, 10, 10, 0xff00ff);
214 WriteBlockPixel(curr_.get(), 2, 1, 10, 10, 0xff00ff);
215 WriteBlockPixel(curr_.get(), 0, 2, 10, 10, 0xff00ff);
216
217 differ_->MarkDirtyBlocks(prev_.get(), curr_.get());
218
219 // Make sure corresponding blocks are updated.
220 EXPECT_EQ(0, GetDiffInfo(0, 0));
221 EXPECT_EQ(0, GetDiffInfo(0, 1));
222 EXPECT_EQ(1, GetDiffInfo(0, 2));
223 EXPECT_EQ(1, GetDiffInfo(1, 0));
224 EXPECT_EQ(0, GetDiffInfo(1, 1));
225 EXPECT_EQ(0, GetDiffInfo(1, 2));
226 EXPECT_EQ(0, GetDiffInfo(2, 0));
227 EXPECT_EQ(1, GetDiffInfo(2, 1));
228 EXPECT_EQ(0, GetDiffInfo(2, 2));
229 }
230
231 TEST_F(DifferTest, DiffBlock) {
232 // Verify no differences at start.
233 EXPECT_EQ(0, DiffBlock(0, 0));
234 EXPECT_EQ(0, DiffBlock(1, 1));
235
236 // Write new data into the 4 corners of the middle block and verify that
237 // neighboring blocks are not affected.
238 int max = kBlockSize - 1;
239 WriteBlockPixel(curr_.get(), 1, 1, 0, 0, 0xffffff);
240 WriteBlockPixel(curr_.get(), 1, 1, 0, max, 0xffffff);
241 WriteBlockPixel(curr_.get(), 1, 1, max, 0, 0xffffff);
242 WriteBlockPixel(curr_.get(), 1, 1, max, max, 0xffffff);
243 EXPECT_EQ(0, DiffBlock(0, 0));
244 EXPECT_EQ(0, DiffBlock(0, 1));
245 EXPECT_EQ(0, DiffBlock(0, 2));
246 EXPECT_EQ(0, DiffBlock(1, 0));
247 EXPECT_EQ(1, DiffBlock(1, 1)); // Only this block should change.
248 EXPECT_EQ(0, DiffBlock(1, 2));
249 EXPECT_EQ(0, DiffBlock(2, 0));
250 EXPECT_EQ(0, DiffBlock(2, 1));
251 EXPECT_EQ(0, DiffBlock(2, 2));
252 }
253
254 TEST_F(DifferTest, DiffPartialBlocks) {
255 // TODO(garykac): Add tests for DiffPartialBlock
256 }
257
258
259 TEST_F(DifferTest, MergeBlocks_Empty) {
260 // No blocks marked:
261 // +---+---+---+---+
262 // | | | | _ |
263 // +---+---+---+---+
264 // | | | | _ |
265 // +---+---+---+---+
266 // | | | | _ |
267 // +---+---+---+---+
268 // | _ | _ | _ | _ |
269 // +---+---+---+---+
270 ClearDiffInfo();
271
272 DirtyRects* dirty = new DirtyRects();
273 differ_->MergeBlocks(dirty);
274
275 EXPECT_EQ(0, dirty->size());
276 }
277
278 TEST_F(DifferTest, MergeBlocks_SingleBlock) {
279 // Mark a single block and make sure that there is a single merged
280 // rect with the correct bounds.
281 for (int y = 0; y < GetDiffInfoHeight() - 1; y++) {
282 for (int x = 0; x < GetDiffInfoWidth() - 1; x++) {
283 MarkBlocksAndCheckMerge(x, y, 1, 1);
284 }
285 }
286 }
287
288 TEST_F(DifferTest, MergeBlocks_BlockRow) {
289 // +---+---+---+---+
290 // | X | X | | _ |
291 // +---+---+---+---+
292 // | | | | _ |
293 // +---+---+---+---+
294 // | | | | _ |
295 // +---+---+---+---+
296 // | _ | _ | _ | _ |
297 // +---+---+---+---+
298 MarkBlocksAndCheckMerge(0, 0, 2, 1);
299
300 // +---+---+---+---+
301 // | | | | _ |
302 // +---+---+---+---+
303 // | X | X | X | _ |
304 // +---+---+---+---+
305 // | | | | _ |
306 // +---+---+---+---+
307 // | _ | _ | _ | _ |
308 // +---+---+---+---+
309 MarkBlocksAndCheckMerge(0, 1, 3, 1);
310
311 // +---+---+---+---+
312 // | | | | _ |
313 // +---+---+---+---+
314 // | | | | _ |
315 // +---+---+---+---+
316 // | | X | X | _ |
317 // +---+---+---+---+
318 // | _ | _ | _ | _ |
319 // +---+---+---+---+
320 MarkBlocksAndCheckMerge(1, 2, 2, 1);
321 }
322
323 TEST_F(DifferTest, MergeBlocks_BlockColumn) {
324 // +---+---+---+---+
325 // | X | | | _ |
326 // +---+---+---+---+
327 // | X | | | _ |
328 // +---+---+---+---+
329 // | | | | _ |
330 // +---+---+---+---+
331 // | _ | _ | _ | _ |
332 // +---+---+---+---+
333 MarkBlocksAndCheckMerge(0, 0, 1, 2);
334
335 // +---+---+---+---+
336 // | | | | _ |
337 // +---+---+---+---+
338 // | | X | | _ |
339 // +---+---+---+---+
340 // | | X | | _ |
341 // +---+---+---+---+
342 // | _ | _ | _ | _ |
343 // +---+---+---+---+
344 MarkBlocksAndCheckMerge(1, 1, 1, 2);
345
346 // +---+---+---+---+
347 // | | | X | _ |
348 // +---+---+---+---+
349 // | | | X | _ |
350 // +---+---+---+---+
351 // | | | X | _ |
352 // +---+---+---+---+
353 // | _ | _ | _ | _ |
354 // +---+---+---+---+
355 MarkBlocksAndCheckMerge(2, 0, 1, 3);
356 }
357
358 TEST_F(DifferTest, MergeBlocks_BlockRect) {
359 // +---+---+---+---+
360 // | X | X | | _ |
361 // +---+---+---+---+
362 // | X | X | | _ |
363 // +---+---+---+---+
364 // | | | | _ |
365 // +---+---+---+---+
366 // | _ | _ | _ | _ |
367 // +---+---+---+---+
368 MarkBlocksAndCheckMerge(0, 0, 2, 2);
369
370 // +---+---+---+---+
371 // | | | | _ |
372 // +---+---+---+---+
373 // | | X | X | _ |
374 // +---+---+---+---+
375 // | | X | X | _ |
376 // +---+---+---+---+
377 // | _ | _ | _ | _ |
378 // +---+---+---+---+
379 MarkBlocksAndCheckMerge(1, 1, 2, 2);
380
381 // +---+---+---+---+
382 // | | X | X | _ |
383 // +---+---+---+---+
384 // | | X | X | _ |
385 // +---+---+---+---+
386 // | | X | X | _ |
387 // +---+---+---+---+
388 // | _ | _ | _ | _ |
389 // +---+---+---+---+
390 MarkBlocksAndCheckMerge(1, 0, 2, 3);
391
392 // +---+---+---+---+
393 // | | | | _ |
394 // +---+---+---+---+
395 // | X | X | X | _ |
396 // +---+---+---+---+
397 // | X | X | X | _ |
398 // +---+---+---+---+
399 // | _ | _ | _ | _ |
400 // +---+---+---+---+
401 MarkBlocksAndCheckMerge(0, 1, 3, 2);
402
403 // +---+---+---+---+
404 // | X | X | X | _ |
405 // +---+---+---+---+
406 // | X | X | X | _ |
407 // +---+---+---+---+
408 // | X | X | X | _ |
409 // +---+---+---+---+
410 // | _ | _ | _ | _ |
411 // +---+---+---+---+
412 MarkBlocksAndCheckMerge(0, 0, 3, 3);
413 }
414
415 // This tests marked regions that require more than 1 single dirty rect.
416 // The exact rects returned depend on the current implementation, so these
417 // may need to be updated if we modify how we merge blocks.
418 TEST_F(DifferTest, MergeBlocks_MultiRect) {
419 DirtyRects* dirty;
420
421 // +---+---+---+---+ +---+---+---+
422 // | | X | | _ | | | 0 | |
423 // +---+---+---+---+ +---+---+---+
424 // | X | | | _ | | 1 | | |
425 // +---+---+---+---+ => +---+---+---+
426 // | | | X | _ | | | | 2 |
427 // +---+---+---+---+ +---+---+---+
428 // | _ | _ | _ | _ |
429 // +---+---+---+---+
430 ClearDiffInfo();
431 MarkBlocks(1, 0, 1, 1);
432 MarkBlocks(0, 1, 1, 1);
433 MarkBlocks(2, 2, 1, 1);
434
435 dirty = new DirtyRects();
436 differ_->MergeBlocks(dirty);
437
438 ASSERT_EQ(3, dirty->size());
439 CheckDirtyRect(dirty->at(0), 1, 0, 1, 1);
440 CheckDirtyRect(dirty->at(1), 0, 1, 1, 1);
441 CheckDirtyRect(dirty->at(2), 2, 2, 1, 1);
442
443 // +---+---+---+---+ +---+---+---+
444 // | | | X | _ | | | | 0 |
445 // +---+---+---+---+ +---+---+ +
446 // | X | X | X | _ | | 1 1 | 0 |
447 // +---+---+---+---+ => + + +
448 // | X | X | X | _ | | 1 1 | 0 |
449 // +---+---+---+---+ +---+---+---+
450 // | _ | _ | _ | _ |
451 // +---+---+---+---+
452 ClearDiffInfo();
453 MarkBlocks(2, 0, 1, 3);
454 MarkBlocks(0, 1, 2, 2);
455
456 dirty = new DirtyRects();
457 differ_->MergeBlocks(dirty);
458
459 ASSERT_EQ(2, dirty->size());
460 CheckDirtyRect(dirty->at(0), 2, 0, 1, 3);
461 CheckDirtyRect(dirty->at(1), 0, 1, 2, 2);
462
463 // +---+---+---+---+ +---+---+---+
464 // | | | | _ | | | | |
465 // +---+---+---+---+ +---+---+---+
466 // | X | | X | _ | | 0 | | 1 |
467 // +---+---+---+---+ => + +---+ +
468 // | X | X | X | _ | | 0 | 2 | 1 |
469 // +---+---+---+---+ +---+---+---+
470 // | _ | _ | _ | _ |
471 // +---+---+---+---+
472 ClearDiffInfo();
473 MarkBlocks(0, 1, 1, 1);
474 MarkBlocks(2, 1, 1, 1);
475 MarkBlocks(0, 2, 3, 1);
476
477 dirty = new DirtyRects();
478 differ_->MergeBlocks(dirty);
479
480 ASSERT_EQ(3, dirty->size());
481 CheckDirtyRect(dirty->at(0), 0, 1, 1, 2);
482 CheckDirtyRect(dirty->at(1), 2, 1, 1, 2);
483 CheckDirtyRect(dirty->at(2), 1, 2, 1, 1);
484
485 // +---+---+---+---+ +---+---+---+
486 // | X | X | X | _ | | 0 0 0 |
487 // +---+---+---+---+ +---+---+---+
488 // | X | | X | _ | | 1 | | 2 |
489 // +---+---+---+---+ => + +---+ +
490 // | X | X | X | _ | | 1 | 3 | 2 |
491 // +---+---+---+---+ +---+---+---+
492 // | _ | _ | _ | _ |
493 // +---+---+---+---+
494 ClearDiffInfo();
495 MarkBlocks(0, 0, 3, 1);
496 MarkBlocks(0, 1, 1, 1);
497 MarkBlocks(2, 1, 1, 1);
498 MarkBlocks(0, 2, 3, 1);
499
500 dirty = new DirtyRects();
501 differ_->MergeBlocks(dirty);
502
503 ASSERT_EQ(4, dirty->size());
504 CheckDirtyRect(dirty->at(0), 0, 0, 3, 1);
505 CheckDirtyRect(dirty->at(1), 0, 1, 1, 2);
506 CheckDirtyRect(dirty->at(2), 2, 1, 1, 2);
507 CheckDirtyRect(dirty->at(3), 1, 2, 1, 1);
508
509 // +---+---+---+---+ +---+---+---+
510 // | X | X | | _ | | 0 0 | |
511 // +---+---+---+---+ + +---+
512 // | X | X | | _ | | 0 0 | |
513 // +---+---+---+---+ => +---+---+---+
514 // | | X | | _ | | | 1 | |
515 // +---+---+---+---+ +---+---+---+
516 // | _ | _ | _ | _ |
517 // +---+---+---+---+
518 ClearDiffInfo();
519 MarkBlocks(0, 0, 2, 2);
520 MarkBlocks(1, 2, 1, 1);
521
522 dirty = new DirtyRects();
523 differ_->MergeBlocks(dirty);
524
525 ASSERT_EQ(2, dirty->size());
526 CheckDirtyRect(dirty->at(0), 0, 0, 2, 2);
527 CheckDirtyRect(dirty->at(1), 1, 2, 1, 1);
528 }
529
530 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/differ.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698