blob: 1c2bd38307b5d2554a5bebf27c5c52312ab5b045 [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>
Adam Tkac20e0d712008-11-14 14:48:21 +000019#include <string.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000020#include <vector>
21#include <rdr/types.h>
22#include <rfb/Exception.h>
23#include <rfb/ComparingUpdateTracker.h>
24
25using namespace rfb;
26
27ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
Pierre Ossmanb114cec2011-11-20 15:36:11 +000028 : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true), enabled(true)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029{
30 changed.assign_union(fb->getRect());
31}
32
33ComparingUpdateTracker::~ComparingUpdateTracker()
34{
35}
36
37
Pierre Ossmanc9971292011-11-20 15:37:31 +000038#define BLOCK_SIZE 64
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000039
Pierre Ossmanb114cec2011-11-20 15:36:11 +000040bool ComparingUpdateTracker::compare()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000041{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000042 std::vector<Rect> rects;
43 std::vector<Rect>::iterator i;
44
Pierre Ossmanb114cec2011-11-20 15:36:11 +000045 if (!enabled)
46 return false;
47
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048 if (firstCompare) {
49 // NB: We leave the change region untouched on this iteration,
50 // since in effect the entire framebuffer has changed.
51 oldFb.setSize(fb->width(), fb->height());
Pierre Ossmanb114cec2011-11-20 15:36:11 +000052
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053 for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
54 Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
55 int srcStride;
56 const rdr::U8* srcData = fb->getPixelsR(pos, &srcStride);
57 oldFb.imageRect(pos, srcData, srcStride);
58 }
Pierre Ossmanb114cec2011-11-20 15:36:11 +000059
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000060 firstCompare = false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000061
Pierre Ossmanb114cec2011-11-20 15:36:11 +000062 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000063 }
Pierre Ossmanb114cec2011-11-20 15:36:11 +000064
65 copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
66 for (i = rects.begin(); i != rects.end(); i++)
67 oldFb.copyRect(*i, copy_delta);
68
69 changed.get_rects(&rects);
70
71 Region newChanged;
72 for (i = rects.begin(); i != rects.end(); i++)
73 compareRect(*i, &newChanged);
74
75 if (changed.equals(newChanged))
76 return false;
77
78 changed = newChanged;
79
80 return true;
81}
82
83void ComparingUpdateTracker::enable()
84{
85 enabled = true;
86}
87
88void ComparingUpdateTracker::disable()
89{
90 enabled = false;
91
92 // Make sure we update the framebuffer next time we get enabled
93 firstCompare = true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000094}
95
96void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
97{
98 if (!r.enclosed_by(fb->getRect())) {
Pierre Ossmand88895d2009-06-09 14:18:36 +000099 Rect safe;
100 // Crop the rect and try again
101 safe = r.intersect(fb->getRect());
102 if (!safe.is_empty())
103 compareRect(safe, newChanged);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000104 return;
105 }
106
107 int bytesPerPixel = fb->getPF().bpp/8;
108 int oldStride;
109 rdr::U8* oldData = oldFb.getPixelsRW(r, &oldStride);
110 int oldStrideBytes = oldStride * bytesPerPixel;
111
112 std::vector<Rect> changedBlocks;
113
114 for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
115 {
116 // Get a strip of the source buffer
117 Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
118 int fbStride;
119 const rdr::U8* newBlockPtr = fb->getPixelsR(pos, &fbStride);
120 int newStrideBytes = fbStride * bytesPerPixel;
121
122 rdr::U8* oldBlockPtr = oldData;
123 int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
124
125 for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
126 {
127 const rdr::U8* newPtr = newBlockPtr;
128 rdr::U8* oldPtr = oldBlockPtr;
129
130 int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
131 int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
132
133 for (int y = blockTop; y < blockBottom; y++)
134 {
135 if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
136 {
137 // A block has changed - copy the remainder to the oldFb
138 changedBlocks.push_back(Rect(blockLeft, blockTop,
139 blockRight, blockBottom));
140 for (int y2 = y; y2 < blockBottom; y2++)
141 {
142 memcpy(oldPtr, newPtr, blockWidthInBytes);
143 newPtr += newStrideBytes;
144 oldPtr += oldStrideBytes;
145 }
146 break;
147 }
148
149 newPtr += newStrideBytes;
150 oldPtr += oldStrideBytes;
151 }
152
153 oldBlockPtr += blockWidthInBytes;
154 newBlockPtr += blockWidthInBytes;
155 }
156
157 oldData += oldStrideBytes * BLOCK_SIZE;
158 }
159
160 if (!changedBlocks.empty()) {
161 Region temp;
162 temp.setOrderedRects(changedBlocks);
163 newChanged->assign_union(temp);
164 }
165}