blob: ec323020fae9d9f2f2f0b24e05e623a8ef2bfe78 [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{
Constantin Kaplinsky1a845d02007-08-31 21:06:53 +000041 // First of all, exclude video area from both changed and copied regions.
42 // We handle video area separately and do not compare it -- we know it's
43 // being changed continuously.
44 if (!video_area.is_empty()) {
45 changed.assign_subtract(video_area);
46 copied.assign_subtract(video_area);
47 }
48
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049 std::vector<Rect> rects;
50 std::vector<Rect>::iterator i;
51
52 if (firstCompare) {
53 // NB: We leave the change region untouched on this iteration,
54 // since in effect the entire framebuffer has changed.
55 oldFb.setSize(fb->width(), fb->height());
56 for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
57 Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
58 int srcStride;
59 const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
60 oldFb.imageRect(pos, srcData, srcStride);
61 }
62 firstCompare = false;
63 } else {
64 copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
65 for (i = rects.begin(); i != rects.end(); i++)
66 oldFb.copyRect(*i, copy_delta);
67
68 Region to_check = changed.union_(copied);
69 to_check.get_rects(&rects);
70
71 Region newChanged;
72 for (i = rects.begin(); i != rects.end(); i++)
73 compareRect(*i, &newChanged);
74
75 copied.assign_subtract(newChanged);
76 changed = newChanged;
77 }
78}
79
80void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
81{
82 if (!r.enclosed_by(fb->getRect())) {
83 fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
84 return;
85 }
86
87 int bytesPerPixel = fb->getPF().bpp/8;
88 int oldStride;
89 rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
90 int oldStrideBytes = oldStride * bytesPerPixel;
91
92 std::vector<Rect> changedBlocks;
93
94 for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
95 {
96 // Get a strip of the source buffer
97 Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
98 int fbStride;
99 const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
100 int newStrideBytes = fbStride * bytesPerPixel;
101
102 rdr::U8* oldBlockPtr = oldData;
103 int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
104
105 for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
106 {
107 const rdr::U8* newPtr = newBlockPtr;
108 rdr::U8* oldPtr = oldBlockPtr;
109
110 int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
111 int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
112
113 for (int y = blockTop; y < blockBottom; y++)
114 {
115 if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
116 {
117 // A block has changed - copy the remainder to the oldFb
118 changedBlocks.push_back(Rect(blockLeft, blockTop,
119 blockRight, blockBottom));
120 for (int y2 = y; y2 < blockBottom; y2++)
121 {
122 memcpy(oldPtr, newPtr, blockWidthInBytes);
123 newPtr += newStrideBytes;
124 oldPtr += oldStrideBytes;
125 }
126 break;
127 }
128
129 newPtr += newStrideBytes;
130 oldPtr += oldStrideBytes;
131 }
132
133 oldBlockPtr += blockWidthInBytes;
134 newBlockPtr += blockWidthInBytes;
135 }
136
137 oldData += oldStrideBytes * BLOCK_SIZE;
138 }
139
140 if (!changedBlocks.empty()) {
141 Region temp;
142 temp.setOrderedRects(changedBlocks);
143 newChanged->assign_union(temp);
144 }
145}