blob: 0c44d85ab792a08b290c61275308685ecd8e099a [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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 : SimpleUpdateTracker(true), fb(buffer),
28 oldFb(fb->getPF(), 0, 0), firstCompare(true)
29{
30 changed.assign_union(fb->getRect());
31}
32
33ComparingUpdateTracker::~ComparingUpdateTracker()
34{
35}
36
37
38void ComparingUpdateTracker::flush_update(UpdateInfo* info,
39 const Region& cliprgn, int maxArea)
40{
41 throw rfb::Exception("flush_update(UpdateInfo*) not implemented");
42}
43
44void ComparingUpdateTracker::flush_update(UpdateTracker &ut,
45 const Region &cliprgn)
46{
47 throw rfb::Exception("flush_update(UpdateTracker&) not implemented");
48}
49
50
51#define BLOCK_SIZE 16
52
53void ComparingUpdateTracker::compare()
54{
55 std::vector<Rect> rects;
56 std::vector<Rect>::iterator i;
57
58 if (firstCompare) {
59 // NB: We leave the change region untouched on this iteration,
60 // since in effect the entire framebuffer has changed.
61 oldFb.setSize(fb->width(), fb->height());
62 for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
63 Rect pos(0, y, fb->width(), min(fb->height(), y+BLOCK_SIZE));
64 int srcStride;
65 const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
66 oldFb.imageRect(pos, srcData, srcStride);
67 }
68 firstCompare = false;
69 } else {
70 copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
71 for (i = rects.begin(); i != rects.end(); i++)
72 oldFb.copyRect(*i, copy_delta);
73
74 Region to_check = changed.union_(copied);
75 to_check.get_rects(&rects);
76
77 Region newChanged;
78 for (i = rects.begin(); i != rects.end(); i++)
79 compareRect(*i, &newChanged);
80
81 copied.assign_subtract(newChanged);
82 changed = newChanged;
83 }
84}
85
86void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
87{
88 if (!r.enclosed_by(fb->getRect())) {
89 fprintf(stderr,"ComparingUpdateTracker: rect outside fb (%d,%d-%d,%d)\n", r.tl.x, r.tl.y, r.br.x, r.br.y);
90 return;
91 }
92
93 int bytesPerPixel = fb->getPF().bpp/8;
94 int oldStride;
95 rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
96 int oldStrideBytes = oldStride * bytesPerPixel;
97
98 std::vector<Rect> changedBlocks;
99
100 for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
101 {
102 // Get a strip of the source buffer
103 Rect pos(r.tl.x, blockTop, r.br.x, min(r.br.y, blockTop+BLOCK_SIZE));
104 int fbStride;
105 const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
106 int newStrideBytes = fbStride * bytesPerPixel;
107
108 rdr::U8* oldBlockPtr = oldData;
109 int blockBottom = min(blockTop+BLOCK_SIZE, r.br.y);
110
111 for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
112 {
113 const rdr::U8* newPtr = newBlockPtr;
114 rdr::U8* oldPtr = oldBlockPtr;
115
116 int blockRight = min(blockLeft+BLOCK_SIZE, r.br.x);
117 int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
118
119 for (int y = blockTop; y < blockBottom; y++)
120 {
121 if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
122 {
123 // A block has changed - copy the remainder to the oldFb
124 changedBlocks.push_back(Rect(blockLeft, blockTop,
125 blockRight, blockBottom));
126 for (int y2 = y; y2 < blockBottom; y2++)
127 {
128 memcpy(oldPtr, newPtr, blockWidthInBytes);
129 newPtr += newStrideBytes;
130 oldPtr += oldStrideBytes;
131 }
132 break;
133 }
134
135 newPtr += newStrideBytes;
136 oldPtr += oldStrideBytes;
137 }
138
139 oldBlockPtr += blockWidthInBytes;
140 newBlockPtr += blockWidthInBytes;
141 }
142
143 oldData += oldStrideBytes * BLOCK_SIZE;
144 }
145
146 if (!changedBlocks.empty()) {
147 Region temp;
148 temp.setOrderedRects(changedBlocks);
149 newChanged->assign_union(temp);
150 }
151}