Revision 999342a0 ui/vnc.c

b/ui/vnc.c
35 35
#define VNC_REFRESH_INTERVAL_BASE 30
36 36
#define VNC_REFRESH_INTERVAL_INC  50
37 37
#define VNC_REFRESH_INTERVAL_MAX  2000
38
static const struct timeval VNC_REFRESH_STATS = { 0, 500000 };
39
static const struct timeval VNC_REFRESH_LOSSY = { 2, 0 };
38 40

  
39 41
#include "vnc_keysym.h"
40 42
#include "d3des.h"
......
2258 2260
    return 0;
2259 2261
}
2260 2262

  
2263
static VncRectStat *vnc_stat_rect(VncDisplay *vd, int x, int y)
2264
{
2265
    struct VncSurface *vs = &vd->guest;
2266

  
2267
    return &vs->stats[y / VNC_STAT_RECT][x / VNC_STAT_RECT];
2268
}
2269

  
2270
static void vnc_update_stats(VncDisplay *vd,  struct timeval * tv)
2271
{
2272
    int x, y;
2273
    struct timeval res;
2274

  
2275
    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
2276
        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
2277
            VncRectStat *rect = vnc_stat_rect(vd, x, y);
2278

  
2279
            rect->updated = false;
2280
        }
2281
    }
2282

  
2283
    timersub(tv, &VNC_REFRESH_STATS, &res);
2284

  
2285
    if (timercmp(&vd->guest.last_freq_check, &res, >)) {
2286
        return ;
2287
    }
2288
    vd->guest.last_freq_check = *tv;
2289

  
2290
    for (y = 0; y < vd->guest.ds->height; y += VNC_STAT_RECT) {
2291
        for (x = 0; x < vd->guest.ds->width; x += VNC_STAT_RECT) {
2292
            VncRectStat *rect= vnc_stat_rect(vd, x, y);
2293
            int count = ARRAY_SIZE(rect->times);
2294
            struct timeval min, max;
2295

  
2296
            if (!timerisset(&rect->times[count - 1])) {
2297
                continue ;
2298
            }
2299

  
2300
            max = rect->times[(rect->idx + count - 1) % count];
2301
            timersub(tv, &max, &res);
2302

  
2303
            if (timercmp(&res, &VNC_REFRESH_LOSSY, >)) {
2304
                rect->freq = 0;
2305
                memset(rect->times, 0, sizeof (rect->times));
2306
                continue ;
2307
            }
2308

  
2309
            min = rect->times[rect->idx];
2310
            max = rect->times[(rect->idx + count - 1) % count];
2311
            timersub(&max, &min, &res);
2312

  
2313
            rect->freq = res.tv_sec + res.tv_usec / 1000000.;
2314
            rect->freq /= count;
2315
            rect->freq = 1. / rect->freq;
2316
        }
2317
    }
2318
}
2319

  
2320
double vnc_update_freq(VncState *vs, int x, int y, int w, int h)
2321
{
2322
    int i, j;
2323
    double total = 0;
2324
    int num = 0;
2325

  
2326
    x =  (x / VNC_STAT_RECT) * VNC_STAT_RECT;
2327
    y =  (y / VNC_STAT_RECT) * VNC_STAT_RECT;
2328

  
2329
    for (j = y; j <= y + h; j += VNC_STAT_RECT) {
2330
        for (i = x; i <= x + w; i += VNC_STAT_RECT) {
2331
            total += vnc_stat_rect(vs->vd, i, j)->freq;
2332
            num++;
2333
        }
2334
    }
2335

  
2336
    if (num) {
2337
        return total / num;
2338
    } else {
2339
        return 0;
2340
    }
2341
}
2342

  
2343
static void vnc_rect_updated(VncDisplay *vd, int x, int y, struct timeval * tv)
2344
{
2345
    VncRectStat *rect;
2346

  
2347
    rect = vnc_stat_rect(vd, x, y);
2348
    if (rect->updated) {
2349
        return ;
2350
    }
2351
    rect->times[rect->idx] = *tv;
2352
    rect->idx = (rect->idx + 1) % ARRAY_SIZE(rect->times);
2353
    rect->updated = true;
2354
}
2355

  
2261 2356
static int vnc_refresh_server_surface(VncDisplay *vd)
2262 2357
{
2263 2358
    int y;
......
2268 2363
    VncState *vs;
2269 2364
    int has_dirty = 0;
2270 2365

  
2366
    struct timeval tv;
2367

  
2368
    gettimeofday(&tv, NULL);
2369
    vnc_update_stats(vd, &tv);
2370

  
2271 2371
    /*
2272 2372
     * Walk through the guest dirty map.
2273 2373
     * Check and copy modified bits from guest to server surface.
......
2294 2394
                if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0)
2295 2395
                    continue;
2296 2396
                memcpy(server_ptr, guest_ptr, cmp_bytes);
2397
                vnc_rect_updated(vd, x, y, &tv);
2297 2398
                QTAILQ_FOREACH(vs, &vd->clients, next) {
2298 2399
                    vnc_set_bit(vs->dirty[y], (x / 16));
2299 2400
                }

Also available in: Unified diff