blob: ce3d68aeb752e9234feb1613fff83296cdb36381 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18#include <stdio.h>
19#include <vector>
20#include <rdr/types.h>
21#include <rfb/Exception.h>
22#include <rfb/ComparingUpdateTracker.h>
23
24using namespace rfb;
25
26ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
27 : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true)
28{
29 changed.assign_union(fb->getRect());
30}
31
32ComparingUpdateTracker::~ComparingUpdateTracker()
33{
34}
35
36
37#define BLOCK_SIZE 16
38
39void ComparingUpdateTracker::compare()
40{
41 std::vector<Rect> rects;
42 std::vector<Rect>::iterator i;
43
44 if (firstCompare) {
45 // NB: We leave the change region untouched on this iteration,
46 // since in effect the entire framebuffer has changed.
47 oldFb.setSize(fb->width(), fb->height());
48 for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
49 Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
50 int srcStride;
51 const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
52 oldFb.imageRect(pos, srcData, srcStride);
53 }
54 firstCompare = false;
55 } else {
56 copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
57 for (i = rects.begin(); i != rects.end(); i++)
58 oldFb.copyRect(*i, copy_delta);
59
60 Region to_check = changed.union_(copied);
61 to_check.get_rects(&rects);
62
63 Region newChanged;
64 for (i = rects.begin(); i != rects.end(); i++)
65 compareRect(*i, &newChanged);
66
67 copied.assign_subtract(newChanged);
68 changed = newChanged;
69 }
70}
71
72void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
73{
74 if (!r.enclosed_by(fb->getRect())) {
75 fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
76 return;
77 }
78
79 int bytesPerPixel = fb->getPF().bpp/8;
80 int oldStride;
81 rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
82 int oldStrideBytes = oldStride * bytesPerPixel;
83
84 std::vector<Rect> changedBlocks;
85
86 for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
87 {
88 // Get a strip of the source buffer
89 Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
90 int fbStride;
91 const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
92 int newStrideBytes = fbStride * bytesPerPixel;
93
94 rdr::U8* oldBlockPtr = oldData;
95 int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
96
97 for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
98 {
99 const rdr::U8* newPtr = newBlockPtr;
100 rdr::U8* oldPtr = oldBlockPtr;
101
102 int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
103 int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
104
105 for (int y = blockTop; y < blockBottom; y++)
106 {
107 if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
108 {
109 // A block has changed - copy the remainder to the oldFb
110 changedBlocks.push_back(Rect(blockLeft, blockTop,
111 blockRight, blockBottom));
112 for (int y2 = y; y2 < blockBottom; y2++)
113 {
114 memcpy(oldPtr, newPtr, blockWidthInBytes);
115 newPtr += newStrideBytes;
116 oldPtr += oldStrideBytes;
117 }
118 break;
119 }
120
121 newPtr += newStrideBytes;
122 oldPtr += oldStrideBytes;
123 }
124
125 oldBlockPtr += blockWidthInBytes;
126 newBlockPtr += blockWidthInBytes;
127 }
128
129 oldData += oldStrideBytes * BLOCK_SIZE;
130 }
131
132 if (!changedBlocks.empty()) {
133 Region temp;
134 temp.setOrderedRects(changedBlocks);
135 newChanged->assign_union(temp);
136 }
137}