summaryrefslogtreecommitdiffstats
path: root/server/red_worker.c
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 /server/red_worker.c
parent3ccc9de184f9cb499a4f887779c9fb9bffba3210 (diff)
downloadspice-80f0865b44f903c8b009471377dfbe86a79ece06.tar.gz
spice-80f0865b44f903c8b009471377dfbe86a79ece06.tar.xz
spice-80f0865b44f903c8b009471377dfbe86a79ece06.zip
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.
Diffstat (limited to 'server/red_worker.c')
-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);