summaryrefslogtreecommitdiffstats
path: root/server/dcc.c
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@gmail.com>2013-09-17 16:29:44 +0200
committerFrediano Ziglio <fziglio@redhat.com>2015-11-19 12:43:33 +0000
commit0e224d04fbd9a05a3289b19c32e9a8fd4afca086 (patch)
tree381b330b43233781b1fca8204ae42fa2356b8bbe /server/dcc.c
parent85920bb2e9715bc9317c2717cb14cc58f31f28ef (diff)
downloadspice-0e224d04fbd9a05a3289b19c32e9a8fd4afca086.tar.gz
spice-0e224d04fbd9a05a3289b19c32e9a8fd4afca086.tar.xz
spice-0e224d04fbd9a05a3289b19c32e9a8fd4afca086.zip
worker: move dcc_start()
Author: Marc-André Lureau <marcandre.lureau@gmail.com> Acked-by: Fabiano Fidêncio <fidencio@redhat.com>
Diffstat (limited to 'server/dcc.c')
-rw-r--r--server/dcc.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/server/dcc.c b/server/dcc.c
index 4a957358..a14247c7 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -22,6 +22,97 @@
#include "dcc.h"
#include "display-channel.h"
+static SurfaceCreateItem *surface_create_item_new(RedChannel* channel,
+ uint32_t surface_id, uint32_t width,
+ uint32_t height, uint32_t format, uint32_t flags)
+{
+ SurfaceCreateItem *create;
+
+ create = spice_malloc(sizeof(SurfaceCreateItem));
+
+ create->surface_create.surface_id = surface_id;
+ create->surface_create.width = width;
+ create->surface_create.height = height;
+ create->surface_create.flags = flags;
+ create->surface_create.format = format;
+
+ red_channel_pipe_item_init(channel,
+ &create->pipe_item, PIPE_ITEM_TYPE_CREATE_SURFACE);
+ return create;
+}
+
+void dcc_create_surface(DisplayChannelClient *dcc, int surface_id)
+{
+ DisplayChannel *display;
+ RedSurface *surface;
+ SurfaceCreateItem *create;
+ uint32_t flags;
+
+ if (!dcc) {
+ return;
+ }
+
+ display = DCC_TO_DC(dcc);
+ flags = is_primary_surface(DCC_TO_DC(dcc), surface_id) ? SPICE_SURFACE_FLAGS_PRIMARY : 0;
+
+ /* don't send redundant create surface commands to client */
+ if (!dcc || display->common.during_target_migrate ||
+ dcc->surface_client_created[surface_id]) {
+ return;
+ }
+ surface = &display->surfaces[surface_id];
+ create = surface_create_item_new(RED_CHANNEL_CLIENT(dcc)->channel,
+ surface_id, surface->context.width, surface->context.height,
+ surface->context.format, flags);
+ dcc->surface_client_created[surface_id] = TRUE;
+ red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &create->pipe_item);
+}
+
+void dcc_push_surface_image(DisplayChannelClient *dcc, int surface_id)
+{
+ DisplayChannel *display;
+ SpiceRect area;
+ RedSurface *surface;
+
+ if (!dcc) {
+ return;
+ }
+
+ display = DCC_TO_DC(dcc);
+ surface = &display->surfaces[surface_id];
+ if (!surface->context.canvas) {
+ return;
+ }
+ area.top = area.left = 0;
+ area.right = surface->context.width;
+ area.bottom = surface->context.height;
+
+ /* not allowing lossy compression because probably, especially if it is a primary surface,
+ it combines both "picture-like" areas with areas that are more "artificial"*/
+ dcc_add_surface_area_image(dcc, surface_id, &area, NULL, FALSE);
+ red_channel_client_push(RED_CHANNEL_CLIENT(dcc));
+}
+
+static void dcc_init_stream_agents(DisplayChannelClient *dcc)
+{
+ int i;
+ DisplayChannel *display = DCC_TO_DC(dcc);
+ RedChannel *channel = RED_CHANNEL_CLIENT(dcc)->channel;
+
+ for (i = 0; i < NUM_STREAMS; i++) {
+ StreamAgent *agent = &dcc->stream_agents[i];
+ agent->stream = &display->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);
+ }
+ dcc->use_mjpeg_encoder_rate_control =
+ red_channel_client_test_remote_cap(RED_CHANNEL_CLIENT(dcc), SPICE_DISPLAY_CAP_STREAM_REPORT);
+}
+
+#define DISPLAY_FREE_LIST_DEFAULT_SIZE 128
+
DisplayChannelClient *dcc_new(DisplayChannel *display,
RedClient *client, RedsStream *stream,
int mig_target,
@@ -40,6 +131,7 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
common_caps, num_common_caps,
caps, num_caps);
spice_return_val_if_fail(dcc, NULL);
+ spice_info("New display (client %p) dcc %p stream %p", client, dcc, stream);
ring_init(&dcc->palette_cache_lru);
dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE;
@@ -49,11 +141,89 @@ DisplayChannelClient *dcc_new(DisplayChannel *display,
// TODO: tune quality according to bandwidth
dcc->jpeg_quality = 85;
+ size_t stream_buf_size;
+ stream_buf_size = 32*1024;
+ dcc->send_data.stream_outbuf = spice_malloc(stream_buf_size);
+ dcc->send_data.stream_outbuf_size = stream_buf_size;
+ dcc->send_data.free_list.res =
+ spice_malloc(sizeof(SpiceResourceList) +
+ DISPLAY_FREE_LIST_DEFAULT_SIZE * sizeof(SpiceResourceID));
+ dcc->send_data.free_list.res_size = DISPLAY_FREE_LIST_DEFAULT_SIZE;
+
+ dcc_init_stream_agents(dcc);
+
dcc_encoders_init(dcc);
return dcc;
}
+static void dcc_create_all_streams(DisplayChannelClient *dcc)
+{
+ Ring *ring = &DCC_TO_DC(dcc)->streams;
+ RingItem *item = ring;
+
+ while ((item = ring_next(ring, item))) {
+ Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
+ dcc_create_stream(dcc, stream);
+ }
+}
+
+/* TODO: this function is evil^Wsynchronous, fix */
+static int display_channel_client_wait_for_init(DisplayChannelClient *dcc)
+{
+ dcc->expect_init = TRUE;
+ uint64_t end_time = red_get_monotonic_time() + DISPLAY_CLIENT_TIMEOUT;
+ for (;;) {
+ red_channel_client_receive(RED_CHANNEL_CLIENT(dcc));
+ if (!red_channel_client_is_connected(RED_CHANNEL_CLIENT(dcc))) {
+ break;
+ }
+ if (dcc->pixmap_cache && dcc->glz_dict) {
+ dcc->pixmap_cache_generation = dcc->pixmap_cache->generation;
+ /* TODO: move common.id? if it's used for a per client structure.. */
+ spice_info("creating encoder with id == %d", dcc->common.id);
+ dcc->glz = glz_encoder_create(dcc->common.id, dcc->glz_dict->dict, &dcc->glz_data.usr);
+ if (!dcc->glz) {
+ spice_critical("create global lz failed");
+ }
+ return TRUE;
+ }
+ if (red_get_monotonic_time() > end_time) {
+ spice_warning("timeout");
+ red_channel_client_disconnect(RED_CHANNEL_CLIENT(dcc));
+ break;
+ }
+ usleep(DISPLAY_CLIENT_RETRY_INTERVAL);
+ }
+ return FALSE;
+}
+
+void dcc_start(DisplayChannelClient *dcc)
+{
+ DisplayChannel *display = DCC_TO_DC(dcc);
+ RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
+
+ red_channel_client_push_set_ack(RED_CHANNEL_CLIENT(dcc));
+
+ if (red_channel_client_waits_for_migrate_data(rcc))
+ return;
+
+ if (!display_channel_client_wait_for_init(dcc))
+ return;
+
+ red_channel_client_ack_zero_messages_window(RED_CHANNEL_CLIENT(dcc));
+ if (display->surfaces[0].context.canvas) {
+ display_channel_current_flush(display, 0);
+ red_channel_client_pipe_add_type(rcc, PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE);
+ dcc_create_surface(dcc, 0);
+ dcc_push_surface_image(dcc, 0);
+ dcc_push_monitors_config(dcc);
+ red_pipe_add_verb(rcc, SPICE_MSG_DISPLAY_MARK);
+ dcc_create_all_streams(dcc);
+ }
+}
+
+
void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent)
{
StreamClipItem *item = stream_clip_item_new(dcc, agent);