From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> --- server/dcc.c | 26 ++++++ server/dcc.h | 3 + server/display-channel.c | 151 +++++++++++++++++++++++++++++++++ server/display-channel.h | 19 +++++ server/red_worker.c | 215 +++-------------------------------------------- 5 files changed, 211 insertions(+), 203 deletions(-) diff --git a/server/dcc.c b/server/dcc.c index 5d666cb..e3b0c55 100644 --- a/server/dcc.c +++ b/server/dcc.c @@ -372,6 +372,32 @@ void dcc_start(DisplayChannelClient *dcc) } } +static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) +{ + int i; + + for (i = 0; i < NUM_STREAMS; i++) { + StreamAgent *agent = &dcc->stream_agents[i]; + region_destroy(&agent->vis_region); + region_destroy(&agent->clip); + if (agent->mjpeg_encoder) { + mjpeg_encoder_destroy(agent->mjpeg_encoder); + agent->mjpeg_encoder = NULL; + } + } +} + +void dcc_stop(DisplayChannelClient *dcc) +{ + pixmap_cache_unref(dcc->pixmap_cache); + dcc->pixmap_cache = NULL; + dcc_release_glz(dcc); + dcc_palette_cache_reset(dcc); + free(dcc->send_data.stream_outbuf); + free(dcc->send_data.free_list.res); + dcc_destroy_stream_agents(dcc); + dcc_encoders_free(dcc); +} void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent) { diff --git a/server/dcc.h b/server/dcc.h index 62261e8..dc6f1e7 100644 --- a/server/dcc.h +++ b/server/dcc.h @@ -161,6 +161,7 @@ DisplayChannelClient* dcc_new (DisplayCha spice_wan_compression_t jpeg_state, spice_wan_compression_t zlib_glz_state); void dcc_start (DisplayChannelClient *dcc); +void dcc_stop (DisplayChannelClient *dcc); int dcc_handle_message (RedChannelClient *rcc, uint32_t size, uint16_t type, void *msg); @@ -198,6 +199,8 @@ void dcc_add_drawable_after (DisplayCha void dcc_release_item (DisplayChannelClient *dcc, PipeItem *item, int item_pushed); +void dcc_send_item (DisplayChannelClient *dcc, + PipeItem *item); typedef struct compress_send_data_t { void* comp_buf; diff --git a/server/display-channel.c b/server/display-channel.c index 855b65a..66b661e 100644 --- a/server/display-channel.c +++ b/server/display-channel.c @@ -1402,3 +1402,154 @@ void display_channel_draw(DisplayChannel *display, const SpiceRect *area, int su draw_until(display, surface, last); surface_update_dest(surface, area); } + +static void on_disconnect(RedChannelClient *rcc) +{ + DisplayChannel *display; + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); + RedWorker *worker; + + spice_info(NULL); + spice_return_if_fail(rcc != NULL); + + display = DCC_TO_DC(dcc); + worker = COMMON_CHANNEL(display)->worker; + spice_return_if_fail(rcc->channel == red_worker_get_display_channel(worker)); + + dcc_stop(dcc); // TODO: start/stop -> connect/disconnect? + display_channel_compress_stats_print(display); + + // this was the last channel client + spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d", + display->drawable_count, display->red_drawable_count, + display->glz_drawable_count); +} + +static void send_item(RedChannelClient *rcc, PipeItem *item) +{ + dcc_send_item(RCC_TO_DCC(rcc), item); +} + +static void hold_item(RedChannelClient *rcc, PipeItem *item) +{ + spice_return_if_fail(item); + + switch (item->type) { + case PIPE_ITEM_TYPE_DRAW: + drawable_pipe_item_ref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item)); + break; + case PIPE_ITEM_TYPE_STREAM_CLIP: + ((StreamClipItem *)item)->refs++; + break; + case PIPE_ITEM_TYPE_UPGRADE: + ((UpgradeItem *)item)->refs++; + break; + case PIPE_ITEM_TYPE_IMAGE: + ((ImageItem *)item)->refs++; + break; + default: + spice_warn_if_reached(); + } +} + +static void release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed) +{ + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); + + spice_return_if_fail(item != NULL); + dcc_release_item(dcc, item, item_pushed); +} + +static int handle_migrate_flush_mark(RedChannelClient *rcc) +{ + DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); + RedChannel *channel = RED_CHANNEL(display_channel); + + red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA); + return TRUE; +} + +static uint64_t handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message) +{ + SpiceMigrateDataDisplay *migrate_data; + + migrate_data = (SpiceMigrateDataDisplay *)((uint8_t *)message + sizeof(SpiceMigrateDataHeader)); + + return migrate_data->message_serial; +} + +static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message) +{ + return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message); +} + +static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id) +{ + DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces); + + spice_return_val_if_fail(validate_surface(display, surface_id), NULL); + + return display->surfaces[surface_id].context.canvas; +} + +DisplayChannel* display_channel_new(RedWorker *worker, int migrate, int stream_video, + uint32_t n_surfaces) +{ + DisplayChannel *display; + ChannelCbs cbs = { + .on_disconnect = on_disconnect, + .send_item = send_item, + .hold_item = hold_item, + .release_item = release_item, + .handle_migrate_flush_mark = handle_migrate_flush_mark, + .handle_migrate_data = handle_migrate_data, + .handle_migrate_data_get_serial = handle_migrate_data_get_serial + }; + static SpiceImageSurfacesOps image_surfaces_ops = { + image_surfaces_get, + }; + + spice_return_val_if_fail(num_renderers > 0, NULL); + + spice_info("create display channel"); + display = (DisplayChannel *)red_worker_new_channel( + worker, sizeof(*display), "display_channel", + SPICE_CHANNEL_DISPLAY, + SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER, + &cbs, dcc_handle_message); + spice_return_val_if_fail(display, NULL); + + stat_init(&display->add_stat, "add", red_worker_get_clockid(worker)); + stat_init(&display->exclude_stat, "exclude", red_worker_get_clockid(worker)); + stat_init(&display->__exclude_stat, "__exclude", red_worker_get_clockid(worker)); +#ifdef RED_STATISTICS + RedChannel *channel = RED_CHANNEL(display); + display->cache_hits_counter = stat_add_counter(channel->stat, + "cache_hits", TRUE); + display->add_to_cache_counter = stat_add_counter(channel->stat, + "add_to_cache", TRUE); + display->non_cache_counter = stat_add_counter(channel->stat, + "non_cache", TRUE); +#endif + stat_compress_init(&display->lz_stat, "lz"); + stat_compress_init(&display->glz_stat, "glz"); + stat_compress_init(&display->quic_stat, "quic"); + stat_compress_init(&display->jpeg_stat, "jpeg"); + stat_compress_init(&display->zlib_glz_stat, "zlib"); + stat_compress_init(&display->jpeg_alpha_stat, "jpeg_alpha"); + stat_compress_init(&display->lz4_stat, "lz4"); + + display->n_surfaces = n_surfaces; + display->num_renderers = num_renderers; + memcpy(display->renderers, renderers, sizeof(display->renderers)); + display->renderer = RED_RENDERER_INVALID; + + ring_init(&display->current_list); + display->image_surfaces.ops = &image_surfaces_ops; + drawables_init(display); + image_cache_init(&display->image_cache); + display->stream_video = stream_video; + display_channel_init_streams(display); + + return display; +} diff --git a/server/display-channel.h b/server/display-channel.h index 0a6f120..42b3850 100644 --- a/server/display-channel.h +++ b/server/display-channel.h @@ -251,6 +251,10 @@ typedef struct UpgradeItem { } UpgradeItem; +DisplayChannel* display_channel_new (RedWorker *worker, + int migrate, + int stream_video, + uint32_t n_surfaces); void display_channel_draw (DisplayChannel *display, const SpiceRect *area, int surface_id); @@ -281,6 +285,21 @@ void display_channel_flush_all_surfaces (DisplayCha void display_channel_free_glz_drawables_to_free(DisplayChannel *display); void display_channel_free_glz_drawables (DisplayChannel *display); +static inline int validate_surface(DisplayChannel *display, uint32_t surface_id) +{ + if SPICE_UNLIKELY(surface_id >= display->n_surfaces) { + spice_warning("invalid surface_id %u", surface_id); + return 0; + } + if (!display->surfaces[surface_id].context.canvas) { + spice_warning("canvas address is %p for %d (and is NULL)\n", + &(display->surfaces[surface_id].context.canvas), surface_id); + spice_warning("failed on %d", surface_id); + return 0; + } + return 1; +} + static inline int is_equal_path(SpicePath *path1, SpicePath *path2) { SpicePathSeg *seg1, *seg2; diff --git a/server/red_worker.c b/server/red_worker.c index 6761e6f..cef546e 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -135,8 +135,6 @@ typedef struct BitmapData { SpiceRect lossy_rect; } BitmapData; -static inline int validate_surface(DisplayChannel *display, uint32_t surface_id); - static inline void display_begin_send_message(RedChannelClient *rcc); static void red_create_surface(DisplayChannel *display, uint32_t surface_id, uint32_t width, uint32_t height, int32_t stride, uint32_t format, @@ -178,21 +176,6 @@ static int validate_drawable_bbox(DisplayChannel *display, RedDrawable *drawable return TRUE; } -static inline int validate_surface(DisplayChannel *display, uint32_t surface_id) -{ - if SPICE_UNLIKELY(surface_id >= display->n_surfaces) { - spice_warning("invalid surface_id %u", surface_id); - return 0; - } - if (!display->surfaces[surface_id].context.canvas) { - spice_warning("canvas address is %p for %d (and is NULL)\n", - &(display->surfaces[surface_id].context.canvas), surface_id); - spice_warning("failed on %d", surface_id); - return 0; - } - return 1; -} - static int display_is_connected(RedWorker *worker) { return (worker->display_channel && red_channel_is_connected( @@ -606,21 +589,6 @@ static void display_channel_streams_timeout(DisplayChannel *display) } } -static void dcc_destroy_stream_agents(DisplayChannelClient *dcc) -{ - int i; - - for (i = 0; i < NUM_STREAMS; i++) { - StreamAgent *agent = &dcc->stream_agents[i]; - region_destroy(&agent->vis_region); - region_destroy(&agent->clip); - if (agent->mjpeg_encoder) { - mjpeg_encoder_destroy(agent->mjpeg_encoder); - agent->mjpeg_encoder = NULL; - } - } -} - static void red_get_area(DisplayChannel *display, int surface_id, const SpiceRect *area, uint8_t *dest, int dest_stride, int update) { @@ -918,24 +886,6 @@ exit: free(surface); } -static SpiceCanvas *image_surfaces_get(SpiceImageSurfaces *surfaces, uint32_t surface_id) -{ - DisplayChannel *display = SPICE_CONTAINEROF(surfaces, DisplayChannel, image_surfaces); - - spice_return_val_if_fail(validate_surface(display, surface_id), NULL); - - return display->surfaces[surface_id].context.canvas; -} - -static void image_surface_init(DisplayChannel *display) -{ - static SpiceImageSurfacesOps image_surfaces_ops = { - image_surfaces_get, - }; - - display->image_surfaces.ops = &image_surfaces_ops; -} - static int red_process_cursor(RedWorker *worker, uint32_t max_pipe_size, int *ring_is_empty) { QXLCommandExt ext_cmd; @@ -1367,13 +1317,6 @@ static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id } } -static inline void red_display_reset_send_data(DisplayChannelClient *dcc) -{ - dcc->send_data.free_list.res->count = 0; - dcc->send_data.num_pixmap_cache_items = 0; - memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync)); -} - /* set area=NULL for testing the whole surface */ static int is_surface_area_lossy(DisplayChannelClient *dcc, uint32_t surface_id, const SpiceRect *area, SpiceRect *out_lossy_area) @@ -3446,12 +3389,19 @@ static void red_marshall_stream_activate_report(RedChannelClient *rcc, spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg); } -static void send_item(RedChannelClient *rcc, PipeItem *pipe_item) +static void reset_send_data(DisplayChannelClient *dcc) +{ + dcc->send_data.free_list.res->count = 0; + dcc->send_data.num_pixmap_cache_items = 0; + memset(dcc->send_data.free_list.sync, 0, sizeof(dcc->send_data.free_list.sync)); +} + +void dcc_send_item(DisplayChannelClient *dcc, PipeItem *pipe_item) { + RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc); SpiceMarshaller *m = red_channel_client_get_marshaller(rcc); - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); - red_display_reset_send_data(dcc); + reset_send_data(dcc); switch (pipe_item->type) { case PIPE_ITEM_TYPE_DRAW: { DrawablePipeItem *dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item); @@ -3545,37 +3495,6 @@ static inline void red_push(RedWorker *worker) } } -static void on_disconnect(RedChannelClient *rcc) -{ - DisplayChannel *display; - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); - CommonChannel *common; - RedWorker *worker; - - if (!rcc) { - return; - } - spice_info(NULL); - common = SPICE_CONTAINEROF(rcc->channel, CommonChannel, base); - worker = common->worker; - display = (DisplayChannel *)rcc->channel; - spice_assert(display == worker->display_channel); - display_channel_compress_stats_print(display); - pixmap_cache_unref(dcc->pixmap_cache); - dcc->pixmap_cache = NULL; - dcc_release_glz(dcc); - dcc_palette_cache_reset(dcc); - free(dcc->send_data.stream_outbuf); - free(dcc->send_data.free_list.res); - dcc_destroy_stream_agents(dcc); - dcc_encoders_free(dcc); - - // this was the last channel client - spice_debug("#draw=%d, #red_draw=%d, #glz_draw=%d", - display->drawable_count, display->red_drawable_count, - display->glz_drawable_count); -} - void red_disconnect_all_display_TODO_remove_me(RedChannel *channel) { // TODO: we need to record the client that actually causes the timeout. So @@ -3822,29 +3741,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker) flush_cursor_commands(worker); } -static int handle_migrate_flush_mark(RedChannelClient *rcc) -{ - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); - RedChannel *channel = RED_CHANNEL(display_channel); - - red_channel_pipes_add_type(channel, PIPE_ITEM_TYPE_MIGRATE_DATA); - return TRUE; -} - -static uint64_t handle_migrate_data_get_serial(RedChannelClient *rcc, uint32_t size, void *message) -{ - SpiceMigrateDataDisplay *migrate_data; - - migrate_data = (SpiceMigrateDataDisplay *)((uint8_t *)message + sizeof(SpiceMigrateDataHeader)); - - return migrate_data->message_serial; -} - -static int handle_migrate_data(RedChannelClient *rcc, uint32_t size, void *message) -{ - return dcc_handle_migrate_data(RCC_TO_DCC(rcc), size, message); -} - static int common_channel_config_socket(RedChannelClient *rcc) { RedClient *client = red_channel_client_get_client(rcc); @@ -4027,94 +3923,6 @@ RedChannel *red_worker_new_channel(RedWorker *worker, int size, return channel; } -static void hold_item(RedChannelClient *rcc, PipeItem *item) -{ - spice_assert(item); - switch (item->type) { - case PIPE_ITEM_TYPE_DRAW: - drawable_pipe_item_ref(SPICE_CONTAINEROF(item, DrawablePipeItem, dpi_pipe_item)); - break; - case PIPE_ITEM_TYPE_STREAM_CLIP: - ((StreamClipItem *)item)->refs++; - break; - case PIPE_ITEM_TYPE_UPGRADE: - ((UpgradeItem *)item)->refs++; - break; - case PIPE_ITEM_TYPE_IMAGE: - ((ImageItem *)item)->refs++; - break; - default: - spice_critical("invalid item type"); - } -} - -static void release_item(RedChannelClient *rcc, PipeItem *item, int item_pushed) -{ - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); - - spice_return_if_fail(item != NULL); - dcc_release_item(dcc, item, item_pushed); -} - -static void display_channel_create(RedWorker *worker, int migrate, int stream_video, - uint32_t n_surfaces) -{ - DisplayChannel *display_channel; - ChannelCbs cbs = { - .on_disconnect = on_disconnect, - .send_item = send_item, - .hold_item = hold_item, - .release_item = release_item, - .handle_migrate_flush_mark = handle_migrate_flush_mark, - .handle_migrate_data = handle_migrate_data, - .handle_migrate_data_get_serial = handle_migrate_data_get_serial - }; - - spice_return_if_fail(num_renderers > 0); - - spice_info("create display channel"); - if (!(display_channel = (DisplayChannel *)red_worker_new_channel( - worker, sizeof(*display_channel), "display_channel", - SPICE_CHANNEL_DISPLAY, - SPICE_MIGRATE_NEED_FLUSH | SPICE_MIGRATE_NEED_DATA_TRANSFER, - &cbs, dcc_handle_message))) { - spice_warning("failed to create display channel"); - return; - } - worker->display_channel = display_channel; - stat_init(&display_channel->add_stat, "add", worker->clockid); - stat_init(&display_channel->exclude_stat, "exclude", worker->clockid); - stat_init(&display_channel->__exclude_stat, "__exclude", worker->clockid); -#ifdef RED_STATISTICS - RedChannel *channel = RED_CHANNEL(display_channel); - display_channel->cache_hits_counter = stat_add_counter(channel->stat, - "cache_hits", TRUE); - display_channel->add_to_cache_counter = stat_add_counter(channel->stat, - "add_to_cache", TRUE); - display_channel->non_cache_counter = stat_add_counter(channel->stat, - "non_cache", TRUE); -#endif - stat_compress_init(&display_channel->lz_stat, "lz"); - stat_compress_init(&display_channel->glz_stat, "glz"); - stat_compress_init(&display_channel->quic_stat, "quic"); - stat_compress_init(&display_channel->jpeg_stat, "jpeg"); - stat_compress_init(&display_channel->zlib_glz_stat, "zlib"); - stat_compress_init(&display_channel->jpeg_alpha_stat, "jpeg_alpha"); - stat_compress_init(&display_channel->lz4_stat, "lz4"); - - display_channel->n_surfaces = n_surfaces; - display_channel->num_renderers = num_renderers; - memcpy(display_channel->renderers, renderers, sizeof(display_channel->renderers)); - display_channel->renderer = RED_RENDERER_INVALID; - - ring_init(&display_channel->current_list); - image_surface_init(display_channel); - drawables_init(display_channel); - image_cache_init(&display_channel->image_cache); - display_channel->stream_video = stream_video; - display_channel_init_streams(display_channel); -} - static void guest_set_client_capabilities(RedWorker *worker) { int i; @@ -5174,7 +4982,8 @@ RedWorker* red_worker_new(QXLInstance *qxl, RedDispatcher *red_dispatcher) worker->cursor_channel = cursor_channel_new(worker); // TODO: handle seemless migration. Temp, setting migrate to FALSE - display_channel_create(worker, FALSE, streaming_video, init_info.n_surfaces); + worker->display_channel = display_channel_new(worker, FALSE, streaming_video, + init_info.n_surfaces); return worker; } -- 2.4.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel