summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2012-04-29 11:55:01 +0300
committerYonit Halperin <yhalperi@redhat.com>2012-05-03 12:30:55 +0300
commit80f0865b44f903c8b009471377dfbe86a79ece06 (patch)
tree6020f565fdfe69fa316140109f60baf7c816ad40
parent3ccc9de184f9cb499a4f887779c9fb9bffba3210 (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.c39
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);