| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2011 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 "remoting/host/differ.h" |  | 
| 6 |  | 
| 7 #include "base/logging.h" |  | 
| 8 #include "remoting/host/differ_block.h" |  | 
| 9 |  | 
| 10 namespace remoting { |  | 
| 11 |  | 
| 12 Differ::Differ(int width, int height, int bpp, int stride) { |  | 
| 13   // Dimensions of screen. |  | 
| 14   width_ = width; |  | 
| 15   height_ = height; |  | 
| 16   bytes_per_pixel_ = bpp; |  | 
| 17   bytes_per_row_ = stride; |  | 
| 18 |  | 
| 19   // Calc number of blocks (full and partial) required to cover entire image. |  | 
| 20   // One additional row/column is added as a boundary on the right & bottom. |  | 
| 21   diff_info_width_ = ((width_ + kBlockSize - 1) / kBlockSize) + 1; |  | 
| 22   diff_info_height_ = ((height_ + kBlockSize - 1) / kBlockSize) + 1; |  | 
| 23   diff_info_size_ = diff_info_width_ * diff_info_height_ * sizeof(DiffInfo); |  | 
| 24   diff_info_.reset(new DiffInfo[diff_info_size_]); |  | 
| 25 } |  | 
| 26 |  | 
| 27 Differ::~Differ() {} |  | 
| 28 |  | 
| 29 void Differ::CalcDirtyRegion(const void* prev_buffer, const void* curr_buffer, |  | 
| 30                              SkRegion* region) { |  | 
| 31   if (!region) { |  | 
| 32     return; |  | 
| 33   } |  | 
| 34   region->setEmpty(); |  | 
| 35 |  | 
| 36   if (!prev_buffer || !curr_buffer) { |  | 
| 37     return; |  | 
| 38   } |  | 
| 39 |  | 
| 40   // Identify all the blocks that contain changed pixels. |  | 
| 41   MarkDirtyBlocks(prev_buffer, curr_buffer); |  | 
| 42 |  | 
| 43   // Now that we've identified the blocks that have changed, merge adjacent |  | 
| 44   // blocks to minimize the number of rects that we return. |  | 
| 45   MergeBlocks(region); |  | 
| 46 } |  | 
| 47 |  | 
| 48 void Differ::MarkDirtyBlocks(const void* prev_buffer, const void* curr_buffer) { |  | 
| 49   memset(diff_info_.get(), 0, diff_info_size_); |  | 
| 50 |  | 
| 51   // Calc number of full blocks. |  | 
| 52   int x_full_blocks = width_ / kBlockSize; |  | 
| 53   int y_full_blocks = height_ / kBlockSize; |  | 
| 54 |  | 
| 55   // Calc size of partial blocks which may be present on right and bottom edge. |  | 
| 56   int partial_column_width = width_ - (x_full_blocks * kBlockSize); |  | 
| 57   int partial_row_height = height_ - (y_full_blocks * kBlockSize); |  | 
| 58 |  | 
| 59   // Offset from the start of one block-column to the next. |  | 
| 60   int block_x_offset = bytes_per_pixel_ * kBlockSize; |  | 
| 61   // Offset from the start of one block-row to the next. |  | 
| 62   int block_y_stride = (width_ * bytes_per_pixel_) * kBlockSize; |  | 
| 63   // Offset from the start of one diff_info row to the next. |  | 
| 64   int diff_info_stride = diff_info_width_ * sizeof(DiffInfo); |  | 
| 65 |  | 
| 66   const uint8* prev_block_row_start = static_cast<const uint8*>(prev_buffer); |  | 
| 67   const uint8* curr_block_row_start = static_cast<const uint8*>(curr_buffer); |  | 
| 68   DiffInfo* diff_info_row_start = static_cast<DiffInfo*>(diff_info_.get()); |  | 
| 69 |  | 
| 70   for (int y = 0; y < y_full_blocks; y++) { |  | 
| 71     const uint8* prev_block = prev_block_row_start; |  | 
| 72     const uint8* curr_block = curr_block_row_start; |  | 
| 73     DiffInfo* diff_info = diff_info_row_start; |  | 
| 74 |  | 
| 75     for (int x = 0; x < x_full_blocks; x++) { |  | 
| 76       // Mark this block as being modified so that it gets incorporated into |  | 
| 77       // a dirty rect. |  | 
| 78       *diff_info = BlockDifference(prev_block, curr_block, bytes_per_row_); |  | 
| 79       prev_block += block_x_offset; |  | 
| 80       curr_block += block_x_offset; |  | 
| 81       diff_info += sizeof(DiffInfo); |  | 
| 82     } |  | 
| 83 |  | 
| 84     // If there is a partial column at the end, handle it. |  | 
| 85     // This condition should rarely, if ever, occur. |  | 
| 86     if (partial_column_width != 0) { |  | 
| 87       *diff_info = DiffPartialBlock(prev_block, curr_block, bytes_per_row_, |  | 
| 88                                     partial_column_width, kBlockSize); |  | 
| 89       diff_info += sizeof(DiffInfo); |  | 
| 90     } |  | 
| 91 |  | 
| 92     // Update pointers for next row. |  | 
| 93     prev_block_row_start += block_y_stride; |  | 
| 94     curr_block_row_start += block_y_stride; |  | 
| 95     diff_info_row_start += diff_info_stride; |  | 
| 96   } |  | 
| 97 |  | 
| 98   // If the screen height is not a multiple of the block size, then this |  | 
| 99   // handles the last partial row. This situation is far more common than the |  | 
| 100   // 'partial column' case. |  | 
| 101   if (partial_row_height != 0) { |  | 
| 102     const uint8* prev_block = prev_block_row_start; |  | 
| 103     const uint8* curr_block = curr_block_row_start; |  | 
| 104     DiffInfo* diff_info = diff_info_row_start; |  | 
| 105     for (int x = 0; x < x_full_blocks; x++) { |  | 
| 106       *diff_info = DiffPartialBlock(prev_block, curr_block, |  | 
| 107                                     bytes_per_row_, |  | 
| 108                                     kBlockSize, partial_row_height); |  | 
| 109       prev_block += block_x_offset; |  | 
| 110       curr_block += block_x_offset; |  | 
| 111       diff_info += sizeof(DiffInfo); |  | 
| 112     } |  | 
| 113     if (partial_column_width != 0) { |  | 
| 114       *diff_info = DiffPartialBlock(prev_block, curr_block, bytes_per_row_, |  | 
| 115                                     partial_column_width, partial_row_height); |  | 
| 116       diff_info += sizeof(DiffInfo); |  | 
| 117     } |  | 
| 118   } |  | 
| 119 } |  | 
| 120 |  | 
| 121 DiffInfo Differ::DiffPartialBlock(const uint8* prev_buffer, |  | 
| 122                                   const uint8* curr_buffer, |  | 
| 123                                   int stride, int width, int height) { |  | 
| 124   int width_bytes = width * bytes_per_pixel_; |  | 
| 125   for (int y = 0; y < height; y++) { |  | 
| 126     if (memcmp(prev_buffer, curr_buffer, width_bytes) != 0) |  | 
| 127       return 1; |  | 
| 128     prev_buffer += bytes_per_row_; |  | 
| 129     curr_buffer += bytes_per_row_; |  | 
| 130   } |  | 
| 131   return 0; |  | 
| 132 } |  | 
| 133 |  | 
| 134 void Differ::MergeBlocks(SkRegion* region) { |  | 
| 135   DCHECK(region); |  | 
| 136   region->setEmpty(); |  | 
| 137 |  | 
| 138   uint8* diff_info_row_start = static_cast<uint8*>(diff_info_.get()); |  | 
| 139   int diff_info_stride = diff_info_width_ * sizeof(DiffInfo); |  | 
| 140 |  | 
| 141   for (int y = 0; y < diff_info_height_; y++) { |  | 
| 142     uint8* diff_info = diff_info_row_start; |  | 
| 143     for (int x = 0; x < diff_info_width_; x++) { |  | 
| 144       if (*diff_info != 0) { |  | 
| 145         // We've found a modified block. Look at blocks to the right and below |  | 
| 146         // to group this block with as many others as we can. |  | 
| 147         int left = x * kBlockSize; |  | 
| 148         int top = y * kBlockSize; |  | 
| 149         int width = 1; |  | 
| 150         int height = 1; |  | 
| 151         *diff_info = 0; |  | 
| 152 |  | 
| 153         // Group with blocks to the right. |  | 
| 154         // We can keep looking until we find an unchanged block because we |  | 
| 155         // have a boundary block which is never marked as having diffs. |  | 
| 156         uint8* right = diff_info + 1; |  | 
| 157         while (*right) { |  | 
| 158           *right++ = 0; |  | 
| 159           width++; |  | 
| 160         } |  | 
| 161 |  | 
| 162         // Group with blocks below. |  | 
| 163         // The entire width of blocks that we matched above much match for |  | 
| 164         // each row that we add. |  | 
| 165         uint8* bottom = diff_info; |  | 
| 166         bool found_new_row; |  | 
| 167         do { |  | 
| 168           found_new_row = true; |  | 
| 169           bottom += diff_info_stride; |  | 
| 170           right = bottom; |  | 
| 171           for (int x2 = 0; x2 < width; x2++) { |  | 
| 172             if (*right++ == 0) { |  | 
| 173               found_new_row = false; |  | 
| 174             } |  | 
| 175           } |  | 
| 176 |  | 
| 177           if (found_new_row) { |  | 
| 178             height++; |  | 
| 179 |  | 
| 180             // We need to go back and erase the diff markers so that we don't |  | 
| 181             // try to add these blocks a second time. |  | 
| 182             right = bottom; |  | 
| 183             for (int x2 = 0; x2 < width; x2++) { |  | 
| 184               *right++ = 0; |  | 
| 185             } |  | 
| 186           } |  | 
| 187         } while (found_new_row); |  | 
| 188 |  | 
| 189         // Add rect to list of dirty rects. |  | 
| 190         width *= kBlockSize; |  | 
| 191         if (left + width > width_) { |  | 
| 192           width = width_ - left; |  | 
| 193         } |  | 
| 194         height *= kBlockSize; |  | 
| 195         if (top + height > height_) { |  | 
| 196           height = height_ - top; |  | 
| 197         } |  | 
| 198         region->op(SkIRect::MakeXYWH(left, top, width, height), |  | 
| 199                    SkRegion::kUnion_Op); |  | 
| 200       } |  | 
| 201 |  | 
| 202       // Increment to next block in this row. |  | 
| 203       diff_info++; |  | 
| 204     } |  | 
| 205 |  | 
| 206     // Go to start of next row. |  | 
| 207     diff_info_row_start += diff_info_stride; |  | 
| 208   } |  | 
| 209 } |  | 
| 210 |  | 
| 211 }  // namespace remoting |  | 
| OLD | NEW | 
|---|