123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
- #include <stdio.h>
- #include <string.h>
- #include <vector>
- #include <rdr/types.h>
- #include <rfb/Exception.h>
- #include <rfb/LogWriter.h>
- #include <rfb/ComparingUpdateTracker.h>
-
- using namespace rfb;
-
- static LogWriter vlog("ComparingUpdateTracker");
-
- ComparingUpdateTracker::ComparingUpdateTracker(PixelBuffer* buffer)
- : fb(buffer), oldFb(fb->getPF(), 0, 0), firstCompare(true),
- enabled(true), totalPixels(0), missedPixels(0)
- {
- changed.assign_union(fb->getRect());
- }
-
- ComparingUpdateTracker::~ComparingUpdateTracker()
- {
- }
-
-
- #define BLOCK_SIZE 64
-
- bool ComparingUpdateTracker::compare()
- {
- std::vector<Rect> rects;
- std::vector<Rect>::iterator i;
-
- if (!enabled)
- return false;
-
- if (firstCompare) {
- // NB: We leave the change region untouched on this iteration,
- // since in effect the entire framebuffer has changed.
- oldFb.setSize(fb->width(), fb->height());
-
- for (int y=0; y<fb->height(); y+=BLOCK_SIZE) {
- Rect pos(0, y, fb->width(), __rfbmin(fb->height(), y+BLOCK_SIZE));
- int srcStride;
- const rdr::U8* srcData = fb->getBuffer(pos, &srcStride);
- oldFb.imageRect(pos, srcData, srcStride);
- }
-
- firstCompare = false;
-
- return false;
- }
-
- copied.get_rects(&rects, copy_delta.x<=0, copy_delta.y<=0);
- for (i = rects.begin(); i != rects.end(); i++)
- oldFb.copyRect(*i, copy_delta);
-
- changed.get_rects(&rects);
-
- Region newChanged;
- for (i = rects.begin(); i != rects.end(); i++)
- compareRect(*i, &newChanged);
-
- changed.get_rects(&rects);
- for (i = rects.begin(); i != rects.end(); i++)
- totalPixels += i->area();
- newChanged.get_rects(&rects);
- for (i = rects.begin(); i != rects.end(); i++)
- missedPixels += i->area();
-
- if (changed.equals(newChanged))
- return false;
-
- changed = newChanged;
-
- return true;
- }
-
- void ComparingUpdateTracker::enable()
- {
- enabled = true;
- }
-
- void ComparingUpdateTracker::disable()
- {
- enabled = false;
-
- // Make sure we update the framebuffer next time we get enabled
- firstCompare = true;
- }
-
- void ComparingUpdateTracker::compareRect(const Rect& r, Region* newChanged)
- {
- if (!r.enclosed_by(fb->getRect())) {
- Rect safe;
- // Crop the rect and try again
- safe = r.intersect(fb->getRect());
- if (!safe.is_empty())
- compareRect(safe, newChanged);
- return;
- }
-
- int bytesPerPixel = fb->getPF().bpp/8;
- int oldStride;
- rdr::U8* oldData = oldFb.getBufferRW(r, &oldStride);
- int oldStrideBytes = oldStride * bytesPerPixel;
-
- std::vector<Rect> changedBlocks;
-
- for (int blockTop = r.tl.y; blockTop < r.br.y; blockTop += BLOCK_SIZE)
- {
- // Get a strip of the source buffer
- Rect pos(r.tl.x, blockTop, r.br.x, __rfbmin(r.br.y, blockTop+BLOCK_SIZE));
- int fbStride;
- const rdr::U8* newBlockPtr = fb->getBuffer(pos, &fbStride);
- int newStrideBytes = fbStride * bytesPerPixel;
-
- rdr::U8* oldBlockPtr = oldData;
- int blockBottom = __rfbmin(blockTop+BLOCK_SIZE, r.br.y);
-
- for (int blockLeft = r.tl.x; blockLeft < r.br.x; blockLeft += BLOCK_SIZE)
- {
- const rdr::U8* newPtr = newBlockPtr;
- rdr::U8* oldPtr = oldBlockPtr;
-
- int blockRight = __rfbmin(blockLeft+BLOCK_SIZE, r.br.x);
- int blockWidthInBytes = (blockRight-blockLeft) * bytesPerPixel;
-
- for (int y = blockTop; y < blockBottom; y++)
- {
- if (memcmp(oldPtr, newPtr, blockWidthInBytes) != 0)
- {
- // A block has changed - copy the remainder to the oldFb
- changedBlocks.push_back(Rect(blockLeft, blockTop,
- blockRight, blockBottom));
- for (int y2 = y; y2 < blockBottom; y2++)
- {
- memcpy(oldPtr, newPtr, blockWidthInBytes);
- newPtr += newStrideBytes;
- oldPtr += oldStrideBytes;
- }
- break;
- }
-
- newPtr += newStrideBytes;
- oldPtr += oldStrideBytes;
- }
-
- oldBlockPtr += blockWidthInBytes;
- newBlockPtr += blockWidthInBytes;
- }
-
- oldData += oldStrideBytes * BLOCK_SIZE;
- }
-
- oldFb.commitBufferRW(r);
-
- if (!changedBlocks.empty()) {
- Region temp;
- temp.setOrderedRects(changedBlocks);
- newChanged->assign_union(temp);
- }
- }
-
- void ComparingUpdateTracker::logStats()
- {
- double ratio;
- char a[1024], b[1024];
-
- siPrefix(totalPixels, "pixels", a, sizeof(a));
- siPrefix(missedPixels, "pixels", b, sizeof(b));
-
- ratio = (double)totalPixels / missedPixels;
-
- vlog.info("%s in / %s out", a, b);
- vlog.info("(1:%g ratio)", ratio);
-
- totalPixels = missedPixels = 0;
- }
|