blob: 237adc41bef6f0fc5187de601b42c72118fec847 [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>
Pierre Ossman05338bc2016-11-08 14:57:11 +010023#include <rfb/LogWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000024#include <rfb/ComparingUpdateTracker.h>
25
26using namespace rfb;
27
Pierre Ossman05338bc2016-11-08 14:57:11 +010028static LogWriter vlog("ComparingUpdateTracker");
29
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000030ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
Pierre Ossman05338bc2016-11-08 14:57:11 +010031 : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true),
32 enabled(true), totalPixels(0), missedPixels(0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000033{
34 changed.assign_union(fb->getRect());
35}
36
37ComparingUpdateTracker::~ComparingUpdateTracker()
38{
39}
40
41
Pierre Ossmanc9971292011-11-20 15:37:31 +000042#define BLOCK_SIZE 64
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000043
Pierre Ossmanb114cec2011-11-20 15:36:11 +000044bool ComparingUpdateTracker::compare()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000045{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000046 std::vector<Rect> rects;
47 std::vector<Rect>::iterator i;
48
Pierre Ossmanb114cec2011-11-20 15:36:11 +000049 if (!enabled)
50 return false;
51
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052 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());
Pierre Ossmanb114cec2011-11-20 15:36:11 +000056
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000057 for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
58 Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
59 int srcStride;
Pierre Ossman945cdda2014-01-28 14:13:12 +010060 const rdr::U8* srcData = fb->getBuffer(pos, &srcStride);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000061 oldFb.imageRect(pos, srcData, srcStride);
62 }
Pierre Ossmanb114cec2011-11-20 15:36:11 +000063
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000064 firstCompare = false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000065
Pierre Ossmanb114cec2011-11-20 15:36:11 +000066 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000067 }
Pierre Ossmanb114cec2011-11-20 15:36:11 +000068
69 copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
70 for (i = rects.begin(); i != rects.end(); i++)
71 oldFb.copyRect(*i, copy_delta);
72
73 changed.get_rects(&rects);
74
75 Region newChanged;
76 for (i = rects.begin(); i != rects.end(); i++)
77 compareRect(*i, &newChanged);
78
Pierre Ossman05338bc2016-11-08 14:57:11 +010079 changed.get_rects(&rects);
80 for (i = rects.begin(); i != rects.end(); i++)
81 totalPixels += i->area();
82 newChanged.get_rects(&rects);
83 for (i = rects.begin(); i != rects.end(); i++)
84 missedPixels += i->area();
85
Pierre Ossmanb114cec2011-11-20 15:36:11 +000086 if (changed.equals(newChanged))
87 return false;
88
89 changed = newChanged;
90
91 return true;
92}
93
94void ComparingUpdateTracker::enable()
95{
96 enabled = true;
97}
98
99void ComparingUpdateTracker::disable()
100{
101 enabled = false;
102
103 // Make sure we update the framebuffer next time we get enabled
104 firstCompare = true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000105}
106
107void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
108{
109 if (!r.enclosed_by(fb->getRect())) {
Pierre Ossmand88895d2009-06-09 14:18:36 +0000110 Rect safe;
111 // Crop the rect and try again
112 safe = r.intersect(fb->getRect());
113 if (!safe.is_empty())
114 compareRect(safe, newChanged);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000115 return;
116 }
117
118 int bytesPerPixel = fb->getPF().bpp/8;
119 int oldStride;
Pierre Ossman945cdda2014-01-28 14:13:12 +0100120 rdr::U8* oldData = oldFb.getBufferRW(r, &oldStride);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000121 int oldStrideBytes = oldStride * bytesPerPixel;
122
123 std::vector<Rect> changedBlocks;
124
125 for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
126 {
127 // Get a strip of the source buffer
128 Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
129 int fbStride;
Pierre Ossman945cdda2014-01-28 14:13:12 +0100130 const rdr::U8* newBlockPtr = fb->getBuffer(pos, &fbStride);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000131 int newStrideBytes = fbStride * bytesPerPixel;
132
133 rdr::U8* oldBlockPtr = oldData;
134 int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
135
136 for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
137 {
138 const rdr::U8* newPtr = newBlockPtr;
139 rdr::U8* oldPtr = oldBlockPtr;
140
141 int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
142 int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
143
144 for (int y = blockTop; y < blockBottom; y++)
145 {
146 if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
147 {
148 // A block has changed - copy the remainder to the oldFb
149 changedBlocks.push_back(Rect(blockLeft, blockTop,
150 blockRight, blockBottom));
151 for (int y2 = y; y2 < blockBottom; y2++)
152 {
153 memcpy(oldPtr, newPtr, blockWidthInBytes);
154 newPtr += newStrideBytes;
155 oldPtr += oldStrideBytes;
156 }
157 break;
158 }
159
160 newPtr += newStrideBytes;
161 oldPtr += oldStrideBytes;
162 }
163
164 oldBlockPtr += blockWidthInBytes;
165 newBlockPtr += blockWidthInBytes;
166 }
167
168 oldData += oldStrideBytes * BLOCK_SIZE;
169 }
170
Pierre Ossmana32040d2014-02-06 16:31:10 +0100171 oldFb.commitBufferRW(r);
172
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000173 if (!changedBlocks.empty()) {
174 Region temp;
175 temp.setOrderedRects(changedBlocks);
176 newChanged->assign_union(temp);
177 }
178}
Pierre Ossman05338bc2016-11-08 14:57:11 +0100179
180void ComparingUpdateTracker::logStats()
181{
182 double ratio;
183 char a[1024], b[1024];
184
185 siPrefix(totalPixels, "pixels", a, sizeof(a));
186 siPrefix(missedPixels, "pixels", b, sizeof(b));
187
188 ratio = (double)totalPixels / missedPixels;
189
190 vlog.info("%s in / %s out", a, b);
191 vlog.info("(1:%g ratio)", ratio);
192
193 totalPixels = missedPixels = 0;
194}