diff options
author | Marc-André Lureau <marcandre.lureau@gmail.com> | 2013-09-17 15:53:05 +0200 |
---|---|---|
committer | Fabiano Fidêncio <fidencio@redhat.com> | 2015-02-23 23:00:38 +0100 |
commit | df586a4da1fcaea044271a9523ca038a9ce838d5 (patch) | |
tree | 2c8fb3a552d5cf9ce9a12d155c30cc39bafb8c86 /server | |
parent | c0fa5717c6454f3dc9e971c44398558079b9077c (diff) | |
download | spice-df586a4da1fcaea044271a9523ca038a9ce838d5.tar.gz spice-df586a4da1fcaea044271a9523ca038a9ce838d5.tar.xz spice-df586a4da1fcaea044271a9523ca038a9ce838d5.zip |
worker: start a DisplayChannelClient unit
Diffstat (limited to 'server')
-rw-r--r-- | server/Makefile.am | 2 | ||||
-rw-r--r-- | server/dcc.c | 113 | ||||
-rw-r--r-- | server/dcc.h | 116 | ||||
-rw-r--r-- | server/dcc_encoders.c | 1 | ||||
-rw-r--r-- | server/dcc_encoders.h | 1 | ||||
-rw-r--r-- | server/display_channel.c | 120 | ||||
-rw-r--r-- | server/display_channel.h | 111 | ||||
-rw-r--r-- | server/red_worker.c | 4 | ||||
-rw-r--r-- | server/red_worker.h | 2 | ||||
-rw-r--r-- | server/stream.h | 1 |
10 files changed, 240 insertions, 231 deletions
diff --git a/server/Makefile.am b/server/Makefile.am index 79f853cf..10696316 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -134,6 +134,8 @@ libspice_server_la_SOURCES = \ utils.h \ stream.c \ stream.h \ + dcc.c \ + dcc.h \ dcc_encoders.c \ dcc_encoders.h \ $(NULL) diff --git a/server/dcc.c b/server/dcc.c new file mode 100644 index 00000000..d8b31408 --- /dev/null +++ b/server/dcc.c @@ -0,0 +1,113 @@ +#include "dcc.h" +#include "display_channel.h" + +DisplayChannelClient *dcc_new(DisplayChannel *display, + RedClient *client, RedsStream *stream, + int mig_target, + uint32_t *common_caps, int num_common_caps, + uint32_t *caps, int num_caps, + spice_image_compression_t image_compression, + spice_wan_compression_t jpeg_state, + spice_wan_compression_t zlib_glz_state) + +{ + DisplayChannelClient *dcc; + + dcc = (DisplayChannelClient*)common_channel_new_client( + COMMON_CHANNEL(display), sizeof(DisplayChannelClient), + client, stream, mig_target, TRUE, + common_caps, num_common_caps, + caps, num_caps); + spice_return_val_if_fail(dcc, NULL); + + ring_init(&dcc->palette_cache_lru); + dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; + dcc->image_compression = image_compression; + dcc->jpeg_state = jpeg_state; + dcc->zlib_glz_state = zlib_glz_state; + // todo: tune quality according to bandwidth + dcc->jpeg_quality = 85; + + dcc_encoders_init(dcc); + + return dcc; +} + +void dcc_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent) +{ + StreamClipItem *item = stream_clip_item_new(dcc, agent); + int n_rects; + + item->clip_type = SPICE_CLIP_TYPE_RECTS; + + 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->clip, item->rects->rects, n_rects); + + red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), (PipeItem *)item); +} + +static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel, + MonitorsConfig *monitors_config) +{ + MonitorsConfigItem *mci; + + mci = (MonitorsConfigItem *)spice_malloc(sizeof(*mci)); + mci->monitors_config = monitors_config; + + red_channel_pipe_item_init(channel, + &mci->pipe_item, PIPE_ITEM_TYPE_MONITORS_CONFIG); + return mci; +} + +void dcc_push_monitors_config(DisplayChannelClient *dcc) +{ + DisplayChannel *dc = DCC_TO_DC(dcc); + MonitorsConfig *monitors_config = dc->monitors_config; + MonitorsConfigItem *mci; + + if (monitors_config == NULL) { + spice_warning("monitors_config is NULL"); + return; + } + + if (!red_channel_client_test_remote_cap(&dcc->common.base, + SPICE_DISPLAY_CAP_MONITORS_CONFIG)) { + return; + } + + mci = monitors_config_item_new(dcc->common.base.channel, + monitors_config_ref(dc->monitors_config)); + red_channel_client_pipe_add(&dcc->common.base, &mci->pipe_item); + red_channel_client_push(&dcc->common.base); +} + +static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel, + uint32_t surface_id) +{ + SurfaceDestroyItem *destroy; + + destroy = (SurfaceDestroyItem *)malloc(sizeof(SurfaceDestroyItem)); + destroy->surface_destroy.surface_id = surface_id; + red_channel_pipe_item_init(channel, &destroy->pipe_item, + PIPE_ITEM_TYPE_DESTROY_SURFACE); + + return destroy; +} + +void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id) +{ + DisplayChannel *display = DCC_TO_DC(dcc); + RedChannel *channel = RED_CHANNEL(display); + SurfaceDestroyItem *destroy; + + if (!dcc || COMMON_CHANNEL(display)->during_target_migrate || + !dcc->surface_client_created[surface_id]) { + return; + } + + dcc->surface_client_created[surface_id] = FALSE; + destroy = surface_destroy_item_new(channel, surface_id); + red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item); +} diff --git a/server/dcc.h b/server/dcc.h new file mode 100644 index 00000000..396946cd --- /dev/null +++ b/server/dcc.h @@ -0,0 +1,116 @@ +#ifndef DCC_H_ +# define DCC_H_ + +#include "red_worker.h" +#include "pixmap_cache.h" +#include "cache_item.h" +#include "dcc_encoders.h" +#include "stream.h" + +#define PALETTE_CACHE_HASH_SHIFT 8 +#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT) +#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1) +#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK) +#define CLIENT_PALETTE_CACHE_SIZE 128 + +/* Each drawable can refer to at most 3 images: src, brush and mask */ +#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3 + +typedef struct WaitForChannels { + SpiceMsgWaitForChannels header; + SpiceWaitForChannel buf[MAX_CACHE_CLIENTS]; +} WaitForChannels; + +typedef struct FreeList { + int res_size; + SpiceResourceList *res; + uint64_t sync[MAX_CACHE_CLIENTS]; + WaitForChannels wait; +} FreeList; + +struct _DisplayChannelClient { + CommonChannelClient common; + spice_image_compression_t image_compression; + spice_wan_compression_t jpeg_state; + spice_wan_compression_t zlib_glz_state; + int jpeg_quality; + int zlib_level; + + QuicData quic_data; + QuicContext *quic; + LzData lz_data; + LzContext *lz; + JpegData jpeg_data; + JpegEncoderContext *jpeg; +#ifdef USE_LZ4 + Lz4Data lz4_data; + Lz4EncoderContext *lz4; +#endif + ZlibData zlib_data; + ZlibEncoder *zlib; + + int expect_init; + + PixmapCache *pixmap_cache; + uint32_t pixmap_cache_generation; + int pending_pixmaps_sync; + + CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE]; + Ring palette_cache_lru; + long palette_cache_available; + uint32_t palette_cache_items; + + struct { + uint32_t stream_outbuf_size; + uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!! + + FreeList free_list; + uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS]; + int num_pixmap_cache_items; + } send_data; + + /* global lz encoding entities */ + GlzSharedDictionary *glz_dict; + GlzEncoderContext *glz; + GlzData glz_data; + + Ring glz_drawables; // all the living lz drawable, ordered by encoding time + Ring glz_drawables_inst_to_free; // list of instances to be freed + pthread_mutex_t glz_drawables_inst_to_free_lock; + + uint8_t surface_client_created[NUM_SURFACES]; + QRegion surface_client_lossy_region[NUM_SURFACES]; + + StreamAgent stream_agents[NUM_STREAMS]; + int use_mjpeg_encoder_rate_control; + uint32_t streams_max_latency; + uint64_t streams_max_bit_rate; +}; + +#define DCC_TO_WORKER(dcc) \ + (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker) +#define DCC_TO_DC(dcc) \ + SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base) +#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base) + + +DisplayChannelClient* dcc_new (DisplayChannel *display, + RedClient *client, + RedsStream *stream, + int mig_target, + uint32_t *common_caps, + int num_common_caps, + uint32_t *caps, + int num_caps, + spice_image_compression_t image_compression, + spice_wan_compression_t jpeg_state, + spice_wan_compression_t zlib_glz_state); +void dcc_push_monitors_config (DisplayChannelClient *dcc); +void dcc_destroy_surface (DisplayChannelClient *dcc, + uint32_t surface_id); +void dcc_stream_agent_clip (DisplayChannelClient* dcc, + StreamAgent *agent); +void dcc_create_stream (DisplayChannelClient *dcc, + Stream *stream); + +#endif /* DCC_H_ */ diff --git a/server/dcc_encoders.c b/server/dcc_encoders.c index 50ca01df..678083e4 100644 --- a/server/dcc_encoders.c +++ b/server/dcc_encoders.c @@ -1,5 +1,4 @@ #include <glib.h> -#include <setjmp.h> #include "dcc_encoders.h" #include "display_channel.h" diff --git a/server/dcc_encoders.h b/server/dcc_encoders.h index b8913aca..e9ed9843 100644 --- a/server/dcc_encoders.h +++ b/server/dcc_encoders.h @@ -1,6 +1,7 @@ #ifndef DCC_ENCODERS_H_ # define DCC_ENCODERS_H_ +#include <setjmp.h> #include "common/marshaller.h" #include "common/quic.h" #include "red_channel.h" diff --git a/server/display_channel.c b/server/display_channel.c index 9e6466f1..fb7e51b8 100644 --- a/server/display_channel.c +++ b/server/display_channel.c @@ -115,53 +115,6 @@ void display_channel_compress_stats_print(const DisplayChannel *display_channel) #endif } -DisplayChannelClient *dcc_new(DisplayChannel *display, - RedClient *client, RedsStream *stream, - int mig_target, - uint32_t *common_caps, int num_common_caps, - uint32_t *caps, int num_caps, - spice_image_compression_t image_compression, - spice_wan_compression_t jpeg_state, - spice_wan_compression_t zlib_glz_state) - -{ - DisplayChannelClient *dcc; - - dcc = (DisplayChannelClient*)common_channel_new_client( - COMMON_CHANNEL(display), sizeof(DisplayChannelClient), - client, stream, mig_target, TRUE, - common_caps, num_common_caps, - caps, num_caps); - spice_return_val_if_fail(dcc, NULL); - - ring_init(&dcc->palette_cache_lru); - dcc->palette_cache_available = CLIENT_PALETTE_CACHE_SIZE; - dcc->image_compression = image_compression; - dcc->jpeg_state = jpeg_state; - dcc->zlib_glz_state = zlib_glz_state; - // todo: tune quality according to bandwidth - dcc->jpeg_quality = 85; - - dcc_encoders_init(dcc); - - return dcc; -} - -void dcc_add_stream_agent_clip(DisplayChannelClient* dcc, StreamAgent *agent) -{ - StreamClipItem *item = stream_clip_item_new(dcc, agent); - int n_rects; - - item->clip_type = SPICE_CLIP_TYPE_RECTS; - - 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->clip, item->rects->rects, n_rects); - - red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), (PipeItem *)item); -} - MonitorsConfig* monitors_config_ref(MonitorsConfig *monitors_config) { monitors_config->refs++; @@ -207,75 +160,6 @@ MonitorsConfig* monitors_config_new(QXLHead *heads, ssize_t nheads, ssize_t max) return mc; } -static MonitorsConfigItem *monitors_config_item_new(RedChannel* channel, - MonitorsConfig *monitors_config) -{ - MonitorsConfigItem *mci; - - mci = (MonitorsConfigItem *)spice_malloc(sizeof(*mci)); - mci->monitors_config = monitors_config; - - red_channel_pipe_item_init(channel, - &mci->pipe_item, PIPE_ITEM_TYPE_MONITORS_CONFIG); - return mci; -} - -static void red_monitors_config_item_add(DisplayChannelClient *dcc) -{ - DisplayChannel *dc = DCC_TO_DC(dcc); - MonitorsConfigItem *mci; - - mci = monitors_config_item_new(dcc->common.base.channel, - monitors_config_ref(dc->monitors_config)); - red_channel_client_pipe_add(&dcc->common.base, &mci->pipe_item); -} - -void dcc_push_monitors_config(DisplayChannelClient *dcc) -{ - MonitorsConfig *monitors_config = DCC_TO_DC(dcc)->monitors_config; - - if (monitors_config == NULL) { - spice_warning("monitors_config is NULL"); - return; - } - - if (!red_channel_client_test_remote_cap(&dcc->common.base, - SPICE_DISPLAY_CAP_MONITORS_CONFIG)) { - return; - } - red_monitors_config_item_add(dcc); - red_channel_client_push(&dcc->common.base); -} - -static SurfaceDestroyItem *surface_destroy_item_new(RedChannel *channel, - uint32_t surface_id) -{ - SurfaceDestroyItem *destroy; - - destroy = (SurfaceDestroyItem *)malloc(sizeof(SurfaceDestroyItem)); - destroy->surface_destroy.surface_id = surface_id; - red_channel_pipe_item_init(channel, &destroy->pipe_item, - PIPE_ITEM_TYPE_DESTROY_SURFACE); - - return destroy; -} - -void dcc_push_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id) -{ - DisplayChannel *display = DCC_TO_DC(dcc); - RedChannel *channel = RED_CHANNEL(display); - SurfaceDestroyItem *destroy; - - if (!dcc || COMMON_CHANNEL(display)->during_target_migrate || - !dcc->surface_client_created[surface_id]) { - return; - } - - dcc->surface_client_created[surface_id] = FALSE; - destroy = surface_destroy_item_new(channel, surface_id); - red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &destroy->pipe_item); -} - int display_channel_get_streams_timeout(DisplayChannel *display) { int timeout = INT_MAX; @@ -367,7 +251,7 @@ void display_channel_surface_unref(DisplayChannel *display, uint32_t surface_id) region_destroy(&surface->draw_dirty_region); surface->context.canvas = NULL; FOREACH_DCC(display, link, next, dcc) { - dcc_push_destroy_surface(dcc, surface_id); + dcc_destroy_surface(dcc, surface_id); } spice_warn_if(!ring_is_empty(&surface->depend_on_me)); @@ -447,7 +331,7 @@ static void streams_update_visible_region(DisplayChannel *display, Drawable *dra 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); - dcc_add_stream_agent_clip(dcc, agent); + dcc_stream_agent_clip(dcc, agent); } } } diff --git a/server/display_channel.h b/server/display_channel.h index 61d8abd3..4d108c10 100644 --- a/server/display_channel.h +++ b/server/display_channel.h @@ -33,32 +33,8 @@ #include "utils.h" #include "tree_item.h" #include "stream.h" -#include "dcc_encoders.h" +#include "dcc.h" -#define PALETTE_CACHE_HASH_SHIFT 8 -#define PALETTE_CACHE_HASH_SIZE (1 << PALETTE_CACHE_HASH_SHIFT) -#define PALETTE_CACHE_HASH_MASK (PALETTE_CACHE_HASH_SIZE - 1) -#define PALETTE_CACHE_HASH_KEY(id) ((id) & PALETTE_CACHE_HASH_MASK) - -#define CLIENT_PALETTE_CACHE_SIZE 128 - -/* Each drawable can refer to at most 3 images: src, brush and mask */ -#define MAX_DRAWABLE_PIXMAP_CACHE_ITEMS 3 - -#define NUM_STREAMS 50 -#define NUM_SURFACES 10000 - -typedef struct WaitForChannels { - SpiceMsgWaitForChannels header; - SpiceWaitForChannel buf[MAX_CACHE_CLIENTS]; -} WaitForChannels; - -typedef struct FreeList { - int res_size; - SpiceResourceList *res; - uint64_t sync[MAX_CACHE_CLIENTS]; - WaitForChannels wait; -} FreeList; typedef struct DependItem { Drawable *drawable; @@ -102,72 +78,6 @@ struct Drawable { SAFE_FOREACH(link, next, drawable, &(drawable)->pipes, dpi, LINK_TO_DPI(link)) -struct _DisplayChannelClient { - CommonChannelClient common; - spice_image_compression_t image_compression; - spice_wan_compression_t jpeg_state; - spice_wan_compression_t zlib_glz_state; - int jpeg_quality; - int zlib_level; - - QuicData quic_data; - QuicContext *quic; - LzData lz_data; - LzContext *lz; - JpegData jpeg_data; - JpegEncoderContext *jpeg; -#ifdef USE_LZ4 - Lz4Data lz4_data; - Lz4EncoderContext *lz4; -#endif - ZlibData zlib_data; - ZlibEncoder *zlib; - - int expect_init; - - PixmapCache *pixmap_cache; - uint32_t pixmap_cache_generation; - int pending_pixmaps_sync; - - CacheItem *palette_cache[PALETTE_CACHE_HASH_SIZE]; - Ring palette_cache_lru; - long palette_cache_available; - uint32_t palette_cache_items; - - struct { - uint32_t stream_outbuf_size; - uint8_t *stream_outbuf; // caution stream buffer is also used as compress bufs!!! - - FreeList free_list; - uint64_t pixmap_cache_items[MAX_DRAWABLE_PIXMAP_CACHE_ITEMS]; - int num_pixmap_cache_items; - } send_data; - - /* global lz encoding entities */ - GlzSharedDictionary *glz_dict; - GlzEncoderContext *glz; - GlzData glz_data; - - Ring glz_drawables; // all the living lz drawable, ordered by encoding time - Ring glz_drawables_inst_to_free; // list of instances to be freed - pthread_mutex_t glz_drawables_inst_to_free_lock; - - uint8_t surface_client_created[NUM_SURFACES]; - QRegion surface_client_lossy_region[NUM_SURFACES]; - - StreamAgent stream_agents[NUM_STREAMS]; - int use_mjpeg_encoder_rate_control; - uint32_t streams_max_latency; - uint64_t streams_max_bit_rate; -}; - -#define DCC_TO_WORKER(dcc) \ - (SPICE_CONTAINEROF((dcc)->common.base.channel, CommonChannel, base)->worker) -#define DCC_TO_DC(dcc) \ - SPICE_CONTAINEROF((dcc)->common.base.channel, DisplayChannel, common.base) -#define RCC_TO_DCC(rcc) SPICE_CONTAINEROF((rcc), DisplayChannelClient, common.base) - - enum { PIPE_ITEM_TYPE_DRAW = PIPE_ITEM_TYPE_COMMON_LAST, PIPE_ITEM_TYPE_IMAGE, @@ -185,25 +95,6 @@ enum { PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT, }; -DisplayChannelClient* dcc_new (DisplayChannel *display, - RedClient *client, - RedsStream *stream, - int mig_target, - uint32_t *common_caps, - int num_common_caps, - uint32_t *caps, - int num_caps, - spice_image_compression_t image_compression, - spice_wan_compression_t jpeg_state, - spice_wan_compression_t zlib_glz_state); -void dcc_push_monitors_config (DisplayChannelClient *dcc); -void dcc_push_destroy_surface (DisplayChannelClient *dcc, - uint32_t surface_id); -void dcc_add_stream_agent_clip (DisplayChannelClient* dcc, - StreamAgent *agent); -void dcc_create_stream (DisplayChannelClient *dcc, - Stream *stream); - typedef struct DrawablePipeItem { RingItem base; /* link for a list of pipe items held by Drawable */ PipeItem dpi_pipe_item; /* link for the client's pipe itself */ diff --git a/server/red_worker.c b/server/red_worker.c index 31bfce0b..7443c077 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -247,7 +247,7 @@ void attach_stream(DisplayChannel *display, Drawable *drawable, Stream *stream) if (!region_is_equal(&clip_in_draw_dest, &drawable->tree_item.base.rgn)) { region_remove(&agent->clip, &drawable->red_drawable->bbox); region_or(&agent->clip, &drawable->tree_item.base.rgn); - dcc_add_stream_agent_clip(dcc, agent); + dcc_stream_agent_clip(dcc, agent); } #ifdef STREAM_STATS agent->stats.num_input_frames++; @@ -911,7 +911,7 @@ static void dcc_detach_stream_gracefully(DisplayChannelClient *dcc, /* stopping the client from playing older frames at once*/ region_clear(&agent->clip); - dcc_add_stream_agent_clip(dcc, agent); + dcc_stream_agent_clip(dcc, agent); if (region_is_empty(&agent->vis_region)) { spice_debug("stream %d: vis region empty", stream_id); diff --git a/server/red_worker.h b/server/red_worker.h index 585024db..f08bd627 100644 --- a/server/red_worker.h +++ b/server/red_worker.h @@ -27,6 +27,8 @@ #include "red_dispatcher.h" #include "red_parse_qxl.h" +#define NUM_SURFACES 10000 + typedef struct RedWorker RedWorker; typedef struct CommonChannelClient { diff --git a/server/stream.h b/server/stream.h index 266da6ba..6de848de 100644 --- a/server/stream.h +++ b/server/stream.h @@ -23,6 +23,7 @@ #define RED_STREAM_DEFAULT_HIGH_START_BIT_RATE (10 * 1024 * 1024) // 10Mbps #define RED_STREAM_DEFAULT_LOW_START_BIT_RATE (2.5 * 1024 * 1024) // 2.5Mbps #define MAX_FPS 30 +#define NUM_STREAMS 50 /* move back to display_channel once struct private */ typedef struct DisplayChannel DisplayChannel; |