summaryrefslogtreecommitdiffstats
path: root/common/rfb
diff options
context:
space:
mode:
Diffstat (limited to 'common/rfb')
-rw-r--r--common/rfb/EncodeManager.cxx154
-rw-r--r--common/rfb/EncodeManager.h18
-rw-r--r--common/rfb/SMsgWriter.cxx30
-rw-r--r--common/rfb/SMsgWriter.h13
4 files changed, 168 insertions, 47 deletions
diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx
index ca60da48..cd80df97 100644
--- a/common/rfb/EncodeManager.cxx
+++ b/common/rfb/EncodeManager.cxx
@@ -23,6 +23,7 @@
#include <rfb/SConnection.h>
#include <rfb/SMsgWriter.h>
#include <rfb/UpdateTracker.h>
+#include <rfb/LogWriter.h>
#include <rfb/RawEncoder.h>
#include <rfb/RREEncoder.h>
@@ -33,6 +34,8 @@
using namespace rfb;
+static LogWriter vlog("EncodeManager");
+
// Split each rectangle into smaller ones no larger than this area,
// and no wider than this width.
static const int SubRectMaxArea = 65536;
@@ -73,8 +76,50 @@ struct RectInfo {
};
+static const char *encoderClassName(EncoderClass klass)
+{
+ switch (klass) {
+ case encoderRaw:
+ return "Raw";
+ case encoderRRE:
+ return "RRE";
+ case encoderHextile:
+ return "Hextile";
+ case encoderTight:
+ return "Tight";
+ case encoderTightJPEG:
+ return "Tight (JPEG)";
+ case encoderZRLE:
+ return "ZRLE";
+ }
+
+ return "Unknown Encoder Class";
+}
+
+static const char *encoderTypeName(EncoderType type)
+{
+ switch (type) {
+ case encoderSolid:
+ return "Solid";
+ case encoderBitmap:
+ return "Bitmap";
+ case encoderBitmapRLE:
+ return "Bitmap RLE";
+ case encoderIndexed:
+ return "Indexed";
+ case encoderIndexedRLE:
+ return "Indexed RLE";
+ case encoderFullColour:
+ return "Full Colour";
+ }
+
+ return "Unknown Encoder Type";
+}
+
EncodeManager::EncodeManager(SConnection* conn_) : conn(conn_)
{
+ StatsVector::iterator iter;
+
encoders.resize(encoderClassMax, NULL);
activeEncoders.resize(encoderTypeMax, encoderRaw);
@@ -84,16 +129,78 @@ EncodeManager::EncodeManager(SConnection* conn_) : conn(conn_)
encoders[encoderTight] = new TightEncoder(conn);
encoders[encoderTightJPEG] = new TightJPEGEncoder(conn);
encoders[encoderZRLE] = new ZRLEEncoder(conn);
+
+ updates = 0;
+ stats.resize(encoderClassMax);
+ for (iter = stats.begin();iter != stats.end();++iter) {
+ StatsVector::value_type::iterator iter2;
+ iter->resize(encoderTypeMax);
+ for (iter2 = iter->begin();iter2 != iter->end();++iter2)
+ memset(&*iter2, 0, sizeof(EncoderStats));
+ }
}
EncodeManager::~EncodeManager()
{
std::vector<Encoder*>::iterator iter;
+ logStats();
+
for (iter = encoders.begin();iter != encoders.end();iter++)
delete *iter;
}
+void EncodeManager::logStats()
+{
+ int i, j;
+
+ unsigned rects;
+ unsigned long long pixels, bytes, equivalent;
+
+ double ratio;
+
+ rects = 0;
+ pixels = bytes = equivalent = 0;
+
+ vlog.info("Framebuffer updates: %u", updates);
+
+ for (i = 0;i < stats.size();i++) {
+ // Did this class do anything at all?
+ for (j = 0;j < stats[i].size();j++) {
+ if (stats[i][j].rects != 0)
+ break;
+ }
+ if (j == stats[i].size())
+ continue;
+
+ vlog.info(" %s:", encoderClassName((EncoderClass)i));
+
+ for (j = 0;j < stats[i].size();j++) {
+ if (stats[i][j].rects == 0)
+ continue;
+
+ rects += stats[i][j].rects;
+ pixels += stats[i][j].pixels;
+ bytes += stats[i][j].bytes;
+ equivalent += stats[i][j].equivalent;
+
+ ratio = (double)stats[i][j].equivalent / stats[i][j].bytes;
+
+ vlog.info(" %s: %u rects, %llu pixels",
+ encoderTypeName((EncoderType)j),
+ stats[i][j].rects, stats[i][j].pixels);
+ vlog.info(" %*s %llu bytes (%g ratio)",
+ strlen(encoderTypeName((EncoderType)j)), "",
+ stats[i][j].bytes, ratio);
+ }
+ }
+
+ ratio = (double)equivalent / bytes;
+
+ vlog.info(" Total: %u rects, %llu pixels", rects, pixels);
+ vlog.info(" %llu bytes (%g ratio)", bytes, ratio);
+}
+
bool EncodeManager::supported(int encoding)
{
switch (encoding) {
@@ -114,6 +221,8 @@ void EncodeManager::writeUpdate(const UpdateInfo& ui, const PixelBuffer* pb,
int nRects;
Region changed;
+ updates++;
+
prepareEncoders();
if (conn->cp.supportsLastRect)
@@ -292,6 +401,40 @@ int EncodeManager::computeNumRects(const Region& changed)
return numRects;
}
+Encoder *EncodeManager::startRect(const Rect& rect, int type)
+{
+ Encoder *encoder;
+ int klass, equiv;
+
+ activeType = type;
+ klass = activeEncoders[activeType];
+
+ beforeLength = conn->getOutStream()->length();
+
+ stats[klass][activeType].rects++;
+ stats[klass][activeType].pixels += rect.area();
+ equiv = 12 + rect.area() * conn->cp.pf().bpp/8;
+ stats[klass][activeType].equivalent += equiv;
+
+ encoder = encoders[klass];
+ conn->writer()->startRect(rect, encoder->encoding);
+
+ return encoder;
+}
+
+void EncodeManager::endRect()
+{
+ int klass;
+ int length;
+
+ conn->writer()->endRect();
+
+ length = conn->getOutStream()->length() - beforeLength;
+
+ klass = activeEncoders[activeType];
+ stats[klass][activeType].bytes += length;
+}
+
void EncodeManager::writeCopyRects(const UpdateInfo& ui)
{
std::vector<Rect> rects;
@@ -362,8 +505,7 @@ void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
}
// Send solid-color rectangle.
- encoder = encoders[activeEncoders[encoderSolid]];
- conn->writer()->startRect(erp, encoder->encoding);
+ encoder = startRect(erp, encoderSolid);
if (encoder->flags & EncoderUseNativePF) {
encoder->writeSolidRect(erp.width(), erp.height(),
pb->getPF(), colourValue);
@@ -377,7 +519,7 @@ void EncodeManager::writeSolidRects(Region *changed, const PixelBuffer* pb)
encoder->writeSolidRect(erp.width(), erp.height(),
conn->cp.pf(), converted);
}
- conn->writer()->endRect();
+ endRect();
changed->assign_subtract(Region(erp));
@@ -507,14 +649,14 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb)
type = encoderIndexed;
}
- encoder = encoders[activeEncoders[type]];
+ encoder = startRect(rect, type);
if (encoder->flags & EncoderUseNativePF)
ppb = preparePixelBuffer(rect, pb, false);
- conn->writer()->startRect(rect, encoder->encoding);
encoder->writeRect(ppb, info.palette);
- conn->writer()->endRect();
+
+ endRect();
}
bool EncodeManager::checkSolidTile(const Rect& r, const rdr::U8* colourValue,
diff --git a/common/rfb/EncodeManager.h b/common/rfb/EncodeManager.h
index df0275ce..a694e063 100644
--- a/common/rfb/EncodeManager.h
+++ b/common/rfb/EncodeManager.h
@@ -41,6 +41,8 @@ namespace rfb {
EncodeManager(SConnection* conn);
~EncodeManager();
+ void logStats();
+
// Hack to let ConnParams calculate the client's preferred encoding
static bool supported(int encoding);
@@ -52,6 +54,9 @@ namespace rfb {
int computeNumRects(const Region& changed);
+ Encoder *startRect(const Rect& rect, int type);
+ void endRect();
+
void writeCopyRects(const UpdateInfo& ui);
void writeSolidRects(Region *changed, const PixelBuffer* pb);
void writeRects(const Region& changed, const PixelBuffer* pb);
@@ -97,6 +102,19 @@ namespace rfb {
std::vector<Encoder*> encoders;
std::vector<int> activeEncoders;
+ struct EncoderStats {
+ unsigned rects;
+ unsigned long long bytes;
+ unsigned long long pixels;
+ unsigned long long equivalent;
+ };
+ typedef std::vector< std::vector<struct EncoderStats> > StatsVector;
+
+ unsigned updates;
+ StatsVector stats;
+ int activeType;
+ int beforeLength;
+
class OffsetPixelBuffer : public FullFramePixelBuffer {
public:
OffsetPixelBuffer() {}
diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx
index 0d61292c..9aee96d2 100644
--- a/common/rfb/SMsgWriter.cxx
+++ b/common/rfb/SMsgWriter.cxx
@@ -33,31 +33,15 @@ using namespace rfb;
static LogWriter vlog("SMsgWriter");
SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
- : cp(cp_), os(os_), currentEncoding(0),
+ : cp(cp_), os(os_),
nRectsInUpdate(0), nRectsInHeader(0),
needSetDesktopSize(false), needExtendedDesktopSize(false),
- needSetDesktopName(false), needSetCursor(false), needSetXCursor(false),
- lenBeforeRect(0), updatesSent(0), rawBytesEquivalent(0)
+ needSetDesktopName(false), needSetCursor(false), needSetXCursor(false)
{
- for (int i = 0; i <= encodingMax; i++) {
- bytesSent[i] = 0;
- rectsSent[i] = 0;
- }
}
SMsgWriter::~SMsgWriter()
{
- vlog.info("framebuffer updates %d",updatesSent);
- int bytes = 0;
- for (int i = 0; i <= encodingMax; i++) {
- if (i != encodingCopyRect)
- bytes += bytesSent[i];
- if (rectsSent[i])
- vlog.info(" %s rects %d, bytes %d",
- encodingName(i), rectsSent[i], bytesSent[i]);
- }
- vlog.info(" raw bytes equivalent %llu, compression ratio %f",
- rawBytesEquivalent, (double)rawBytesEquivalent / bytes);
}
void SMsgWriter::writeServerInit()
@@ -276,7 +260,6 @@ void SMsgWriter::writeFramebufferUpdateEnd()
os->writeU32(pseudoEncodingLastRect);
}
- updatesSent++;
endMsg();
}
@@ -293,11 +276,6 @@ void SMsgWriter::startRect(const Rect& r, int encoding)
if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
throw Exception("SMsgWriter::startRect: nRects out of sync");
- currentEncoding = encoding;
- lenBeforeRect = os->length();
- if (encoding != encodingCopyRect)
- rawBytesEquivalent += 12 + r.width() * r.height() * (cp->pf().bpp/8);
-
os->writeS16(r.tl.x);
os->writeS16(r.tl.y);
os->writeU16(r.width());
@@ -307,10 +285,6 @@ void SMsgWriter::startRect(const Rect& r, int encoding)
void SMsgWriter::endRect()
{
- if (currentEncoding <= encodingMax) {
- bytesSent[currentEncoding] += os->length() - lenBeforeRect;
- rectsSent[currentEncoding]++;
- }
}
void SMsgWriter::startMsg(int type)
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index deddd3cd..917b933c 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -109,11 +109,6 @@ namespace rfb {
void startRect(const Rect& r, int enc);
void endRect();
- int getUpdatesSent() { return updatesSent; }
- int getRectsSent(int encoding) { return rectsSent[encoding]; }
- int getBytesSent(int encoding) { return bytesSent[encoding]; }
- rdr::U64 getRawBytesEquivalent() { return rawBytesEquivalent; }
-
protected:
void startMsg(int type);
void endMsg();
@@ -137,8 +132,6 @@ namespace rfb {
ConnParams* cp;
rdr::OutStream* os;
- int currentEncoding;
-
int nRectsInUpdate;
int nRectsInHeader;
@@ -149,12 +142,6 @@ namespace rfb {
bool needSetCursor;
bool needSetXCursor;
- int lenBeforeRect;
- int updatesSent;
- int bytesSent[encodingMax+1];
- int rectsSent[encodingMax+1];
- rdr::U64 rawBytesEquivalent;
-
typedef struct {
rdr::U16 reason, result;
int fb_width, fb_height;