summaryrefslogtreecommitdiff
path: root/server/display-channel.c
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2015-11-27 12:49:40 +0000
committerFrediano Ziglio <fziglio@redhat.com>2015-12-03 10:41:46 +0000
commitc1ecbaf7b1faa7fee4328e76607f3ea638381756 (patch)
tree86db3efb8fdb08705f64baddf2c52a514bf08c4f /server/display-channel.c
parentc26e6de0ee5492a3c944d98422885bd468768a56 (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.c185
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)) {