From a439c1b50ab984a06aa311a32f0410e00d67c0c4 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Fri, 13 Nov 2015 18:23:18 +0100 Subject: worker: painfully move display_channel_add_drawable --- server/red_worker.c | 558 ++-------------------------------------------------- 1 file changed, 13 insertions(+), 545 deletions(-) (limited to 'server/red_worker.c') diff --git a/server/red_worker.c b/server/red_worker.c index 7560b9d0..e1036d47 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -593,7 +593,7 @@ static int cursor_is_connected(RedWorker *worker) red_channel_is_connected(RED_CHANNEL(worker->cursor_channel)); } -static void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable) +void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable) { DrawablePipeItem *dpi; @@ -602,7 +602,7 @@ static void dcc_add_drawable(DisplayChannelClient *dcc, Drawable *drawable) red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item); } -static void red_pipes_add_drawable(RedWorker *worker, Drawable *drawable) +void red_pipes_add_drawable(RedWorker *worker, Drawable *drawable) { DisplayChannelClient *dcc; RingItem *dcc_ring_item, *next; @@ -625,8 +625,8 @@ static void dcc_add_drawable_to_tail(DisplayChannelClient *dcc, Drawable *drawab red_channel_client_pipe_add_tail(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item); } -static inline void red_pipes_add_drawable_after(RedWorker *worker, - Drawable *drawable, Drawable *pos_after) +void red_pipes_add_drawable_after(RedWorker *worker, + Drawable *drawable, Drawable *pos_after) { DrawablePipeItem *dpi, *dpi_pos_after; RingItem *dpi_link, *dpi_next; @@ -674,7 +674,7 @@ static inline PipeItem *red_pipe_get_tail(DisplayChannelClient *dcc) static void red_surface_unref(RedWorker *worker, uint32_t surface_id); -static inline void red_pipes_remove_drawable(Drawable *drawable) +void red_pipes_remove_drawable(Drawable *drawable) { DrawablePipeItem *dpi; RingItem *item, *next; @@ -972,10 +972,11 @@ static void red_flush_source_surfaces(RedWorker *worker, Drawable *drawable) } } -static inline void current_remove_drawable(RedWorker *worker, Drawable *item) +void current_remove_drawable(RedWorker *worker, Drawable *item) { DisplayChannel *display = worker->display_channel; + /* todo: move all to unref? */ display_stream_trace_add_drawable(display, item); draw_item_remove_shadow(&item->tree_item); ring_remove(&item->tree_item.base.siblings_link); @@ -985,13 +986,7 @@ static inline void current_remove_drawable(RedWorker *worker, Drawable *item) display->current_size--; } -static void remove_drawable(RedWorker *worker, Drawable *drawable) -{ - red_pipes_remove_drawable(drawable); - current_remove_drawable(worker, drawable); -} - -static inline void current_remove(RedWorker *worker, TreeItem *item) +void current_remove(RedWorker *worker, TreeItem *item) { TreeItem *now = item; @@ -1000,8 +995,10 @@ static inline void current_remove(RedWorker *worker, TreeItem *item) RingItem *ring_item; if (now->type == TREE_ITEM_TYPE_DRAWABLE) { + Drawable *drawable = SPICE_CONTAINEROF(now, Drawable, tree_item); ring_item = now->siblings_link.prev; - remove_drawable(worker, SPICE_CONTAINEROF(now, Drawable, tree_item)); + red_pipes_remove_drawable(drawable); + current_remove_drawable(display, drawable); } else { Container *container = (Container *)now; @@ -1131,150 +1128,6 @@ static void red_clear_surface_drawables_from_pipes(RedWorker *worker, } } -static inline void __exclude_region(RedWorker *worker, Ring *ring, TreeItem *item, QRegion *rgn, - Ring **top_ring, Drawable *frame_candidate) -{ - QRegion and_rgn; -#ifdef RED_WORKER_STAT - stat_time_t start_time = stat_now(worker->clockid); -#endif - - region_clone(&and_rgn, rgn); - region_and(&and_rgn, &item->rgn); - if (!region_is_empty(&and_rgn)) { - if (IS_DRAW_ITEM(item)) { - DrawItem *draw = (DrawItem *)item; - - if (draw->effect == QXL_EFFECT_OPAQUE) { - region_exclude(rgn, &and_rgn); - } - - if (draw->shadow) { - Shadow *shadow; - int32_t x = item->rgn.extents.x1; - int32_t y = item->rgn.extents.y1; - - region_exclude(&draw->base.rgn, &and_rgn); - shadow = draw->shadow; - region_offset(&and_rgn, shadow->base.rgn.extents.x1 - x, - shadow->base.rgn.extents.y1 - y); - region_exclude(&shadow->base.rgn, &and_rgn); - region_and(&and_rgn, &shadow->on_hold); - if (!region_is_empty(&and_rgn)) { - region_exclude(&shadow->on_hold, &and_rgn); - region_or(rgn, &and_rgn); - // in flat representation of current, shadow is always his owner next - if (!tree_item_contained_by((TreeItem*)shadow, *top_ring)) { - *top_ring = tree_item_container_items((TreeItem*)shadow, ring); - } - } - } else { - if (frame_candidate) { - Drawable *drawable = SPICE_CONTAINEROF(draw, Drawable, tree_item); - stream_maintenance(worker->display_channel, frame_candidate, drawable); - } - region_exclude(&draw->base.rgn, &and_rgn); - } - } else if (item->type == TREE_ITEM_TYPE_CONTAINER) { - region_exclude(&item->rgn, &and_rgn); - - if (region_is_empty(&item->rgn)) { //assume container removal will follow - Shadow *shadow; - - region_exclude(rgn, &and_rgn); - if ((shadow = tree_item_find_shadow(item))) { - region_or(rgn, &shadow->on_hold); - if (!tree_item_contained_by((TreeItem*)shadow, *top_ring)) { - *top_ring = tree_item_container_items((TreeItem*)shadow, ring); - } - } - } - } else { - Shadow *shadow; - - spice_assert(item->type == TREE_ITEM_TYPE_SHADOW); - shadow = (Shadow *)item; - region_exclude(rgn, &and_rgn); - region_or(&shadow->on_hold, &and_rgn); - } - } - region_destroy(&and_rgn); - stat_add(&worker->display_channel->__exclude_stat, start_time); -} - -static void exclude_region(RedWorker *worker, Ring *ring, RingItem *ring_item, QRegion *rgn, - TreeItem **last, Drawable *frame_candidate) -{ -#ifdef RED_WORKER_STAT - stat_time_t start_time = stat_now(worker->clockid); -#endif - Ring *top_ring; - - if (!ring_item) { - return; - } - - top_ring = ring; - - for (;;) { - TreeItem *now = SPICE_CONTAINEROF(ring_item, TreeItem, siblings_link); - Container *container = now->container; - - spice_assert(!region_is_empty(&now->rgn)); - - if (region_intersects(rgn, &now->rgn)) { - __exclude_region(worker, ring, now, rgn, &top_ring, frame_candidate); - - if (region_is_empty(&now->rgn)) { - spice_assert(now->type != TREE_ITEM_TYPE_SHADOW); - ring_item = now->siblings_link.prev; - current_remove(worker, now); - if (last && *last == now) { - *last = (TreeItem *)ring_next(ring, ring_item); - } - } else if (now->type == TREE_ITEM_TYPE_CONTAINER) { - Container *container = (Container *)now; - if ((ring_item = ring_get_head(&container->items))) { - ring = &container->items; - spice_assert(((TreeItem *)ring_item)->container); - continue; - } - ring_item = &now->siblings_link; - } - - if (region_is_empty(rgn)) { - stat_add(&worker->display_channel->exclude_stat, start_time); - return; - } - } - - while ((last && *last == (TreeItem *)ring_item) || - !(ring_item = ring_next(ring, ring_item))) { - if (ring == top_ring) { - stat_add(&worker->display_channel->exclude_stat, start_time); - return; - } - ring_item = &container->base.siblings_link; - container = container->base.container; - ring = (container) ? &container->items : top_ring; - } - } -} - -static inline void current_add_drawable(RedWorker *worker, Drawable *drawable, RingItem *pos) -{ - DisplayChannel *display = worker->display_channel; - RedSurface *surface; - uint32_t surface_id = drawable->surface_id; - - surface = &worker->surfaces[surface_id]; - ring_add_after(&drawable->tree_item.base.siblings_link, pos); - ring_add(&display->current_list, &drawable->list_link); - ring_add(&surface->current_list, &drawable->surface_list_link); - display->current_size++; - drawable->refs++; -} - void detach_stream(DisplayChannel *display, Stream *stream, int detach_sized) { @@ -1397,7 +1250,7 @@ static void detach_stream_gracefully(DisplayChannel *display, Stream *stream, * involves sending an upgrade image to the client, this drawable won't be rendered * (see dcc_detach_stream_gracefully). */ -static void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable) +void detach_streams_behind(DisplayChannel *display, QRegion *region, Drawable *drawable) { Ring *ring = &display->streams; RingItem *item = ring_get_head(ring); @@ -1430,46 +1283,6 @@ static void detach_streams_behind(DisplayChannel *display, QRegion *region, Draw } } -static void streams_update_visible_region(DisplayChannel *display, Drawable *drawable) -{ - Ring *ring; - RingItem *item; - RingItem *dcc_ring_item, *next; - DisplayChannelClient *dcc; - - if (!red_channel_is_connected(RED_CHANNEL(display))) { - return; - } - - if (!is_primary_surface(display, drawable->surface_id)) { - return; - } - - ring = &display->streams; - item = ring_get_head(ring); - - while (item) { - Stream *stream = SPICE_CONTAINEROF(item, Stream, link); - StreamAgent *agent; - - item = ring_next(ring, item); - - if (stream->current == drawable) { - continue; - } - - FOREACH_DCC(display, dcc_ring_item, next, dcc) { - agent = &dcc->stream_agents[get_stream_id(display, stream)]; - - if (region_intersects(&agent->vis_region, &drawable->tree_item.base.rgn)) { - region_exclude(&agent->vis_region, &drawable->tree_item.base.rgn); - region_exclude(&agent->clip, &drawable->tree_item.base.rgn); - dcc_add_stream_agent_clip(dcc, agent); - } - } - } -} - static void display_channel_streams_timeout(DisplayChannel *display) { Ring *ring = &display->streams; @@ -1706,351 +1519,6 @@ static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) } } -static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeItem *other) -{ - DisplayChannel *display = worker->display_channel; - DrawItem *other_draw_item; - Drawable *drawable; - Drawable *other_drawable; - - if (other->type != TREE_ITEM_TYPE_DRAWABLE) { - return FALSE; - } - other_draw_item = (DrawItem *)other; - - if (item->shadow || other_draw_item->shadow || item->effect != other_draw_item->effect) { - return FALSE; - } - - drawable = SPICE_CONTAINEROF(item, Drawable, tree_item); - other_drawable = SPICE_CONTAINEROF(other_draw_item, Drawable, tree_item); - - if (item->effect == QXL_EFFECT_OPAQUE) { - int add_after = !!other_drawable->stream && - is_drawable_independent_from_surfaces(drawable); - stream_maintenance(worker->display_channel, drawable, other_drawable); - current_add_drawable(worker, drawable, &other->siblings_link); - other_drawable->refs++; - current_remove_drawable(worker, other_drawable); - if (add_after) { - red_pipes_add_drawable_after(worker, drawable, other_drawable); - } else { - red_pipes_add_drawable(worker, drawable); - } - red_pipes_remove_drawable(other_drawable); - display_channel_drawable_unref(display, other_drawable); - return TRUE; - } - - switch (item->effect) { - case QXL_EFFECT_REVERT_ON_DUP: - if (is_same_drawable(drawable, other_drawable)) { - - DisplayChannelClient *dcc; - DrawablePipeItem *dpi; - RingItem *worker_ring_item, *dpi_ring_item; - - other_drawable->refs++; - current_remove_drawable(worker, other_drawable); - - /* sending the drawable to clients that already received - * (or will receive) other_drawable */ - worker_ring_item = ring_get_head(&RED_CHANNEL(worker->display_channel)->clients); - dpi_ring_item = ring_get_head(&other_drawable->pipes); - /* dpi contains a sublist of dcc's, ordered the same */ - while (worker_ring_item) { - dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient, - common.base.channel_link); - dpi = SPICE_CONTAINEROF(dpi_ring_item, DrawablePipeItem, base); - while (worker_ring_item && (!dpi || dcc != dpi->dcc)) { - dcc_add_drawable(dcc, drawable); - worker_ring_item = ring_next(&RED_CHANNEL(worker->display_channel)->clients, - worker_ring_item); - dcc = SPICE_CONTAINEROF(worker_ring_item, DisplayChannelClient, - common.base.channel_link); - } - - if (dpi_ring_item) { - dpi_ring_item = ring_next(&other_drawable->pipes, dpi_ring_item); - } - if (worker_ring_item) { - worker_ring_item = ring_next(&RED_CHANNEL(worker->display_channel)->clients, - worker_ring_item); - } - } - /* not sending other_drawable where possible */ - red_pipes_remove_drawable(other_drawable); - - display_channel_drawable_unref(display, other_drawable); - return TRUE; - } - break; - case QXL_EFFECT_OPAQUE_BRUSH: - if (is_same_geometry(drawable, other_drawable)) { - current_add_drawable(worker, drawable, &other->siblings_link); - remove_drawable(worker, other_drawable); - red_pipes_add_drawable(worker, drawable); - return TRUE; - } - break; - case QXL_EFFECT_NOP_ON_DUP: - if (is_same_drawable(drawable, other_drawable)) { - return TRUE; - } - break; - } - return FALSE; -} - -static inline int current_add(RedWorker *worker, Ring *ring, Drawable *drawable) -{ - DrawItem *item = &drawable->tree_item; -#ifdef RED_WORKER_STAT - stat_time_t start_time = stat_now(worker->clockid); -#endif - RingItem *now; - QRegion exclude_rgn; - RingItem *exclude_base = NULL; - - spice_assert(!region_is_empty(&item->base.rgn)); - region_init(&exclude_rgn); - now = ring_next(ring, ring); - - while (now) { - TreeItem *sibling = SPICE_CONTAINEROF(now, TreeItem, siblings_link); - int test_res; - - if (!region_bounds_intersects(&item->base.rgn, &sibling->rgn)) { - now = ring_next(ring, now); - continue; - } - test_res = region_test(&item->base.rgn, &sibling->rgn, REGION_TEST_ALL); - if (!(test_res & REGION_TEST_SHARED)) { - now = ring_next(ring, now); - continue; - } else if (sibling->type != TREE_ITEM_TYPE_SHADOW) { - if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) && - !(test_res & REGION_TEST_LEFT_EXCLUSIVE) && - red_current_add_equal(worker, item, sibling)) { - stat_add(&worker->display_channel->add_stat, start_time); - return FALSE; - } - - if (!(test_res & REGION_TEST_RIGHT_EXCLUSIVE) && item->effect == QXL_EFFECT_OPAQUE) { - Shadow *shadow; - int skip = now == exclude_base; - - if ((shadow = tree_item_find_shadow(sibling))) { - if (exclude_base) { - TreeItem *next = sibling; - exclude_region(worker, ring, exclude_base, &exclude_rgn, &next, NULL); - if (next != sibling) { - now = next ? &next->siblings_link : NULL; - exclude_base = NULL; - continue; - } - } - region_or(&exclude_rgn, &shadow->on_hold); - } - now = now->prev; - current_remove(worker, sibling); - now = ring_next(ring, now); - if (shadow || skip) { - exclude_base = now; - } - continue; - } - - if (!(test_res & REGION_TEST_LEFT_EXCLUSIVE) && is_opaque_item(sibling)) { - Container *container; - - if (exclude_base) { - exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, NULL); - region_clear(&exclude_rgn); - exclude_base = NULL; - } - if (sibling->type == TREE_ITEM_TYPE_CONTAINER) { - container = (Container *)sibling; - ring = &container->items; - item->base.container = container; - now = ring_next(ring, ring); - continue; - } - spice_assert(IS_DRAW_ITEM(sibling)); - if (!DRAW_ITEM(sibling)->container_root) { - container = container_new(DRAW_ITEM(sibling)); - if (!container) { - spice_warning("create new container failed"); - region_destroy(&exclude_rgn); - return FALSE; - } - item->base.container = container; - ring = &container->items; - } - } - } - if (!exclude_base) { - exclude_base = now; - } - break; - } - if (item->effect == QXL_EFFECT_OPAQUE) { - region_or(&exclude_rgn, &item->base.rgn); - exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, drawable); - stream_trace_update(worker->display_channel, drawable); - streams_update_visible_region(worker->display_channel, drawable); - /* - * Performing the insertion after exclude_region for - * safety (todo: Not sure if exclude_region can affect the drawable - * if it is added to the tree before calling exclude_region). - */ - current_add_drawable(worker, drawable, ring); - } else { - /* - * red_detach_streams_behind can affect the current tree since it may - * trigger calls to update_area. Thus, the drawable should be added to the tree - * before calling red_detach_streams_behind - */ - current_add_drawable(worker, drawable, ring); - if (is_primary_surface(worker->display_channel, drawable->surface_id)) { - detach_streams_behind(worker->display_channel, &drawable->tree_item.base.rgn, drawable); - } - } - region_destroy(&exclude_rgn); - stat_add(&worker->display_channel->add_stat, start_time); - return TRUE; -} - -static inline int current_add_with_shadow(RedWorker *worker, Ring *ring, Drawable *item) -{ - DisplayChannel *display = worker->display_channel; -#ifdef RED_WORKER_STAT - stat_time_t start_time = stat_now(worker->clockid); - ++display->add_with_shadow_count; -#endif - - RedDrawable *red_drawable = item->red_drawable; - SpicePoint delta = { - .x = red_drawable->u.copy_bits.src_pos.x - red_drawable->bbox.left, - .y = red_drawable->u.copy_bits.src_pos.y - red_drawable->bbox.top - }; - - Shadow *shadow = shadow_new(&item->tree_item, &delta); - if (!shadow) { - stat_add(&display->add_stat, start_time); - return FALSE; - } - // item and his shadow must initially be placed in the same container. - // for now putting them on root. - - // only primary surface streams are supported - if (is_primary_surface(display, item->surface_id)) { - detach_streams_behind(display, &shadow->base.rgn, NULL); - } - - ring_add(ring, &shadow->base.siblings_link); - current_add_drawable(worker, item, ring); - if (item->tree_item.effect == QXL_EFFECT_OPAQUE) { - QRegion exclude_rgn; - region_clone(&exclude_rgn, &item->tree_item.base.rgn); - exclude_region(worker, ring, &shadow->base.siblings_link, &exclude_rgn, NULL, NULL); - region_destroy(&exclude_rgn); - streams_update_visible_region(display, item); - } else { - if (is_primary_surface(display, item->surface_id)) { - detach_streams_behind(display, &item->tree_item.base.rgn, item); - } - } - stat_add(&display->add_stat, start_time); - return TRUE; -} - -static void drawable_update_streamable(DisplayChannel *display, Drawable *drawable) -{ - RedDrawable *red_drawable = drawable->red_drawable; - SpiceImage *image; - - if (display->stream_video == SPICE_STREAM_VIDEO_OFF) { - return; - } - - if (!is_primary_surface(display, drawable->surface_id)) { - return; - } - - if (drawable->tree_item.effect != QXL_EFFECT_OPAQUE || - red_drawable->type != QXL_DRAW_COPY || - red_drawable->u.copy.rop_descriptor != SPICE_ROPD_OP_PUT) { - return; - } - - image = red_drawable->u.copy.src_bitmap; - if (image == NULL || - image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) { - return; - } - - if (display->stream_video == SPICE_STREAM_VIDEO_FILTER) { - SpiceRect* rect; - int size; - - rect = &drawable->red_drawable->u.copy.src_area; - size = (rect->right - rect->left) * (rect->bottom - rect->top); - if (size < RED_STREAM_MIN_SIZE) { - return; - } - } - - drawable->streamable = TRUE; -} - -void print_stats(DisplayChannel *display) -{ -#ifdef RED_WORKER_STAT - stat_time_t total = display->add_stat.total; - spice_info("add with shadow count %u", - display->add_with_shadow_count); - display->add_with_shadow_count = 0; - spice_info("add[%u] %f exclude[%u] %f __exclude[%u] %f", - display->add_stat.count, - stat_cpu_time_to_sec(total), - display->exclude_stat.count, - stat_cpu_time_to_sec(display->exclude_stat.total), - display->__exclude_stat.count, - stat_cpu_time_to_sec(display->__exclude_stat.total)); - spice_info("add %f%% exclude %f%% exclude2 %f%% __exclude %f%%", - (double)(total - display->exclude_stat.total) / total * 100, - (double)(display->exclude_stat.total) / total * 100, - (double)(display->exclude_stat.total - - display->__exclude_stat.total) / display->exclude_stat.total * 100, - (double)(display->__exclude_stat.total) / display->exclude_stat.total * 100); - stat_reset(&display->add_stat); - stat_reset(&display->exclude_stat); - stat_reset(&display->__exclude_stat); -#endif -} - -static int red_add_drawable(RedWorker *worker, Drawable *drawable) -{ - DisplayChannel *display = worker->display_channel; - int ret = FALSE, surface_id = drawable->surface_id; - RedDrawable *red_drawable = drawable->red_drawable; - Ring *ring = &worker->surfaces[surface_id].current; - - if (has_shadow(red_drawable)) { - ret = current_add_with_shadow(worker, ring, drawable); - } else { - drawable_update_streamable(display, drawable); - ret = current_add(worker, ring, drawable); - } - -#ifdef RED_WORKER_STAT - if ((++display->add_count % 100) == 0) - print_stats(display); -#endif - return ret; -} - static void red_get_area(RedWorker *worker, int surface_id, const SpiceRect *area, uint8_t *dest, int dest_stride, int update) { @@ -2350,7 +1818,7 @@ static inline void red_process_draw(RedWorker *worker, RedDrawable *red_drawable goto cleanup; } - if (red_add_drawable(worker, drawable)) { + if (display_channel_add_drawable(worker->display_channel, drawable)) { red_pipes_add_drawable(worker, drawable); } cleanup: -- cgit