summaryrefslogtreecommitdiffstats
path: root/server/red_worker.c
diff options
context:
space:
mode:
authorYonit Halperin <yhalperi@redhat.com>2012-04-29 12:40:25 +0300
committerYonit Halperin <yhalperi@redhat.com>2012-05-03 12:30:59 +0300
commit81fe00b08ad4f8abe848f9840c4879e8c1e645c1 (patch)
tree271f938591f58b8f3af70ecebce38c22a96b70eb /server/red_worker.c
parent80f0865b44f903c8b009471377dfbe86a79ece06 (diff)
downloadspice-81fe00b08ad4f8abe848f9840c4879e8c1e645c1.tar.gz
spice-81fe00b08ad4f8abe848f9840c4879e8c1e645c1.tar.xz
spice-81fe00b08ad4f8abe848f9840c4879e8c1e645c1.zip
server/red_worker/video: upgrade stream by a screenshot instead of the last frame, if needed
Upgrading a stream: When the stream's visible region is bigger than the one of the last frame, we will send an updated screenshot of the visible region, instead of sending the last frame losslessly.
Diffstat (limited to 'server/red_worker.c')
-rw-r--r--server/red_worker.c92
1 files changed, 71 insertions, 21 deletions
diff --git a/server/red_worker.c b/server/red_worker.c
index d95a9bb6..dc66fc1a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1006,6 +1006,8 @@ static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type
static void red_display_release_stream_clip(RedWorker *worker, StreamClipItem *item);
static int red_display_free_some_independent_glz_drawables(DisplayChannelClient *dcc);
static void red_display_free_glz_drawable(DisplayChannelClient *dcc, RedGlzDrawable *drawable);
+static ImageItem *red_add_surface_area_image(DisplayChannelClient *dcc, int surface_id,
+ SpiceRect *area, PipeItem *pos, int can_lossy);
static void reset_rate(DisplayChannelClient *dcc, StreamAgent *stream_agent);
static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap,
uint32_t group_id);
@@ -2541,25 +2543,54 @@ static void red_stop_stream(RedWorker *worker, Stream *stream)
red_release_stream(worker, stream);
}
-static int drawable_is_linked(Drawable *drawable)
+static int red_display_drawable_is_in_pipe(DisplayChannelClient *dcc, Drawable *drawable)
{
- return !ring_is_empty(&drawable->pipes);
+ DrawablePipeItem *dpi;
+ RingItem *dpi_link;
+
+ DRAWABLE_FOREACH_DPI(drawable, dpi_link, dpi) {
+ if (dpi->dcc == dcc) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
-static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
+/*
+ * after red_display_detach_stream_gracefully is called for all the display channel clients,
+ * red_detach_stream should be called. See comment (1).
+ */
+static inline void red_display_detach_stream_gracefully(DisplayChannelClient *dcc, Stream *stream)
{
- RedChannel *channel;
- RingItem *item;
- RedChannelClient *rcc;
- DisplayChannelClient *dcc;
+ int stream_id = get_stream_id(dcc->common.worker, stream);
+ StreamAgent *agent = &dcc->stream_agents[stream_id];
- spice_assert(stream->current);
- WORKER_FOREACH_DCC(worker, item, dcc) {
+ /* stopping the client from playing older frames at once*/
+ region_clear(&agent->clip);
+ push_stream_clip(dcc, agent);
+
+ if (region_is_empty(&agent->vis_region)) {
+ spice_debug("stream %d: vis region empty", stream_id);
+ return;
+ }
+
+ if (stream->current &&
+ region_contains(&stream->current->tree_item.base.rgn, &agent->vis_region)) {
+ RedChannel *channel;
+ RedChannelClient *rcc;
UpgradeItem *upgrade_item;
int n_rects;
- if (drawable_is_linked(stream->current)) {
- continue;
+
+ /* (1) The caller should detach the drawable from the stream. This will
+ * lead to sending the drawable losslessly, as an ordinary drawable. */
+ if (red_display_drawable_is_in_pipe(dcc, stream->current)) {
+ spice_debug("stream %d: upgrade by linked drawable. box ==>", stream_id);
+ rect_debug(&stream->current->red_drawable->bbox);
+ return;
}
+ spice_debug("stream %d: upgrade by drawable. box ==>", stream_id);
+ rect_debug(&stream->current->red_drawable->bbox);
rcc = &dcc->common.base;
channel = rcc->channel;
upgrade_item = spice_new(UpgradeItem, 1);
@@ -2574,8 +2605,31 @@ static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *strea
region_ret_rects(&upgrade_item->drawable->tree_item.base.rgn,
upgrade_item->rects->rects, n_rects);
red_channel_client_pipe_add(rcc, &upgrade_item->base);
+
+ } else {
+ SpiceRect upgrade_area;
+
+ region_extents(&agent->vis_region, &upgrade_area);
+ spice_debug("stream %d: upgrade by screenshot. has current %d. box ==>",
+ stream_id, stream->current != NULL);
+ rect_debug(&upgrade_area);
+ red_update_area(dcc->common.worker, &upgrade_area, 0);
+ red_add_surface_area_image(dcc, 0, &upgrade_area, NULL, FALSE);
+ }
+
+}
+
+static inline void red_detach_stream_gracefully(RedWorker *worker, Stream *stream)
+{
+ RingItem *item;
+ DisplayChannelClient *dcc;
+
+ WORKER_FOREACH_DCC(worker, item, dcc) {
+ red_display_detach_stream_gracefully(dcc, stream);
+ }
+ if (stream->current) {
+ red_detach_stream(worker, stream);
}
- red_detach_stream(worker, stream);
}
// region should be a primary surface region
@@ -2594,24 +2648,20 @@ 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)) {
- /* hiding the stream at the client side at once */
- region_clear(&agent->clip);
- push_stream_clip(dcc, agent);
+ red_display_detach_stream_gracefully(dcc, stream);
detach_stream = 1;
}
}
- if (!has_clients) {
+ if (detach_stream && stream->current) {
+ red_detach_stream(worker, stream);
+ } else if (!has_clients) {
if (stream->current &&
region_intersects(&stream->current->tree_item.base.rgn, region)) {
red_detach_stream(worker, stream);
}
}
- if (detach_stream) {
- if (stream->current) {
- red_detach_stream_gracefully(worker, stream);
- }
- }
}
}