diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-09-17 16:29:44 +0200 |
---|---|---|
committer | Frediano Ziglio <fziglio@redhat.com> | 2015-11-19 12:43:33 +0000 |
commit | 0e224d04fbd9a05a3289b19c32e9a8fd4afca086 (patch) | |
tree | 381b330b43233781b1fca8204ae42fa2356b8bbe /server/dcc.c | |
parent | 85920bb2e9715bc9317c2717cb14cc58f31f28ef (diff) | |
download | spice-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.c | 170 |
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); |