diff options
author | Frediano Ziglio <fziglio@redhat.com> | 2015-11-27 12:49:40 +0000 |
---|---|---|
committer | Frediano Ziglio <fziglio@redhat.com> | 2015-12-03 10:41:46 +0000 |
commit | c1ecbaf7b1faa7fee4328e76607f3ea638381756 (patch) | |
tree | 86db3efb8fdb08705f64baddf2c52a514bf08c4f /server/display-channel.c | |
parent | c26e6de0ee5492a3c944d98422885bd468768a56 (diff) |
display: move more logic in display_channel_get_drawable()
Signed-off-by: Marc-André Lureau <marcandre.lureau@gmail.com>
Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Fabiano FidĂȘncio <fidencio@redhat.com>
Diffstat (limited to 'server/display-channel.c')
-rw-r--r-- | server/display-channel.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/server/display-channel.c b/server/display-channel.c index 27f0d342..ba391745 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -916,6 +916,152 @@ void display_channel_print_stats(DisplayChannel *display) #endif } +static inline void red_inc_surfaces_drawable_dependencies(DisplayChannel *display, Drawable *drawable) +{ + int x; + int surface_id; + RedSurface *surface; + + for (x = 0; x < 3; ++x) { + surface_id = drawable->surface_deps[x]; + if (surface_id == -1) { + continue; + } + surface = &display->surfaces[surface_id]; + surface->refs++; + } +} + +static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area, + uint8_t *dest, int dest_stride, int update) +{ + SpiceCanvas *canvas; + RedSurface *surface; + + surface = &display->surfaces[surface_id]; + if (update) { + display_channel_draw(display, area, 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) +{ + SpiceImage *image; + int32_t width; + int32_t height; + uint8_t *dest; + int dest_stride; + RedSurface *surface; + int bpp; + int all_set; + RedDrawable *red_drawable = drawable->red_drawable; + + if (!red_drawable->self_bitmap) { + return TRUE; + } + + 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; + 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); + image->u.bitmap.stride = dest_stride; + image->descriptor.width = image->u.bitmap.x = width; + image->descriptor.height = image->u.bitmap.y = height; + image->u.bitmap.palette = NULL; + + dest = (uint8_t *)spice_malloc_n(height, dest_stride); + 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); + + /* 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 */ + if (!is_primary_surface(display, drawable->surface_id) && + image->u.bitmap.format == SPICE_BITMAP_FMT_32BIT && + rgb32_data_has_alpha(width, height, dest_stride, dest, &all_set)) { + if (all_set) { + image->descriptor.flags |= SPICE_IMAGE_FLAGS_HIGH_BITS_SET; + } else { + image->u.bitmap.format = SPICE_BITMAP_FMT_RGBA; + } + } + + 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) +{ + RedSurface *surface; + + if (depend_on_surface_id == -1) { + depend_item->drawable = NULL; + return; + } + + surface = &display->surfaces[depend_on_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) +{ + int x; + + for (x = 0; x < 3; ++x) { + // 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); + + if (drawable->surface_deps[x] == 0) { + QRegion depend_region; + region_init(&depend_region); + region_add(&depend_region, &drawable->red_drawable->surfaces_rects[x]); + stream_detach_behind(display, &depend_region, NULL); + } + } + } + + return TRUE; +} + +static void draw_depend_on_me(DisplayChannel *display, uint32_t surface_id) +{ + RedSurface *surface; + RingItem *ring_item; + + surface = &display->surfaces[surface_id]; + + while ((ring_item = ring_get_tail(&surface->depend_on_me))) { + Drawable *drawable; + DependItem *depended_item = SPICE_CONTAINEROF(ring_item, DependItem, ring_item); + drawable = depended_item->drawable; + display_channel_draw(display, &drawable->red_drawable->bbox, drawable->surface_id); + } +} + static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable) { DrawContext *context; @@ -980,6 +1126,45 @@ void display_channel_add_drawable(DisplayChannel *display, Drawable *drawable) { int success = FALSE, surface_id = drawable->surface_id; RedDrawable *red_drawable = drawable->red_drawable; + + red_drawable->mm_time = reds_get_mm_time(); + surface_id = drawable->surface_id; + + display->surfaces[surface_id].refs++; + + region_add(&drawable->tree_item.base.rgn, &red_drawable->bbox); + + if (red_drawable->clip.type == SPICE_CLIP_TYPE_RECTS) { + QRegion rgn; + + region_init(&rgn); + region_add_clip_rects(&rgn, red_drawable->clip.rects); + region_and(&drawable->tree_item.base.rgn, &rgn); + region_destroy(&rgn); + } + + /* + 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); + + if (region_is_empty(&drawable->tree_item.base.rgn)) { + return; + } + + if (!display_channel_handle_self_bitmap(display, drawable)) { + return; + } + + draw_depend_on_me(display, surface_id); + + if (!red_handle_surfaces_dependencies(display, drawable)) { + return; + } + Ring *ring = &display->surfaces[surface_id].current; if (has_shadow(red_drawable)) { |