diff options
Diffstat (limited to 'vncviewer')
-rw-r--r-- | vncviewer/CConn.cxx | 21 | ||||
-rw-r--r-- | vncviewer/CConn.h | 7 | ||||
-rw-r--r-- | vncviewer/DesktopWindow.cxx | 155 | ||||
-rw-r--r-- | vncviewer/DesktopWindow.h | 18 |
4 files changed, 199 insertions, 2 deletions
diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index a692732c..addc30df 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -73,7 +73,7 @@ static const PixelFormat mediumColourPF(8, 8, false, true, CConn::CConn(const char* vncServerName, network::Socket* socket=NULL) : serverHost(0), serverPort(0), desktop(NULL), - pendingPFChange(false), + frameCount(0), pixelCount(0), pendingPFChange(false), currentEncoding(encodingTight), lastServerEncoding((unsigned int)-1), formatChange(false), encodingChange(false), firstUpdate(true), pendingUpdate(false), continuousUpdates(false), @@ -223,6 +223,21 @@ const char *CConn::connectionInfo() return infoText; } +unsigned CConn::getFrameCount() +{ + return frameCount; +} + +unsigned CConn::getPixelCount() +{ + return pixelCount; +} + +unsigned CConn::getPosition() +{ + return sock->inStream().pos(); +} + // The RFB core is not properly asynchronous, so it calls this callback // whenever it needs to block to wait for more data. Since FLTK is // monitoring the socket, we just make sure FLTK gets to run. @@ -365,6 +380,8 @@ void CConn::framebufferUpdateEnd() { CConnection::framebufferUpdateEnd(); + frameCount++; + Fl::remove_timeout(handleUpdateTimeout, this); desktop->updateWindow(); @@ -441,6 +458,8 @@ void CConn::dataRect(const Rect& r, int encoding) CConnection::dataRect(r, encoding); sock->inStream().stopTiming(); + + pixelCount += r.area(); } void CConn::setCursor(int width, int height, const Point& hotspot, diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index d6dd4a75..93cc278f 100644 --- a/vncviewer/CConn.h +++ b/vncviewer/CConn.h @@ -40,6 +40,10 @@ public: const char *connectionInfo(); + unsigned getFrameCount(); + unsigned getPixelCount(); + unsigned getPosition(); + // FdInStreamBlockCallback methods void blockCallback(); @@ -89,6 +93,9 @@ private: DesktopWindow *desktop; + unsigned frameCount; + unsigned pixelCount; + rfb::PixelFormat serverPF; rfb::PixelFormat fullColourPF; diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 8fdd59b7..1f0f55f2 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -64,7 +64,9 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name, CConn* cc_) : Fl_Window(w, h), cc(cc_), offscreen(NULL), overlay(NULL), firstUpdate(true), - delayedFullscreen(false), delayedDesktopSize(false) + delayedFullscreen(false), delayedDesktopSize(false), + statsLastFrame(0), statsLastPixels(0), statsLastPosition(0), + statsGraph(NULL) { Fl_Group* group; @@ -174,6 +176,12 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name, fullscreen_on(); } + // Throughput graph for debugging + if (vlog.getLevel() >= LogWriter::LEVEL_DEBUG) { + memset(&stats, 0, sizeof(stats)); + Fl::add_timeout(0, handleStatsTimeout, this); + } + // Show hint about menu key Fl::add_timeout(0.5, menuOverlay, this); } @@ -187,6 +195,7 @@ DesktopWindow::~DesktopWindow() Fl::remove_timeout(handleResizeTimeout, this); Fl::remove_timeout(handleFullscreenTimeout, this); Fl::remove_timeout(handleEdgeScroll, this); + Fl::remove_timeout(handleStatsTimeout, this); Fl::remove_timeout(menuOverlay, this); Fl::remove_timeout(updateOverlay, this); @@ -195,6 +204,8 @@ DesktopWindow::~DesktopWindow() delete overlay; delete offscreen; + delete statsGraph; + // FLTK automatically deletes all child widgets, so we shouldn't touch // them ourselves here } @@ -325,6 +336,23 @@ void DesktopWindow::draw() update_child(*viewport); } + // Debug graph (if active) + if (statsGraph) { + int ox, oy, ow, oh; + + ox = X = w() - statsGraph->width() - 30; + oy = Y = h() - statsGraph->height() - 30; + ow = statsGraph->width(); + oh = statsGraph->height(); + + fl_clip_box(ox, oy, ow, oh, ox, oy, ow, oh); + + if (offscreen) + statsGraph->blend(offscreen, ox - X, oy - Y, ox, oy, ow, oh, 204); + else + statsGraph->blend(ox - X, oy - Y, ox, oy, ow, oh, 204); + } + // Overlay (if active) if (overlay) { int ox, oy, ow, oh; @@ -1161,3 +1189,128 @@ void DesktopWindow::handleEdgeScroll(void *data) Fl::repeat_timeout(0.1, handleEdgeScroll, data); } + +void DesktopWindow::handleStatsTimeout(void *data) +{ + DesktopWindow *self = (DesktopWindow*)data; + + const size_t statsCount = sizeof(stats)/sizeof(stats[0]); + + unsigned frame, pixels, pos; + unsigned elapsed; + + const unsigned statsWidth = 200; + const unsigned statsHeight = 100; + const unsigned graphWidth = statsWidth - 10; + const unsigned graphHeight = statsHeight - 25; + + Fl_Image_Surface *surface; + Fl_RGB_Image *image; + + unsigned maxFPS, maxPPS, maxBPS; + size_t i; + + char buffer[256]; + + frame = self->cc->getFrameCount(); + pixels = self->cc->getPixelCount(); + pos = self->cc->getPosition(); + elapsed = msSince(&self->statsLastTime); + if (elapsed < 1) + elapsed = 1; + + memmove(&self->stats[0], &self->stats[1], sizeof(stats[0])*(statsCount-1)); + + self->stats[statsCount-1].fps = (frame - self->statsLastFrame) * 1000 / elapsed; + self->stats[statsCount-1].pps = (pixels - self->statsLastPixels) * 1000 / elapsed; + self->stats[statsCount-1].bps = (pos - self->statsLastPosition) * 1000 / elapsed; + + gettimeofday(&self->statsLastTime, NULL); + self->statsLastFrame = frame; + self->statsLastPixels = pixels; + self->statsLastPosition = pos; + +#if !defined(WIN32) && !defined(__APPLE__) + // FLTK < 1.3.5 crashes if fl_gc is unset + if (!fl_gc) + fl_gc = XDefaultGC(fl_display, 0); +#endif + + surface = new Fl_Image_Surface(statsWidth, statsHeight); + surface->set_current(); + + fl_rectf(0, 0, statsWidth, statsHeight, FL_BLACK); + + fl_rect(5, 5, graphWidth, graphHeight, FL_WHITE); + + maxFPS = maxPPS = maxBPS = 0; + for (i = 0;i < statsCount;i++) { + if (self->stats[i].fps > maxFPS) + maxFPS = self->stats[i].fps; + if (self->stats[i].pps > maxPPS) + maxPPS = self->stats[i].pps; + if (self->stats[i].bps > maxBPS) + maxBPS = self->stats[i].bps; + } + + if (maxFPS != 0) { + fl_color(FL_GREEN); + for (i = 0;i < statsCount-1;i++) { + fl_line(5 + i * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i].fps / maxFPS, + 5 + (i+1) * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i+1].fps / maxFPS); + } + } + + if (maxPPS != 0) { + fl_color(FL_YELLOW); + for (i = 0;i < statsCount-1;i++) { + fl_line(5 + i * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i].pps / maxPPS, + 5 + (i+1) * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i+1].pps / maxPPS); + } + } + + if (maxBPS != 0) { + fl_color(FL_RED); + for (i = 0;i < statsCount-1;i++) { + fl_line(5 + i * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i].bps / maxBPS, + 5 + (i+1) * graphWidth / statsCount, + 5 + graphHeight - graphHeight * self->stats[i+1].bps / maxBPS); + } + } + + fl_font(FL_HELVETICA, 10); + + fl_color(FL_GREEN); + snprintf(buffer, sizeof(buffer), "%u fps", self->stats[statsCount-1].fps); + fl_draw(buffer, 5, statsHeight - 5); + + fl_color(FL_YELLOW); + siPrefix(self->stats[statsCount-1].pps * 8, "pix/s", + buffer, sizeof(buffer), 3); + fl_draw(buffer, 5 + (statsWidth-10)/3, statsHeight - 5); + + fl_color(FL_RED); + iecPrefix(self->stats[statsCount-1].bps * 8, "Bps", + buffer, sizeof(buffer), 3); + fl_draw(buffer, 5 + (statsWidth-10)*2/3, statsHeight - 5); + + image = surface->image(); + delete surface; + + Fl_Display_Device::display_device()->set_current(); + + delete self->statsGraph; + self->statsGraph = new Surface(image); + delete image; + + self->damage(FL_DAMAGE_CHILD, self->w() - statsWidth - 30, + self->h() - statsHeight - 30, + statsWidth, statsHeight); + + Fl::repeat_timeout(0.5, handleStatsTimeout, data); +} diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h index 11f3dc20..4224699c 100644 --- a/vncviewer/DesktopWindow.h +++ b/vncviewer/DesktopWindow.h @@ -22,6 +22,8 @@ #include <map> +#include <sys/time.h> + #include <rfb/Rect.h> #include <rfb/Pixel.h> @@ -103,6 +105,8 @@ private: static void handleScroll(Fl_Widget *wnd, void *data); static void handleEdgeScroll(void *data); + static void handleStatsTimeout(void *data); + private: CConn* cc; Fl_Scrollbar *hscroll, *vscroll; @@ -115,6 +119,20 @@ private: bool firstUpdate; bool delayedFullscreen; bool delayedDesktopSize; + + struct statsEntry { + unsigned fps; + unsigned pps; + unsigned bps; + }; + struct statsEntry stats[100]; + + struct timeval statsLastTime; + unsigned statsLastFrame; + unsigned statsLastPixels; + unsigned statsLastPosition; + + Surface *statsGraph; }; #endif |