On Thu, Mar 11, 2021 at 10:38 PM Daniel P. Berrangé <berra...@redhat.com>
wrote:

> A long time ago the VNC server code had some memory corruption
> fixes done in:
>
>   commit bea60dd7679364493a0d7f5b54316c767cf894ef
>   Author: Peter Lieven <p...@kamp.de>
>   Date:   Mon Jun 30 10:57:51 2014 +0200
>
>     ui/vnc: fix potential memory corruption issues
>
> One of the implications of the fix was that the VNC server would have a
> thin black bad down the right hand side if the guest desktop width was
> not a multiple of 16. In practice this was a non-issue since the VNC
> server was always honouring a guest specified resolution and guests
> essentially always pick from a small set of sane resolutions likely in
> real world hardware.
>
> We recently introduced support for the extended desktop resize extension
> and as a result the VNC client has ability to specify an arbitrary
> desktop size and the guest OS may well honour it exactly. As a result we
> no longer have any guarantee that the width will be a multiple of 16,
> and so when resizing the desktop we have a 93% chance of getting the
> black bar on the right hand size.
>
> The VNC server maintains three different desktop dimensions
>
>  1. The guest surface
>  2. The server surface
>  3. The client desktop
>
> The requirement for the width to be a multiple of 16 only applies to
> item 2, the server surface, for the purpose of doing dirty bitmap
> tracking.
>
> Normally we will set the client desktop size to always match the server
> surface size, but that's not a strict requirement. In order to cope with
> clients that don't support the desktop size encoding, we already allow
> for the client desktop to be a different size that the server surface.
>
> Thus we can trivially eliminate the black bar, but setting the client
> desktop size to be the un-rounded server surface size - the so called
> "true width".
>
> Signed-off-by: Daniel P. Berrangé <berra...@redhat.com>
> ---
>  ui/trace-events |  2 ++
>  ui/vnc.c        | 23 +++++++++++++++++++----
>  ui/vnc.h        |  1 +
>  3 files changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/ui/trace-events b/ui/trace-events
> index 3838ae2d84..5d1da6f236 100644
> --- a/ui/trace-events
> +++ b/ui/trace-events
> @@ -59,6 +59,8 @@ vnc_client_throttle_audio(void *state, void *ioc, size_t
> offset) "VNC client thr
>  vnc_client_unthrottle_forced(void *state, void *ioc) "VNC client
> unthrottle forced offset state=%p ioc=%p"
>  vnc_client_unthrottle_incremental(void *state, void *ioc, size_t offset)
> "VNC client unthrottle incremental state=%p ioc=%p offset=%zu"
>  vnc_client_output_limit(void *state, void *ioc, size_t offset, size_t
> threshold) "VNC client output limit state=%p ioc=%p offset=%zu
> threshold=%zu"
> +vnc_server_dpy_pageflip(void *dpy, int w, int h, int fmt) "VNC server dpy
> pageflip dpy=%p size=%dx%d fmt=%d"
> +vnc_server_dpy_recreate(void *dpy, int w, int h, int fmt) "VNC server dpy
> recreate dpy=%p size=%dx%d fmt=%d"
>  vnc_job_add_rect(void *state, void *job, int x, int y, int w, int h) "VNC
> add rect state=%p job=%p offset=%d,%d size=%dx%d"
>  vnc_job_discard_rect(void *state, void *job, int x, int y, int w, int h)
> "VNC job discard rect state=%p job=%p offset=%d,%d size=%dx%d"
>  vnc_job_clamp_rect(void *state, void *job, int x, int y, int w, int h)
> "VNC job clamp rect state=%p job=%p offset=%d,%d size=%dx%d"
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 8c9890b3cd..9c004a11f4 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -608,6 +608,11 @@ static int vnc_width(VncDisplay *vd)
>                                         VNC_DIRTY_PIXELS_PER_BIT));
>  }
>
> +static int vnc_true_width(VncDisplay *vd)
> +{
> +    return MIN(VNC_MAX_WIDTH, surface_width(vd->ds));
> +}
> +
>  static int vnc_height(VncDisplay *vd)
>  {
>      return MIN(VNC_MAX_HEIGHT, surface_height(vd->ds));
> @@ -691,16 +696,16 @@ static void vnc_desktop_resize(VncState *vs)
>                              !vnc_has_feature(vs,
> VNC_FEATURE_RESIZE_EXT))) {
>          return;
>      }
> -    if (vs->client_width == pixman_image_get_width(vs->vd->server) &&
> +    if (vs->client_width == vs->vd->true_width &&
>          vs->client_height == pixman_image_get_height(vs->vd->server)) {
>          return;
>      }
>
> -    assert(pixman_image_get_width(vs->vd->server) < 65536 &&
> -           pixman_image_get_width(vs->vd->server) >= 0);
> +    assert(vs->vd->true_width < 65536 &&
> +           vs->vd->true_width >= 0);
>      assert(pixman_image_get_height(vs->vd->server) < 65536 &&
>             pixman_image_get_height(vs->vd->server) >= 0);
> -    vs->client_width = pixman_image_get_width(vs->vd->server);
> +    vs->client_width = vs->vd->true_width;
>      vs->client_height = pixman_image_get_height(vs->vd->server);
>
>      if (vnc_has_feature(vs, VNC_FEATURE_RESIZE_EXT)) {
> @@ -774,6 +779,7 @@ static void vnc_update_server_surface(VncDisplay *vd)
>
>      width = vnc_width(vd);
>      height = vnc_height(vd);
> +    vd->true_width = vnc_true_width(vd);
>      vd->server = pixman_image_create_bits(VNC_SERVER_FB_FORMAT,
>                                            width, height,
>                                            NULL, 0);
> @@ -809,13 +815,22 @@ static void vnc_dpy_switch(DisplayChangeListener
> *dcl,
>      vd->guest.fb = pixman_image_ref(surface->image);
>      vd->guest.format = surface->format;
>
> +
>      if (pageflip) {
> +        trace_vnc_server_dpy_pageflip(vd,
> +                                      surface_width(surface),
> +                                      surface_height(surface),
> +                                      surface_format(surface));
>          vnc_set_area_dirty(vd->guest.dirty, vd, 0, 0,
>                             surface_width(surface),
>                             surface_height(surface));
>          return;
>      }
>
> +    trace_vnc_server_dpy_recreate(vd,
> +                                  surface_width(surface),
> +                                  surface_height(surface),
> +                                  surface_format(surface));
>      /* server surface */
>      vnc_update_server_surface(vd);
>
> diff --git a/ui/vnc.h b/ui/vnc.h
> index 116463d5f0..d4f3e15558 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -164,6 +164,7 @@ struct VncDisplay
>
>      struct VncSurface guest;   /* guest visible surface (aka ds->surface)
> */
>      pixman_image_t *server;    /* vnc server surface */
> +    int true_width; /* server surface width before rounding up */
>
>      const char *id;
>      QTAILQ_ENTRY(VncDisplay) next;
> --
> 2.29.2
>
>
>
Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com>


-- 
Marc-André Lureau

Reply via email to