diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2012-04-29 11:55:01 +0300 |
---|---|---|
committer | Yonit Halperin <yhalperi@redhat.com> | 2012-05-03 12:30:55 +0300 |
commit | 80f0865b44f903c8b009471377dfbe86a79ece06 (patch) | |
tree | 6020f565fdfe69fa316140109f60baf7c816ad40 | |
parent | 3ccc9de184f9cb499a4f887779c9fb9bffba3210 (diff) |
server/red_worker/video: maintain visible region and clip region for streams
Differentiate between the clipping of the video stream, and the region
that currently displays fragments of the video stream (henceforth,
vis_region). The latter equals or contains the former one. For example,
let c1 be the clip area at time t1, and c2 be the clip area at time t2,
where t1 < t2. If c1 contains c2, and at least part of c1/c2, hasn't been
covered by a non-video images, vis_region will contain c2, and also the part
of c1/c2 that still displays fragments of the video.
When we consider if a stream should be "upgraded" (1), due to its area
being used by a rendering operation, or due to stopping the video, we
should take into account the vis_region, and not the clip region (next
patch: not upgrade by the last frame, but rather by vis_region).
This fix will be more necessary when sized frames are introduced (see the
following patches). Then, the vis_region might be larger
than the last frame, and contain it, more frequently than before.
(1) "upgrading a stream" stands for sending its last frame losslessly. Or more
precisely, lossless resending of all the currently displayed lossy areas, that were
sent as part of the stream.
-rw-r--r-- | server/red_worker.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/server/red_worker.c b/server/red_worker.c index 9456a55f..d95a9bb6 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -390,7 +390,15 @@ struct Stream { }; typedef struct StreamAgent { - QRegion vis_region; + QRegion vis_region; /* the part of the surface area that is currently occupied by video + fragments */ + QRegion clip; /* the current video clipping. It can be different from vis_region: + for example, let c1 be the clip area at time t1, and c2 + be the clip area at time t2, where t1 < t2. If c1 contains c2, and + at least part of c1/c2, hasn't been covered by a non-video images, + vis_region will contain c2 and also the part of c1/c2 that still + displays fragments of the video */ + PipeItem create_item; PipeItem destroy_item; Stream *stream; @@ -2468,11 +2476,11 @@ static void push_stream_clip(DisplayChannelClient* dcc, StreamAgent *agent) } item->clip_type = SPICE_CLIP_TYPE_RECTS; - n_rects = pixman_region32_n_rects(&agent->vis_region); + n_rects = pixman_region32_n_rects(&agent->clip); item->rects = spice_malloc_n_m(n_rects, sizeof(SpiceRect), sizeof(SpiceClipRects)); item->rects->num_rects = n_rects; - region_ret_rects(&agent->vis_region, item->rects->rects, n_rects); + region_ret_rects(&agent->clip, item->rects->rects, n_rects); red_channel_client_pipe_add(&dcc->common.base, (PipeItem *)item); } @@ -2493,7 +2501,6 @@ static inline int get_stream_id(RedWorker *worker, Stream *stream) static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *stream) { DisplayChannelClient *dcc; - StreamAgent *agent; RingItem *item; spice_assert(!drawable->stream && !stream->current); @@ -2503,10 +2510,12 @@ static void red_attach_stream(RedWorker *worker, Drawable *drawable, Stream *str stream->last_time = drawable->creation_time; WORKER_FOREACH_DCC(worker, item, dcc) { - agent = &dcc->stream_agents[get_stream_id(worker, stream)]; - if (!region_is_equal(&agent->vis_region, &drawable->tree_item.base.rgn)) { - region_destroy(&agent->vis_region); - region_clone(&agent->vis_region, &drawable->tree_item.base.rgn); + StreamAgent *agent = &dcc->stream_agents[get_stream_id(worker, stream)]; + + region_or(&agent->vis_region, &drawable->tree_item.base.rgn); + if (!region_is_equal(&agent->clip, &drawable->tree_item.base.rgn)) { + region_destroy(&agent->clip); + region_clone(&agent->clip, &drawable->tree_item.base.rgn); push_stream_clip_by_drawable(dcc, agent, drawable); } } @@ -2523,6 +2532,7 @@ static void red_stop_stream(RedWorker *worker, Stream *stream) StreamAgent *stream_agent; stream_agent = &dcc->stream_agents[get_stream_id(worker, stream)]; region_clear(&stream_agent->vis_region); + region_clear(&stream_agent->clip); spice_assert(!pipe_item_is_linked(&stream_agent->destroy_item)); stream->refs++; red_channel_client_pipe_add(&dcc->common.base, &stream_agent->destroy_item); @@ -2585,7 +2595,8 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region) WORKER_FOREACH_DCC(worker, dcc_ring_item, dcc) { StreamAgent *agent = &dcc->stream_agents[get_stream_id(worker, stream)]; if (region_intersects(&agent->vis_region, region)) { - region_clear(&agent->vis_region); + /* hiding the stream at the client side at once */ + region_clear(&agent->clip); push_stream_clip(dcc, agent); detach_stream = 1; } @@ -2604,7 +2615,7 @@ static void red_detach_streams_behind(RedWorker *worker, QRegion *region) } } -static void red_streams_update_clip(RedWorker *worker, Drawable *drawable) +static void red_streams_update_visible_region(RedWorker *worker, Drawable *drawable) { Ring *ring; RingItem *item; @@ -2637,6 +2648,7 @@ static void red_streams_update_clip(RedWorker *worker, Drawable *drawable) 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); push_stream_clip(dcc, agent); } } @@ -2747,6 +2759,7 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream) if (stream->current) { agent->frames = 1; region_clone(&agent->vis_region, &stream->current->tree_item.base.rgn); + region_clone(&agent->clip, &agent->vis_region); } else { agent->frames = 0; } @@ -2821,6 +2834,7 @@ static void red_display_client_init_streams(DisplayChannelClient *dcc) StreamAgent *agent = &dcc->stream_agents[i]; agent->stream = &worker->streams_buf[i]; region_init(&agent->vis_region); + region_init(&agent->clip); red_channel_pipe_item_init(channel, &agent->create_item, PIPE_ITEM_TYPE_STREAM_CREATE); red_channel_pipe_item_init(channel, &agent->destroy_item, PIPE_ITEM_TYPE_STREAM_DESTROY); } @@ -2833,6 +2847,7 @@ static void red_display_destroy_streams(DisplayChannelClient *dcc) for (i = 0; i < NUM_STREAMS; i++) { StreamAgent *agent = &dcc->stream_agents[i]; region_destroy(&agent->vis_region); + region_destroy(&agent->clip); } } @@ -3327,7 +3342,7 @@ static inline int red_current_add(RedWorker *worker, Ring *ring, Drawable *drawa region_or(&exclude_rgn, &item->base.rgn); exclude_region(worker, ring, exclude_base, &exclude_rgn, NULL, drawable); red_use_stream_trace(worker, drawable); - red_streams_update_clip(worker, drawable); + red_streams_update_visible_region(worker, drawable); } else { if (drawable->surface_id == 0) { red_detach_streams_behind(worker, &drawable->tree_item.base.rgn); @@ -3397,7 +3412,7 @@ static inline int red_current_add_with_shadow(RedWorker *worker, Ring *ring, Dra 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); - red_streams_update_clip(worker, item); + red_streams_update_visible_region(worker, item); } else { if (item->surface_id == 0) { red_detach_streams_behind(worker, &item->tree_item.base.rgn); |