[Spice-devel] [PATCH 3/3] display: move more logic in add_drawable()

Frediano Ziglio fziglio at redhat.com
Fri Nov 27 06:21:33 PST 2015


> 
> From: Marc-André Lureau <marcandre.lureau at gmail.com>
> 
> Acked-by: Fabiano FidĂȘncio <fidencio at redhat.com>
> fziglio ???
> ---
>  server/display-channel.c | 129
>  +++++++++++++++++------------------------------
>  server/display-channel.h |  10 ++--
>  server/red_worker.c      |  18 ++++---
>  3 files changed, 60 insertions(+), 97 deletions(-)
> 
> diff --git a/server/display-channel.c b/server/display-channel.c
> index 0b4415b..d8ab849 100644
> --- a/server/display-channel.c
> +++ b/server/display-channel.c
> @@ -916,7 +916,7 @@ void display_channel_print_stats(DisplayChannel *display)
>  #endif
>  }
>  
> -static inline void red_inc_surfaces_drawable_dependencies(DisplayChannel
> *display, Drawable *drawable)
> +static void drawable_ref_surface_deps(DisplayChannel *display, Drawable
> *drawable)
>  {
>      int x;
>      int surface_id;
> @@ -932,23 +932,19 @@ static inline void
> red_inc_surfaces_drawable_dependencies(DisplayChannel *displa
>      }
>  }
>  
> -static void red_get_area(DisplayChannel *display, int surface_id, const
> SpiceRect *area,
> -                         uint8_t *dest, int dest_stride, int update)
> +static void surface_read_bits(DisplayChannel *display, int surface_id,
> +                              const SpiceRect *area, uint8_t *dest, int
> dest_stride)
>  {
>      SpiceCanvas *canvas;
> -    RedSurface *surface;
> -
> -    surface = &display->surfaces[surface_id];
> -    if (update) {
> -        display_channel_draw(display, area, surface_id);
> -    }
> +    RedSurface *surface = &display->surfaces[surface_id];
>  
>      canvas = surface->context.canvas;
>      canvas->ops->read_bits(canvas, dest, dest_stride, area);
>  }
>  
> -static int display_channel_handle_self_bitmap(DisplayChannel *display,
> Drawable *drawable)
> +static void handle_self_bitmap(DisplayChannel *display, Drawable *drawable)
>  {
> +    RedDrawable *red_drawable = drawable->red_drawable;
>      SpiceImage *image;
>      int32_t width;
>      int32_t height;
> @@ -957,26 +953,17 @@ static int
> display_channel_handle_self_bitmap(DisplayChannel *display, Drawable
>      RedSurface *surface;
>      int bpp;
>      int all_set;
> -    RedDrawable *red_drawable = drawable->red_drawable;
> -
> -    if (!red_drawable->self_bitmap) {
> -        return TRUE;
> -    }
>  

This check is moved below.

>      surface = &display->surfaces[drawable->surface_id];
>  
>      bpp = SPICE_SURFACE_FMT_DEPTH(surface->context.format) / 8;
> -
> -    width = red_drawable->self_bitmap_area.right
> -            - red_drawable->self_bitmap_area.left;
> -    height = red_drawable->self_bitmap_area.bottom
> -            - red_drawable->self_bitmap_area.top;
> +    width = red_drawable->self_bitmap_area.right -
> red_drawable->self_bitmap_area.left;
> +    height = red_drawable->self_bitmap_area.bottom -
> red_drawable->self_bitmap_area.top;
>      dest_stride = SPICE_ALIGN(width * bpp, 4);
>  
>      image = spice_new0(SpiceImage, 1);
>      image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP;
>      image->descriptor.flags = 0;
> -
>      QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_RED,
>      display_channel_generate_uid(display));
>      image->u.bitmap.flags = surface->context.top_down ?
>      SPICE_BITMAP_FLAGS_TOP_DOWN : 0;
>      image->u.bitmap.format =
>      spice_bitmap_from_surface_type(surface->context.format);
> @@ -989,8 +976,9 @@ static int
> display_channel_handle_self_bitmap(DisplayChannel *display, Drawable
>      image->u.bitmap.data = spice_chunks_new_linear(dest, height *
>      dest_stride);
>      image->u.bitmap.data->flags |= SPICE_CHUNKS_FLAGS_FREE;
>  
> -    red_get_area(display, drawable->surface_id,
> -                 &red_drawable->self_bitmap_area, dest, dest_stride, TRUE);
> +    display_channel_draw(display, &red_drawable->self_bitmap_area,
> drawable->surface_id);
> +    surface_read_bits(display, drawable->surface_id,
> +        &red_drawable->self_bitmap_area, dest, dest_stride);
>  
>      /* For 32bit non-primary surfaces we need to keep any non-zero
>         high bytes as the surface may be used as source to an alpha_blend */
> @@ -1005,26 +993,25 @@ static int
> display_channel_handle_self_bitmap(DisplayChannel *display, Drawable
>      }
>  
>      red_drawable->self_bitmap_image = image;
> -    return TRUE;
>  }
>  
> -static inline void add_to_surface_dependency(DisplayChannel *display, int
> depend_on_surface_id,
> -                                             DependItem *depend_item,
> Drawable *drawable)
> +static void surface_add_reverse_dependency(DisplayChannel *display, int
> surface_id,
> +                                           DependItem *depend_item, Drawable
> *drawable)
>  {
>      RedSurface *surface;
>  
> -    if (depend_on_surface_id == -1) {
> +    if (surface_id == -1) {
>          depend_item->drawable = NULL;
>          return;
>      }
>  
> -    surface = &display->surfaces[depend_on_surface_id];
> +    surface = &display->surfaces[surface_id];
>  
>      depend_item->drawable = drawable;
>      ring_add(&surface->depend_on_me, &depend_item->ring_item);
>  }
>  
> -static inline int red_handle_surfaces_dependencies(DisplayChannel *display,
> Drawable *drawable)
> +static int handle_surface_deps(DisplayChannel *display, Drawable *drawable)
>  {
>      int x;
>  
> @@ -1032,8 +1019,8 @@ static inline int
> red_handle_surfaces_dependencies(DisplayChannel *display, Draw
>          // surface self dependency is handled by shadows in "current", or by
>          // handle_self_bitmap
>          if (drawable->surface_deps[x] != drawable->surface_id) {
> -            add_to_surface_dependency(display, drawable->surface_deps[x],
> -                                      &drawable->depend_items[x], drawable);
> +            surface_add_reverse_dependency(display,
> drawable->surface_deps[x],
> +                                           &drawable->depend_items[x],
> drawable);
>  
>              if (drawable->surface_deps[x] == 0) {
>                  QRegion depend_region;
> @@ -1091,49 +1078,28 @@ static int validate_drawable_bbox(DisplayChannel
> *display, RedDrawable *drawable
>          return TRUE;
>  }
>  
> -Drawable *display_channel_get_drawable(DisplayChannel *display, uint8_t
> effect,
> -                                       RedDrawable *red_drawable, uint32_t
> group_id,
> -                                       uint32_t process_commands_generation)
> -{
> -    Drawable *drawable;
> -    int x;
> -
> -    if (!validate_drawable_bbox(display, red_drawable)) {
> -        return NULL;
> -    }
> -    for (x = 0; x < 3; ++x) {
> -        if (red_drawable->surface_deps[x] != -1
> -            && !validate_surface(display, red_drawable->surface_deps[x])) {
> -            return NULL;
> -        }
> -    }
>  
> -    drawable = display_channel_drawable_try_new(display, group_id,
> process_commands_generation);
> -    if (!drawable) {
> -        return NULL;
> -    }
> -
> -    drawable->tree_item.effect = effect;
> -    drawable->red_drawable = red_drawable_ref(red_drawable);
> -
> -    drawable->surface_id = red_drawable->surface_id;
> -    memcpy(drawable->surface_deps, red_drawable->surface_deps,
> sizeof(drawable->surface_deps));
> -

These looks a bit wrong here. I means, you copy surfaces without incrementing
references so if you need to free drawable you will get less reference then expected.
Looks like a bad dependency. This patch is going to address (perhaps) this but
IMHO not in a good way. display_channel_add_drawable is going to do too much.

> -    return drawable;
> -}
> -
> -void display_channel_add_drawable(DisplayChannel *display, Drawable
> *drawable)
> +int display_channel_add_drawable(DisplayChannel *display, Drawable
> *drawable, RedDrawable *red_drawable)
>  {
> -    int success = FALSE, surface_id = drawable->surface_id;
> -    RedDrawable *red_drawable = drawable->red_drawable;
> +    int surface_id, x;
>  
> +    drawable->red_drawable = red_drawable_ref(red_drawable);
> +    drawable->tree_item.effect = red_drawable->effect;
> +    surface_id = drawable->surface_id = red_drawable->surface_id;
> +    if (!validate_drawable_bbox(display, red_drawable))
> +        return FALSE;
> +    // FIXME here can leak if after we return!
> +    display->surfaces[surface_id].refs++;

this should be moved after all read-only checks...

>      red_drawable->mm_time = reds_get_mm_time();

This line looks misplaced

> -    surface_id = drawable->surface_id;
>  
> -    display->surfaces[surface_id].refs++;
> +    for (x = 0; x < 3; ++x) {
> +        drawable->surface_deps[x] = red_drawable->surface_deps[x];
> +        if (drawable->surface_deps[x] != -1
> +            && !validate_surface(display, drawable->surface_deps[x]))
> +            return FALSE;
> +    }
>  

or when we are returning here reference counting problems will happen.

A test would be awesome here!

- test invalid surface_id
- test invalid surface_deps
- all mix possible

On failure references to surfaces should be the same.

>      region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox);
> -
>      if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) {
>          QRegion rgn;
>  
> @@ -1143,44 +1109,43 @@ void display_channel_add_drawable(DisplayChannel
> *display, Drawable *drawable)
>          region_destroy(&rgn);
>      }
>  
> +    if (region_is_empty(&drawable->tree_item.base.rgn))
> +        return TRUE;
> +

Is this move not causing possible leaks ?

>      /*
>          surface->refs is affected by a drawable (that is
>          dependent on the surface) as long as the drawable is alive.
>          However, surface->depend_on_me is affected by a drawable only
>          as long as it is in the current tree (hasn't been rendered yet).
>      */
> -    red_inc_surfaces_drawable_dependencies(display, drawable);
> +    drawable_ref_surface_deps(display, drawable);
>  
> -    if (region_is_empty(&drawable->tree_item.base.rgn)) {
> -        return;
> -    }
> -
> -    if (!display_channel_handle_self_bitmap(display, drawable)) {
> -        return;
> -    }
> +    if (red_drawable->self_bitmap)
> +        handle_self_bitmap(display, drawable);
>  

Here it is the check above.

>      draw_depend_on_me(display, surface_id);
>  
> -    if (!red_handle_surfaces_dependencies(display, drawable)) {
> -        return;
> -    }
> +    if (!handle_surface_deps(display, drawable))
> +        return FALSE;
>  

style, prefer {} always.

>      Ring *ring = &display->surfaces[surface_id].current;
> -
> +    int add_to_pipe = FALSE;
>      if (has_shadow(red_drawable)) {
> -        success = current_add_with_shadow(display, ring, drawable);
> +        add_to_pipe = current_add_with_shadow(display, ring, drawable);
>      } else {
>          drawable->streamable = drawable_can_stream(display, drawable);
> -        success = current_add(display, ring, drawable);
> +        add_to_pipe = current_add(display, ring, drawable);
>      }
>  
> -    if (success)
> +    if (add_to_pipe)
>          pipes_add_drawable(display, drawable);
>  
>  #ifdef RED_WORKER_STAT
>      if ((++display->add_count % 100) == 0)
>          display_channel_print_stats(display);
>  #endif
> +
> +    return TRUE;
>  }
>  
>  int display_channel_wait_for_migrate_data(DisplayChannel *display)
> diff --git a/server/display-channel.h b/server/display-channel.h
> index 195004d..2ac8173 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -286,8 +286,9 @@ void                       display_channel_surface_unref
> (DisplayCha
>                                                                        uint32_t
>                                                                        surface_id);
>  bool                       display_channel_surface_has_canvas
>  (DisplayChannel *display,
>                                                                        uint32_t
>                                                                        surface_id);
> -void                       display_channel_add_drawable
> (DisplayChannel *display,
> -
> Drawable
> *drawable);
> +int                        display_channel_add_drawable
> (DisplayChannel *display,
> +
> Drawable
> *drawable,
> +
> RedDrawable
> *red_drawable);
>  void                       display_channel_current_flush
>  (DisplayChannel *display,
>                                                                        int
>                                                                        surface_id);
>  int                        display_channel_wait_for_migrate_data
>  (DisplayChannel *display);
> @@ -300,11 +301,6 @@ void
> display_channel_destroy_surfaces          (DisplayCha
>  void                       display_channel_destroy_surface
>  (DisplayChannel *display,
>                                                                        uint32_t
>                                                                        surface_id);
>  uint32_t                   display_channel_generate_uid
>  (DisplayChannel *display);
> -Drawable *                 display_channel_get_drawable
> (DisplayChannel *display,
> -
> uint8_t
> effect,
> -
> RedDrawable
> *red_drawable,
> -
> uint32_t
> group_id,
> -
> uint32_t
> process_commands_generation);
>  
>  static inline int validate_surface(DisplayChannel *display, uint32_t
>  surface_id)
>  {
> diff --git a/server/red_worker.c b/server/red_worker.c
> index ee26b63..f943898 100644
> --- a/server/red_worker.c
> +++ b/server/red_worker.c
> @@ -172,26 +172,28 @@ void red_drawable_unref(RedWorker *worker, RedDrawable
> *red_drawable,
>      free(red_drawable);
>  }
>  
> -static inline void red_process_draw(RedWorker *worker, RedDrawable
> *red_drawable,
> -                                    uint32_t group_id)
> +static void red_process_draw(RedWorker *worker, RedDrawable *red_drawable,
> +                             uint32_t group_id)
>  {
>      DisplayChannel *display = worker->display_channel;
> -    Drawable *drawable =
> -        display_channel_get_drawable(display, red_drawable->effect,
> red_drawable, group_id,
> -                                     worker->process_commands_generation);
> +    Drawable *drawable;
> +    bool success = FALSE;
>  
> +    drawable = display_channel_drawable_try_new(display, group_id,
> +
> worker->process_commands_generation);
>      if (!drawable) {
>          return;
>      }
>  
> -    display_channel_add_drawable(worker->display_channel, drawable);
> +    success = display_channel_add_drawable(worker->display_channel,
> drawable, red_drawable);
> +    spice_warn_if_fail(success);
>  
>      display_channel_drawable_unref(display, drawable);
>  }
>  
>  
> -static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd
> *surface,
> -                                       uint32_t group_id, int loadvm)
> +static void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface,
> +                                uint32_t group_id, int loadvm)
>  {
>      DisplayChannel *display = worker->display_channel;
>      uint32_t surface_id;

Frediano


More information about the Spice-devel mailing list