This patch is freaking huge :-\ Is there some automated way to check whether a function move is just a move or something else changed? On Wed, Nov 25, 2015 at 4:27 PM, Frediano Ziglio <fziglio@xxxxxxxxxx> wrote: > From: Marc-André Lureau <marcandre.lureau@xxxxxxxxx> > > --- > server/Makefile.am | 1 + > server/dcc-send.c | 2450 ++++++++++++++++++++++++++++++++++++++++++++++++++ > server/dcc.h | 2 + > server/red_worker.c | 2460 +-------------------------------------------------- > server/red_worker.h | 2 + > 5 files changed, 2462 insertions(+), 2453 deletions(-) > create mode 100644 server/dcc-send.c > > diff --git a/server/Makefile.am b/server/Makefile.am > index db1cbc3..03ac757 100644 > --- a/server/Makefile.am > +++ b/server/Makefile.am > @@ -140,6 +140,7 @@ libspice_server_la_SOURCES = \ > stream.c \ > stream.h \ > dcc.c \ > + dcc-send.c \ > dcc.h \ > display-limits.h \ > dcc-encoders.c \ > diff --git a/server/dcc-send.c b/server/dcc-send.c > new file mode 100644 > index 0000000..1dc9dcf > --- /dev/null > +++ b/server/dcc-send.c > @@ -0,0 +1,2450 @@ > +#ifdef HAVE_CONFIG_H > +#include <config.h> > +#endif > + > +#include "dcc.h" > +#include "display-channel.h" > + > +#include "common/marshaller.h" > +#include "common/generated_server_marshallers.h" > + > +typedef enum { > + FILL_BITS_TYPE_INVALID, > + FILL_BITS_TYPE_CACHE, > + FILL_BITS_TYPE_SURFACE, > + FILL_BITS_TYPE_COMPRESS_LOSSLESS, > + FILL_BITS_TYPE_COMPRESS_LOSSY, > + FILL_BITS_TYPE_BITMAP, > +} FillBitsType; > + > +typedef enum { > + BITMAP_DATA_TYPE_INVALID, > + BITMAP_DATA_TYPE_CACHE, > + BITMAP_DATA_TYPE_SURFACE, > + BITMAP_DATA_TYPE_BITMAP, > + BITMAP_DATA_TYPE_BITMAP_TO_CACHE, > +} BitmapDataType; > + > +typedef struct BitmapData { > + BitmapDataType type; > + uint64_t id; // surface id or cache item id > + SpiceRect lossy_rect; > +} BitmapData; > + > +static int dcc_pixmap_cache_unlocked_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) > +{ > + PixmapCache *cache = dcc->pixmap_cache; > + NewCacheItem *item; > + uint64_t serial; > + > + serial = red_channel_client_get_message_serial(RED_CHANNEL_CLIENT(dcc)); > + item = cache->hash_table[BITS_CACHE_HASH_KEY(id)]; > + > + while (item) { > + if (item->id == id) { > + ring_remove(&item->lru_link); > + ring_add(&cache->lru, &item->lru_link); > + spice_assert(dcc->common.id < MAX_CACHE_CLIENTS); > + item->sync[dcc->common.id] = serial; > + cache->sync[dcc->common.id] = serial; > + *lossy = item->lossy; > + break; > + } > + item = item->next; > + } > + > + return !!item; > +} > + > +static int dcc_pixmap_cache_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) > +{ > + int hit; > + PixmapCache *cache = dcc->pixmap_cache; > + > + pthread_mutex_lock(&cache->lock); > + hit = dcc_pixmap_cache_unlocked_hit(dcc, id, lossy); > + pthread_mutex_unlock(&cache->lock); > + return hit; > +} > + > +/* 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) > +{ > + RedSurface *surface; > + QRegion *surface_lossy_region; > + QRegion lossy_region; > + DisplayChannel *display = DCC_TO_DC(dcc); > + > + spice_return_val_if_fail(validate_surface(display, surface_id), FALSE); > + > + surface = &display->surfaces[surface_id]; > + surface_lossy_region = &dcc->surface_client_lossy_region[surface_id]; > + > + if (!area) { > + if (region_is_empty(surface_lossy_region)) { > + return FALSE; > + } else { > + out_lossy_area->top = 0; > + out_lossy_area->left = 0; > + out_lossy_area->bottom = surface->context.height; > + out_lossy_area->right = surface->context.width; > + return TRUE; > + } > + } > + > + region_init(&lossy_region); > + region_add(&lossy_region, area); > + region_and(&lossy_region, surface_lossy_region); > + if (!region_is_empty(&lossy_region)) { > + out_lossy_area->left = lossy_region.extents.x1; > + out_lossy_area->top = lossy_region.extents.y1; > + out_lossy_area->right = lossy_region.extents.x2; > + out_lossy_area->bottom = lossy_region.extents.y2; > + region_destroy(&lossy_region); > + return TRUE; > + } else { > + return FALSE; > + } > +} > + > +static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *area, > + Drawable *drawable, BitmapData *out_data) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + > + if (image == NULL) { > + // self bitmap > + out_data->type = BITMAP_DATA_TYPE_BITMAP; > + return FALSE; > + } > + > + if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > + int is_hit_lossy; > + > + out_data->id = image->descriptor.id; > + if (dcc_pixmap_cache_hit(dcc, image->descriptor.id, &is_hit_lossy)) { > + out_data->type = BITMAP_DATA_TYPE_CACHE; > + if (is_hit_lossy) { > + return TRUE; > + } else { > + return FALSE; > + } > + } else { > + out_data->type = BITMAP_DATA_TYPE_BITMAP_TO_CACHE; > + } > + } else { > + out_data->type = BITMAP_DATA_TYPE_BITMAP; > + } > + > + if (image->descriptor.type != SPICE_IMAGE_TYPE_SURFACE) { > + return FALSE; > + } > + > + out_data->type = BITMAP_DATA_TYPE_SURFACE; > + out_data->id = image->u.surface.surface_id; > + > + if (is_surface_area_lossy(dcc, out_data->id, > + area, &out_data->lossy_rect)) > + { > + return TRUE; > + } else { > + return FALSE; > + } > +} > + > +static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush, > + Drawable *drawable, BitmapData *out_data) > +{ > + if (brush->type == SPICE_BRUSH_TYPE_PATTERN) { > + return is_bitmap_lossy(rcc, brush->u.pattern.pat, NULL, > + drawable, out_data); > + } else { > + out_data->type = BITMAP_DATA_TYPE_INVALID; > + return FALSE; > + } > +} > + > +static PipeItem *dcc_get_tail(DisplayChannelClient *dcc) > +{ > + return (PipeItem*)ring_get_tail(&RED_CHANNEL_CLIENT(dcc)->pipe); > +} > + > +static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, > + SpiceImage *image, SpiceImage *io_image, > + int is_lossy) > +{ > + DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + > + if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > + spice_assert(image->descriptor.width * image->descriptor.height > 0); > + if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) { > + if (dcc_pixmap_cache_unlocked_add(dcc, image->descriptor.id, > + image->descriptor.width * image->descriptor.height, > + is_lossy)) { > + io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; > + dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = > + image->descriptor.id; > + stat_inc_counter(display_channel->add_to_cache_counter, 1); > + } > + } > + } > + > + if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > + stat_inc_counter(display_channel->non_cache_counter, 1); > + } > +} > + > +static void marshal_sub_msg_inval_list(SpiceMarshaller *m, > + FreeList *free_list) > +{ > + /* type + size + submessage */ > + spice_marshaller_add_uint16(m, SPICE_MSG_DISPLAY_INVAL_LIST); > + spice_marshaller_add_uint32(m, sizeof(*free_list->res) + > + free_list->res->count * sizeof(free_list->res->resources[0])); > + spice_marshall_msg_display_inval_list(m, free_list->res); > +} > + > +static void marshal_sub_msg_inval_list_wait(SpiceMarshaller *m, > + FreeList *free_list) > +{ > + /* type + size + submessage */ > + spice_marshaller_add_uint16(m, SPICE_MSG_WAIT_FOR_CHANNELS); > + spice_marshaller_add_uint32(m, sizeof(free_list->wait.header) + > + free_list->wait.header.wait_count * sizeof(free_list->wait.buf[0])); > + spice_marshall_msg_wait_for_channels(m, &free_list->wait.header); > +} > + > +/* use legacy SpiceDataHeader (with sub_list) */ > +static void send_free_list_legacy(RedChannelClient *rcc) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + FreeList *free_list = &dcc->send_data.free_list; > + SpiceMarshaller *marshaller; > + int sub_list_len = 1; > + SpiceMarshaller *wait_m = NULL; > + SpiceMarshaller *inval_m; > + SpiceMarshaller *sub_list_m; > + > + marshaller = red_channel_client_get_marshaller(rcc); > + inval_m = spice_marshaller_get_submarshaller(marshaller); > + > + marshal_sub_msg_inval_list(inval_m, free_list); > + > + if (free_list->wait.header.wait_count) { > + wait_m = spice_marshaller_get_submarshaller(marshaller); > + marshal_sub_msg_inval_list_wait(wait_m, free_list); > + sub_list_len++; > + } > + > + sub_list_m = spice_marshaller_get_submarshaller(marshaller); > + spice_marshaller_add_uint16(sub_list_m, sub_list_len); > + if (wait_m) { > + spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m)); > + } > + spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m)); > + red_channel_client_set_header_sub_list(rcc, spice_marshaller_get_offset(sub_list_m)); > +} > + > +/* use mini header and SPICE_MSG_LIST */ > +static void send_free_list(RedChannelClient *rcc) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + FreeList *free_list = &dcc->send_data.free_list; > + int sub_list_len = 1; > + SpiceMarshaller *urgent_marshaller; > + SpiceMarshaller *wait_m = NULL; > + SpiceMarshaller *inval_m; > + uint32_t sub_arr_offset; > + uint32_t wait_offset = 0; > + uint32_t inval_offset = 0; > + int i; > + > + urgent_marshaller = red_channel_client_switch_to_urgent_sender(rcc); > + for (i = 0; i < dcc->send_data.num_pixmap_cache_items; i++) { > + int dummy; > + /* When using the urgent marshaller, the serial number of the message that is > + * going to be sent right after the SPICE_MSG_LIST, is increased by one. > + * But all this message pixmaps cache references used its old serial. > + * we use pixmap_cache_items to collect these pixmaps, and we update their serial > + * by calling pixmap_cache_hit. */ > + dcc_pixmap_cache_hit(dcc, dcc->send_data.pixmap_cache_items[i], &dummy); > + } > + > + if (free_list->wait.header.wait_count) { > + red_channel_client_init_send_data(rcc, SPICE_MSG_LIST, NULL); > + } else { /* only one message, no need for a list */ > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_LIST, NULL); > + spice_marshall_msg_display_inval_list(urgent_marshaller, free_list->res); > + return; > + } > + > + inval_m = spice_marshaller_get_submarshaller(urgent_marshaller); > + marshal_sub_msg_inval_list(inval_m, free_list); > + > + if (free_list->wait.header.wait_count) { > + wait_m = spice_marshaller_get_submarshaller(urgent_marshaller); > + marshal_sub_msg_inval_list_wait(wait_m, free_list); > + sub_list_len++; > + } > + > + sub_arr_offset = sub_list_len * sizeof(uint32_t); > + > + spice_marshaller_add_uint16(urgent_marshaller, sub_list_len); > + inval_offset = spice_marshaller_get_offset(inval_m); // calc the offset before > + // adding the sub list > + // offsets array to the marshaller > + /* adding the array of offsets */ > + if (wait_m) { > + wait_offset = spice_marshaller_get_offset(wait_m); > + spice_marshaller_add_uint32(urgent_marshaller, wait_offset + sub_arr_offset); > + } > + spice_marshaller_add_uint32(urgent_marshaller, inval_offset + sub_arr_offset); > +} > + > +static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable) > +{ > + SpiceMsgDisplayBase base; > + > + base.surface_id = drawable->surface_id; > + base.box = drawable->red_drawable->bbox; > + base.clip = drawable->red_drawable->clip; > + > + spice_marshall_DisplayBase(base_marshaller, &base); > +} > + > +/* if the number of times fill_bits can be called per one qxl_drawable increases - > + MAX_LZ_DRAWABLE_INSTANCES must be increased as well */ > +static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m, > + SpiceImage *simage, Drawable *drawable, int can_lossy) > +{ > + RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc); > + DisplayChannel *display = DCC_TO_DC(dcc); > + SpiceImage image; > + compress_send_data_t comp_send_data = {0}; > + SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out; > + > + if (simage == NULL) { > + spice_assert(drawable->red_drawable->self_bitmap_image); > + simage = drawable->red_drawable->self_bitmap_image; > + } > + > + image.descriptor = simage->descriptor; > + image.descriptor.flags = 0; > + if (simage->descriptor.flags & SPICE_IMAGE_FLAGS_HIGH_BITS_SET) { > + image.descriptor.flags = SPICE_IMAGE_FLAGS_HIGH_BITS_SET; > + } > + pthread_mutex_lock(&dcc->pixmap_cache->lock); > + > + if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > + int lossy_cache_item; > + if (dcc_pixmap_cache_unlocked_hit(dcc, image.descriptor.id, &lossy_cache_item)) { > + dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = > + image.descriptor.id; > + if (can_lossy || !lossy_cache_item) { > + if (!display->enable_jpeg || lossy_cache_item) { > + image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE; > + } else { > + // making sure, in multiple monitor scenario, that lossy items that > + // should have been replaced with lossless data by one display channel, > + // will be retrieved as lossless by another display channel. > + image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS; > + } > + spice_marshall_Image(m, &image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_assert(bitmap_palette_out == NULL); > + spice_assert(lzplt_palette_out == NULL); > + stat_inc_counter(display->cache_hits_counter, 1); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_CACHE; > + } else { > + pixmap_cache_unlocked_set_lossy(dcc->pixmap_cache, simage->descriptor.id, > + FALSE); > + image.descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME; > + } > + } > + } > + > + switch (simage->descriptor.type) { > + case SPICE_IMAGE_TYPE_SURFACE: { > + int surface_id; > + RedSurface *surface; > + > + surface_id = simage->u.surface.surface_id; > + if (!validate_surface(display, surface_id)) { > + spice_warning("Invalid surface in SPICE_IMAGE_TYPE_SURFACE"); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_SURFACE; > + } > + > + surface = &display->surfaces[surface_id]; > + image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE; > + image.descriptor.flags = 0; > + image.descriptor.width = surface->context.width; > + image.descriptor.height = surface->context.height; > + > + image.u.surface.surface_id = surface_id; > + spice_marshall_Image(m, &image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_assert(bitmap_palette_out == NULL); > + spice_assert(lzplt_palette_out == NULL); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_SURFACE; > + } > + case SPICE_IMAGE_TYPE_BITMAP: { > + SpiceBitmap *bitmap = &image.u.bitmap; > +#ifdef DUMP_BITMAP > + dump_bitmap(&simage->u.bitmap); > +#endif > + /* Images must be added to the cache only after they are compressed > + in order to prevent starvation in the client between pixmap_cache and > + global dictionary (in cases of multiple monitors) */ > + if (reds_stream_get_family(rcc->stream) == AF_UNIX || > + !dcc_compress_image(dcc, &image, &simage->u.bitmap, > + drawable, can_lossy, &comp_send_data)) { > + SpicePalette *palette; > + > + red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE); > + > + *bitmap = simage->u.bitmap; > + bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN; > + > + palette = bitmap->palette; > + dcc_palette_cache_palette(dcc, palette, &bitmap->flags); > + spice_marshall_Image(m, &image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_assert(lzplt_palette_out == NULL); > + > + if (bitmap_palette_out && palette) { > + spice_marshall_Palette(bitmap_palette_out, palette); > + } > + > + spice_marshaller_add_ref_chunks(m, bitmap->data); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_BITMAP; > + } else { > + red_display_add_image_to_pixmap_cache(rcc, simage, &image, > + comp_send_data.is_lossy); > + > + spice_marshall_Image(m, &image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_assert(bitmap_palette_out == NULL); > + > + marshaller_add_compressed(m, comp_send_data.comp_buf, > + comp_send_data.comp_buf_size); > + > + if (lzplt_palette_out && comp_send_data.lzplt_palette) { > + spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette); > + } > + > + spice_assert(!comp_send_data.is_lossy || can_lossy); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return (comp_send_data.is_lossy ? FILL_BITS_TYPE_COMPRESS_LOSSY : > + FILL_BITS_TYPE_COMPRESS_LOSSLESS); > + } > + break; > + } > + case SPICE_IMAGE_TYPE_QUIC: > + red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE); > + image.u.quic = simage->u.quic; > + spice_marshall_Image(m, &image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_assert(bitmap_palette_out == NULL); > + spice_assert(lzplt_palette_out == NULL); > + spice_marshaller_add_ref_chunks(m, image.u.quic.data); > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_COMPRESS_LOSSLESS; > + default: > + spice_error("invalid image type %u", image.descriptor.type); > + } > + pthread_mutex_unlock(&dcc->pixmap_cache->lock); > + return FILL_BITS_TYPE_INVALID; > +} > + > +static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m, > + SpiceImage *mask_bitmap, Drawable *drawable) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + > + if (mask_bitmap && m) { > + if (dcc->image_compression != SPICE_IMAGE_COMPRESSION_OFF) { > + /* todo: pass compression argument */ > + SpiceImageCompression save_img_comp = dcc->image_compression; > + dcc->image_compression = SPICE_IMAGE_COMPRESSION_OFF; > + fill_bits(dcc, m, mask_bitmap, drawable, FALSE); > + dcc->image_compression = save_img_comp; > + } else { > + fill_bits(dcc, m, mask_bitmap, drawable, FALSE); > + } > + } > +} > + > +static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id) > +{ > + int i; > + > + if (m && attr->style_nseg) { > + for (i = 0 ; i < attr->style_nseg; i++) { > + spice_marshaller_add_uint32(m, attr->style[i]); > + } > + } > +} > + > +static void marshall_qxl_draw_fill(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMarshaller *brush_pat_out; > + SpiceMarshaller *mask_bitmap_out; > + SpiceFill fill; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + fill = drawable->u.fill; > + spice_marshall_Fill(base_marshaller, > + &fill, > + &brush_pat_out, > + &mask_bitmap_out); > + > + if (brush_pat_out) { > + fill_bits(dcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE); > + } > + > + fill_mask(rcc, mask_bitmap_out, fill.mask.bitmap, item); > +} > + > +/* returns if the bitmap was already sent lossy to the client. If the bitmap hasn't been sent yet > + to the client, returns false. "area" is for surfaces. If area = NULL, > + all the surface is considered. out_lossy_data will hold info about the bitmap, and its lossy > + area in case it is lossy and part of a surface. */ > +static void surface_lossy_region_update(DisplayChannelClient *dcc, > + Drawable *item, int has_mask, int lossy) > +{ > + QRegion *surface_lossy_region; > + RedDrawable *drawable; > + > + if (has_mask && !lossy) { > + return; > + } > + > + surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id]; > + drawable = item->red_drawable; > + > + if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS ) { > + QRegion clip_rgn; > + QRegion draw_region; > + region_init(&clip_rgn); > + region_init(&draw_region); > + region_add(&draw_region, &drawable->bbox); > + region_add_clip_rects(&clip_rgn, drawable->clip.rects); > + region_and(&draw_region, &clip_rgn); > + if (lossy) { > + region_or(surface_lossy_region, &draw_region); > + } else { > + region_exclude(surface_lossy_region, &draw_region); > + } > + > + region_destroy(&clip_rgn); > + region_destroy(&draw_region); > + } else { /* no clip */ > + if (!lossy) { > + region_remove(surface_lossy_region, &drawable->bbox); > + } else { > + region_add(surface_lossy_region, &drawable->bbox); > + } > + } > +} > + > +static int drawable_intersects_with_areas(Drawable *drawable, int surface_ids[], > + SpiceRect *surface_areas[], > + int num_surfaces) > +{ > + int i; > + for (i = 0; i < num_surfaces; i++) { > + if (surface_ids[i] == drawable->red_drawable->surface_id) { > + if (rect_intersects(surface_areas[i], &drawable->red_drawable->bbox)) { > + return TRUE; > + } > + } > + } > + return FALSE; > +} > + > +static int pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *dcc, > + int surface_ids[], > + SpiceRect *surface_areas[], > + int num_surfaces) > +{ > + PipeItem *pipe_item; > + Ring *pipe; > + > + spice_assert(num_surfaces); > + pipe = &RED_CHANNEL_CLIENT(dcc)->pipe; > + > + for (pipe_item = (PipeItem *)ring_get_head(pipe); > + pipe_item; > + pipe_item = (PipeItem *)ring_next(pipe, &pipe_item->link)) > + { > + Drawable *drawable; > + > + if (pipe_item->type != PIPE_ITEM_TYPE_DRAW) > + continue; > + drawable = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item)->drawable; > + > + if (ring_item_is_linked(&drawable->list_link)) > + continue; // item hasn't been rendered > + > + if (drawable_intersects_with_areas(drawable, surface_ids, surface_areas, num_surfaces)) { > + return TRUE; > + } > + } > + > + return FALSE; > +} > + > +static int drawable_depends_on_areas(Drawable *drawable, int surface_ids[], > + SpiceRect surface_areas[], int num_surfaces) > +{ > + int i; > + RedDrawable *red_drawable; > + int drawable_has_shadow; > + SpiceRect shadow_rect = {0, 0, 0, 0}; > + > + red_drawable = drawable->red_drawable; > + drawable_has_shadow = has_shadow(red_drawable); > + > + if (drawable_has_shadow) { > + int delta_x = red_drawable->u.copy_bits.src_pos.x - red_drawable->bbox.left; > + int delta_y = red_drawable->u.copy_bits.src_pos.y - red_drawable->bbox.top; > + > + shadow_rect.left = red_drawable->u.copy_bits.src_pos.x; > + shadow_rect.top = red_drawable->u.copy_bits.src_pos.y; > + shadow_rect.right = red_drawable->bbox.right + delta_x; > + shadow_rect.bottom = red_drawable->bbox.bottom + delta_y; > + } > + > + for (i = 0; i < num_surfaces; i++) { > + int x; > + int dep_surface_id; > + > + for (x = 0; x < 3; ++x) { > + dep_surface_id = drawable->surface_deps[x]; > + if (dep_surface_id == surface_ids[i]) { > + if (rect_intersects(&surface_areas[i], &red_drawable->surfaces_rects[x])) { > + return TRUE; > + } > + } > + } > + > + if (surface_ids[i] == red_drawable->surface_id) { > + if (drawable_has_shadow) { > + if (rect_intersects(&surface_areas[i], &shadow_rect)) { > + return TRUE; > + } > + } > + > + // not dependent on dest > + if (red_drawable->effect == QXL_EFFECT_OPAQUE) { > + continue; > + } > + > + if (rect_intersects(&surface_areas[i], &red_drawable->bbox)) { > + return TRUE; > + } > + } > + > + } > + return FALSE; > +} > + > +static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient *dcc, > + int first_surface_id, > + SpiceRect *first_area) > +{ > + /* TODO: can't have those statics with multiple clients */ > + static int resent_surface_ids[MAX_PIPE_SIZE]; > + static SpiceRect resent_areas[MAX_PIPE_SIZE]; // not pointers since drawbales may be released > + int num_resent; > + PipeItem *pipe_item; > + Ring *pipe; > + > + resent_surface_ids[0] = first_surface_id; > + resent_areas[0] = *first_area; > + num_resent = 1; > + > + pipe = &RED_CHANNEL_CLIENT(dcc)->pipe; > + > + // going from the oldest to the newest > + for (pipe_item = (PipeItem *)ring_get_tail(pipe); > + pipe_item; > + pipe_item = (PipeItem *)ring_prev(pipe, &pipe_item->link)) { > + Drawable *drawable; > + DrawablePipeItem *dpi; > + ImageItem *image; > + > + if (pipe_item->type != PIPE_ITEM_TYPE_DRAW) > + continue; > + dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item); > + drawable = dpi->drawable; > + if (ring_item_is_linked(&drawable->list_link)) > + continue; // item hasn't been rendered > + > + // When a drawable command, X, depends on bitmaps that were resent, > + // these bitmaps state at the client might not be synchronized with X > + // (i.e., the bitmaps can be more futuristic w.r.t X). Thus, X shouldn't > + // be rendered at the client, and we replace it with an image as well. > + if (!drawable_depends_on_areas(drawable, > + resent_surface_ids, > + resent_areas, > + num_resent)) { > + continue; > + } > + > + image = dcc_add_surface_area_image(dcc, drawable->red_drawable->surface_id, > + &drawable->red_drawable->bbox, pipe_item, TRUE); > + resent_surface_ids[num_resent] = drawable->red_drawable->surface_id; > + resent_areas[num_resent] = drawable->red_drawable->bbox; > + num_resent++; > + > + spice_assert(image); > + red_channel_client_pipe_remove_and_release(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item); > + pipe_item = &image->link; > + } > +} > + > +static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc, > + Drawable *item, > + int deps_surfaces_ids[], > + SpiceRect *deps_areas[], > + int num_deps) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + DisplayChannel *display = DCC_TO_DC(dcc); > + RedDrawable *drawable = item->red_drawable; > + int sync_rendered = FALSE; > + int i; > + > + if (!ring_item_is_linked(&item->list_link)) { > + /* drawable was already rendered, we may not be able to retrieve the lossless data > + for the lossy areas */ > + sync_rendered = TRUE; > + > + // checking if the drawable itself or one of the other commands > + // that were rendered, affected the areas that need to be resent > + if (!drawable_intersects_with_areas(item, deps_surfaces_ids, > + deps_areas, num_deps)) { > + if (pipe_rendered_drawables_intersect_with_areas(dcc, > + deps_surfaces_ids, > + deps_areas, > + num_deps)) { > + sync_rendered = TRUE; > + } > + } else { > + sync_rendered = TRUE; > + } > + } else { > + sync_rendered = FALSE; > + for (i = 0; i < num_deps; i++) { > + display_channel_draw_until(display, deps_areas[i], deps_surfaces_ids[i], item); > + } > + } > + > + if (!sync_rendered) { > + // pushing the pipe item back to the pipe > + dcc_append_drawable(dcc, item); > + // the surfaces areas will be sent as DRAW_COPY commands, that > + // will be executed before the current drawable > + for (i = 0; i < num_deps; i++) { > + dcc_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i], > + dcc_get_tail(dcc), FALSE); > + > + } > + } else { > + int drawable_surface_id[1]; > + SpiceRect *drawable_bbox[1]; > + > + drawable_surface_id[0] = drawable->surface_id; > + drawable_bbox[0] = &drawable->bbox; > + > + // check if the other rendered images in the pipe have updated the drawable bbox > + if (pipe_rendered_drawables_intersect_with_areas(dcc, > + drawable_surface_id, > + drawable_bbox, > + 1)) { > + red_pipe_replace_rendered_drawables_with_images(dcc, > + drawable->surface_id, > + &drawable->bbox); > + } > + > + dcc_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox, > + dcc_get_tail(dcc), TRUE); > + } > +} > + > +static void red_lossy_marshall_qxl_draw_fill(RedChannelClient *rcc, > + SpiceMarshaller *m, > + DrawablePipeItem *dpi) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + > + int dest_allowed_lossy = FALSE; > + int dest_is_lossy = FALSE; > + SpiceRect dest_lossy_area; > + int brush_is_lossy; > + BitmapData brush_bitmap_data; > + uint16_t rop; > + > + rop = drawable->u.fill.rop_descriptor; > + > + dest_allowed_lossy = !((rop & SPICE_ROPD_OP_OR) || > + (rop & SPICE_ROPD_OP_AND) || > + (rop & SPICE_ROPD_OP_XOR)); > + > + brush_is_lossy = is_brush_lossy(rcc, &drawable->u.fill.brush, item, > + &brush_bitmap_data); > + if (!dest_allowed_lossy) { > + dest_is_lossy = is_surface_area_lossy(dcc, item->surface_id, &drawable->bbox, > + &dest_lossy_area); > + } > + > + if (!dest_is_lossy && > + !(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) { > + int has_mask = !!drawable->u.fill.mask.bitmap; > + > + marshall_qxl_draw_fill(rcc, m, dpi); > + // either the brush operation is opaque, or the dest is not lossy > + surface_lossy_region_update(dcc, item, has_mask, FALSE); > + } else { > + int resend_surface_ids[2]; > + SpiceRect *resend_areas[2]; > + int num_resend = 0; > + > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = item->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + > + if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = brush_bitmap_data.id; > + resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static FillBitsType red_marshall_qxl_draw_opaque(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi, int src_allowed_lossy) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *brush_pat_out; > + SpiceMarshaller *src_bitmap_out; > + SpiceMarshaller *mask_bitmap_out; > + SpiceOpaque opaque; > + FillBitsType src_send_type; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + opaque = drawable->u.opaque; > + spice_marshall_Opaque(base_marshaller, > + &opaque, > + &src_bitmap_out, > + &brush_pat_out, > + &mask_bitmap_out); > + > + src_send_type = fill_bits(dcc, src_bitmap_out, opaque.src_bitmap, item, > + src_allowed_lossy); > + > + if (brush_pat_out) { > + fill_bits(dcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE); > + } > + fill_mask(rcc, mask_bitmap_out, opaque.mask.bitmap, item); > + > + return src_send_type; > +} > + > +static void red_lossy_marshall_qxl_draw_opaque(RedChannelClient *rcc, > + SpiceMarshaller *m, > + DrawablePipeItem *dpi) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + > + int src_allowed_lossy; > + int rop; > + int src_is_lossy = FALSE; > + int brush_is_lossy = FALSE; > + BitmapData src_bitmap_data; > + BitmapData brush_bitmap_data; > + > + rop = drawable->u.opaque.rop_descriptor; > + src_allowed_lossy = !((rop & SPICE_ROPD_OP_OR) || > + (rop & SPICE_ROPD_OP_AND) || > + (rop & SPICE_ROPD_OP_XOR)); > + > + brush_is_lossy = is_brush_lossy(rcc, &drawable->u.opaque.brush, item, > + &brush_bitmap_data); > + > + if (!src_allowed_lossy) { > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.opaque.src_bitmap, > + &drawable->u.opaque.src_area, > + item, > + &src_bitmap_data); > + } > + > + if (!(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) && > + !(src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) { > + FillBitsType src_send_type; > + int has_mask = !!drawable->u.opaque.mask.bitmap; > + > + src_send_type = red_marshall_qxl_draw_opaque(rcc, m, dpi, src_allowed_lossy); > + if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > + src_is_lossy = TRUE; > + } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > + src_is_lossy = FALSE; > + } > + > + surface_lossy_region_update(dcc, item, has_mask, src_is_lossy); > + } else { > + int resend_surface_ids[2]; > + SpiceRect *resend_areas[2]; > + int num_resend = 0; > + > + if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = src_bitmap_data.id; > + resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = brush_bitmap_data.id; > + resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static FillBitsType red_marshall_qxl_draw_copy(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi, int src_allowed_lossy) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *src_bitmap_out; > + SpiceMarshaller *mask_bitmap_out; > + SpiceCopy copy; > + FillBitsType src_send_type; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + copy = drawable->u.copy; > + spice_marshall_Copy(base_marshaller, > + ©, > + &src_bitmap_out, > + &mask_bitmap_out); > + > + src_send_type = fill_bits(dcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy); > + fill_mask(rcc, mask_bitmap_out, copy.mask.bitmap, item); > + > + return src_send_type; > +} > + > +static void red_lossy_marshall_qxl_draw_copy(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + int has_mask = !!drawable->u.copy.mask.bitmap; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + FillBitsType src_send_type; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.copy.src_bitmap, > + &drawable->u.copy.src_area, item, &src_bitmap_data); > + > + src_send_type = red_marshall_qxl_draw_copy(rcc, base_marshaller, dpi, TRUE); > + if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > + src_is_lossy = TRUE; > + } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > + src_is_lossy = FALSE; > + } > + surface_lossy_region_update(dcc, item, has_mask, > + src_is_lossy); > +} > + > +static void red_marshall_qxl_draw_transparent(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *src_bitmap_out; > + SpiceTransparent transparent; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, > + &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + transparent = drawable->u.transparent; > + spice_marshall_Transparent(base_marshaller, > + &transparent, > + &src_bitmap_out); > + fill_bits(dcc, src_bitmap_out, transparent.src_bitmap, item, FALSE); > +} > + > +static void red_lossy_marshall_qxl_draw_transparent(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.transparent.src_bitmap, > + &drawable->u.transparent.src_area, item, &src_bitmap_data); > + > + if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) { > + red_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi); > + // don't update surface lossy region since transperent areas might be lossy > + } else { > + int resend_surface_ids[1]; > + SpiceRect *resend_areas[1]; > + > + resend_surface_ids[0] = src_bitmap_data.id; > + resend_areas[0] = &src_bitmap_data.lossy_rect; > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, 1); > + } > +} > + > +static FillBitsType red_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi, > + int src_allowed_lossy) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *src_bitmap_out; > + SpiceAlphaBlend alpha_blend; > + FillBitsType src_send_type; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, > + &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + alpha_blend = drawable->u.alpha_blend; > + spice_marshall_AlphaBlend(base_marshaller, > + &alpha_blend, > + &src_bitmap_out); > + src_send_type = fill_bits(dcc, src_bitmap_out, alpha_blend.src_bitmap, item, > + src_allowed_lossy); > + > + return src_send_type; > +} > + > +static void red_lossy_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + FillBitsType src_send_type; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.alpha_blend.src_bitmap, > + &drawable->u.alpha_blend.src_area, item, &src_bitmap_data); > + > + src_send_type = red_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi, TRUE); > + > + if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > + src_is_lossy = TRUE; > + } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > + src_is_lossy = FALSE; > + } > + > + if (src_is_lossy) { > + surface_lossy_region_update(dcc, item, FALSE, src_is_lossy); > + } // else, the area stays lossy/lossless as the destination > +} > + > +static void red_marshall_qxl_copy_bits(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpicePoint copy_bits; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_COPY_BITS, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + copy_bits = drawable->u.copy_bits.src_pos; > + spice_marshall_Point(base_marshaller, > + ©_bits); > +} > + > +static void red_lossy_marshall_qxl_copy_bits(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceRect src_rect; > + int horz_offset; > + int vert_offset; > + int src_is_lossy; > + SpiceRect src_lossy_area; > + > + red_marshall_qxl_copy_bits(rcc, base_marshaller, dpi); > + > + horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left; > + vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top; > + > + src_rect.left = drawable->u.copy_bits.src_pos.x; > + src_rect.top = drawable->u.copy_bits.src_pos.y; > + src_rect.right = drawable->bbox.right + horz_offset; > + src_rect.bottom = drawable->bbox.bottom + vert_offset; > + > + src_is_lossy = is_surface_area_lossy(dcc, item->surface_id, > + &src_rect, &src_lossy_area); > + > + surface_lossy_region_update(dcc, item, FALSE, src_is_lossy); > +} > + > +static void red_marshall_qxl_draw_blend(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *src_bitmap_out; > + SpiceMarshaller *mask_bitmap_out; > + SpiceBlend blend; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLEND, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + blend = drawable->u.blend; > + spice_marshall_Blend(base_marshaller, > + &blend, > + &src_bitmap_out, > + &mask_bitmap_out); > + > + fill_bits(dcc, src_bitmap_out, blend.src_bitmap, item, FALSE); > + > + fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item); > +} > + > +static void red_lossy_marshall_qxl_draw_blend(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + int dest_is_lossy; > + SpiceRect dest_lossy_area; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.blend.src_bitmap, > + &drawable->u.blend.src_area, item, &src_bitmap_data); > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > + &drawable->bbox, &dest_lossy_area); > + > + if (!dest_is_lossy && > + (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) { > + red_marshall_qxl_draw_blend(rcc, base_marshaller, dpi); > + } else { > + int resend_surface_ids[2]; > + SpiceRect *resend_areas[2]; > + int num_resend = 0; > + > + if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = src_bitmap_data.id; > + resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = item->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static void red_marshall_qxl_draw_blackness(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *mask_bitmap_out; > + SpiceBlackness blackness; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + blackness = drawable->u.blackness; > + > + spice_marshall_Blackness(base_marshaller, > + &blackness, > + &mask_bitmap_out); > + > + fill_mask(rcc, mask_bitmap_out, blackness.mask.bitmap, item); > +} > + > +static void red_lossy_marshall_qxl_draw_blackness(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int has_mask = !!drawable->u.blackness.mask.bitmap; > + > + red_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi); > + > + surface_lossy_region_update(dcc, item, has_mask, FALSE); > +} > + > +static void red_marshall_qxl_draw_whiteness(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *mask_bitmap_out; > + SpiceWhiteness whiteness; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + whiteness = drawable->u.whiteness; > + > + spice_marshall_Whiteness(base_marshaller, > + &whiteness, > + &mask_bitmap_out); > + > + fill_mask(rcc, mask_bitmap_out, whiteness.mask.bitmap, item); > +} > + > +static void red_lossy_marshall_qxl_draw_whiteness(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int has_mask = !!drawable->u.whiteness.mask.bitmap; > + > + red_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi); > + > + surface_lossy_region_update(dcc, item, has_mask, FALSE); > +} > + > +static void red_marshall_qxl_draw_inverse(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + Drawable *item) > +{ > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *mask_bitmap_out; > + SpiceInvers inverse; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL); > + fill_base(base_marshaller, item); > + inverse = drawable->u.invers; > + > + spice_marshall_Invers(base_marshaller, > + &inverse, > + &mask_bitmap_out); > + > + fill_mask(rcc, mask_bitmap_out, inverse.mask.bitmap, item); > +} > + > +static void red_lossy_marshall_qxl_draw_inverse(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + Drawable *item) > +{ > + red_marshall_qxl_draw_inverse(rcc, base_marshaller, item); > +} > + > +static void red_marshall_qxl_draw_rop3(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceRop3 rop3; > + SpiceMarshaller *src_bitmap_out; > + SpiceMarshaller *brush_pat_out; > + SpiceMarshaller *mask_bitmap_out; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ROP3, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + rop3 = drawable->u.rop3; > + spice_marshall_Rop3(base_marshaller, > + &rop3, > + &src_bitmap_out, > + &brush_pat_out, > + &mask_bitmap_out); > + > + fill_bits(dcc, src_bitmap_out, rop3.src_bitmap, item, FALSE); > + > + if (brush_pat_out) { > + fill_bits(dcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE); > + } > + fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item); > +} > + > +static void red_lossy_marshall_qxl_draw_rop3(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + int brush_is_lossy; > + BitmapData brush_bitmap_data; > + int dest_is_lossy; > + SpiceRect dest_lossy_area; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.rop3.src_bitmap, > + &drawable->u.rop3.src_area, item, &src_bitmap_data); > + brush_is_lossy = is_brush_lossy(rcc, &drawable->u.rop3.brush, item, > + &brush_bitmap_data); > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > + &drawable->bbox, &dest_lossy_area); > + > + if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > + (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > + !dest_is_lossy) { > + int has_mask = !!drawable->u.rop3.mask.bitmap; > + red_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi); > + surface_lossy_region_update(dcc, item, has_mask, FALSE); > + } else { > + int resend_surface_ids[3]; > + SpiceRect *resend_areas[3]; > + int num_resend = 0; > + > + if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = src_bitmap_data.id; > + resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = brush_bitmap_data.id; > + resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = item->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static void red_marshall_qxl_draw_composite(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceMarshaller *src_bitmap_out; > + SpiceMarshaller *mask_bitmap_out; > + SpiceComposite composite; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COMPOSITE, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + composite = drawable->u.composite; > + spice_marshall_Composite(base_marshaller, > + &composite, > + &src_bitmap_out, > + &mask_bitmap_out); > + > + fill_bits(dcc, src_bitmap_out, composite.src_bitmap, item, FALSE); > + if (mask_bitmap_out) { > + fill_bits(dcc, mask_bitmap_out, composite.mask_bitmap, item, FALSE); > + } > +} > + > +static void red_lossy_marshall_qxl_draw_composite(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int src_is_lossy; > + BitmapData src_bitmap_data; > + int mask_is_lossy; > + BitmapData mask_bitmap_data; > + int dest_is_lossy; > + SpiceRect dest_lossy_area; > + > + src_is_lossy = is_bitmap_lossy(rcc, drawable->u.composite.src_bitmap, > + NULL, item, &src_bitmap_data); > + mask_is_lossy = drawable->u.composite.mask_bitmap && > + is_bitmap_lossy(rcc, drawable->u.composite.mask_bitmap, NULL, item, &mask_bitmap_data); > + > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > + &drawable->bbox, &dest_lossy_area); > + > + if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > + (!mask_is_lossy || (mask_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > + !dest_is_lossy) { > + red_marshall_qxl_draw_composite(rcc, base_marshaller, dpi); > + surface_lossy_region_update(dcc, item, FALSE, FALSE); > + } > + else { > + int resend_surface_ids[3]; > + SpiceRect *resend_areas[3]; > + int num_resend = 0; > + > + if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = src_bitmap_data.id; > + resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (mask_is_lossy && (mask_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = mask_bitmap_data.id; > + resend_areas[num_resend] = &mask_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = item->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static void red_marshall_qxl_draw_stroke(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceStroke stroke; > + SpiceMarshaller *brush_pat_out; > + SpiceMarshaller *style_out; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_STROKE, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + stroke = drawable->u.stroke; > + spice_marshall_Stroke(base_marshaller, > + &stroke, > + &style_out, > + &brush_pat_out); > + > + fill_attr(style_out, &stroke.attr, item->group_id); > + if (brush_pat_out) { > + fill_bits(dcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE); > + } > +} > + > +static void red_lossy_marshall_qxl_draw_stroke(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int brush_is_lossy; > + BitmapData brush_bitmap_data; > + int dest_is_lossy = FALSE; > + SpiceRect dest_lossy_area; > + int rop; > + > + brush_is_lossy = is_brush_lossy(rcc, &drawable->u.stroke.brush, item, > + &brush_bitmap_data); > + > + // back_mode is not used at the client. Ignoring. > + rop = drawable->u.stroke.fore_mode; > + > + // assuming that if the brush type is solid, the destination can > + // be lossy, no matter what the rop is. > + if (drawable->u.stroke.brush.type != SPICE_BRUSH_TYPE_SOLID && > + ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) || > + (rop & SPICE_ROPD_OP_XOR))) { > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > + &drawable->bbox, &dest_lossy_area); > + } > + > + if (!dest_is_lossy && > + (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) > + { > + red_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi); > + } else { > + int resend_surface_ids[2]; > + SpiceRect *resend_areas[2]; > + int num_resend = 0; > + > + if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = brush_bitmap_data.id; > + resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + // TODO: use the path in order to resend smaller areas > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = drawable->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static void red_marshall_qxl_draw_text(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + SpiceText text; > + SpiceMarshaller *brush_pat_out; > + SpiceMarshaller *back_brush_pat_out; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TEXT, &dpi->dpi_pipe_item); > + fill_base(base_marshaller, item); > + text = drawable->u.text; > + spice_marshall_Text(base_marshaller, > + &text, > + &brush_pat_out, > + &back_brush_pat_out); > + > + if (brush_pat_out) { > + fill_bits(dcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE); > + } > + if (back_brush_pat_out) { > + fill_bits(dcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE); > + } > +} > + > +static void red_lossy_marshall_qxl_draw_text(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *drawable = item->red_drawable; > + int fg_is_lossy; > + BitmapData fg_bitmap_data; > + int bg_is_lossy; > + BitmapData bg_bitmap_data; > + int dest_is_lossy = FALSE; > + SpiceRect dest_lossy_area; > + int rop = 0; > + > + fg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.fore_brush, item, > + &fg_bitmap_data); > + bg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.back_brush, item, > + &bg_bitmap_data); > + > + // assuming that if the brush type is solid, the destination can > + // be lossy, no matter what the rop is. > + if (drawable->u.text.fore_brush.type != SPICE_BRUSH_TYPE_SOLID) { > + rop = drawable->u.text.fore_mode; > + } > + > + if (drawable->u.text.back_brush.type != SPICE_BRUSH_TYPE_SOLID) { > + rop |= drawable->u.text.back_mode; > + } > + > + if ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) || > + (rop & SPICE_ROPD_OP_XOR)) { > + dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > + &drawable->bbox, &dest_lossy_area); > + } > + > + if (!dest_is_lossy && > + (!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > + (!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) { > + red_marshall_qxl_draw_text(rcc, base_marshaller, dpi); > + } else { > + int resend_surface_ids[3]; > + SpiceRect *resend_areas[3]; > + int num_resend = 0; > + > + if (fg_is_lossy && (fg_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = fg_bitmap_data.id; > + resend_areas[num_resend] = &fg_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (bg_is_lossy && (bg_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > + resend_surface_ids[num_resend] = bg_bitmap_data.id; > + resend_areas[num_resend] = &bg_bitmap_data.lossy_rect; > + num_resend++; > + } > + > + if (dest_is_lossy) { > + resend_surface_ids[num_resend] = drawable->surface_id; > + resend_areas[num_resend] = &dest_lossy_area; > + num_resend++; > + } > + red_add_lossless_drawable_dependencies(rcc, item, > + resend_surface_ids, resend_areas, num_resend); > + } > +} > + > +static inline int red_marshall_stream_data(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, Drawable *drawable) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + DisplayChannel *display = DCC_TO_DC(dcc); > + Stream *stream = drawable->stream; > + SpiceImage *image; > + uint32_t frame_mm_time; > + int n; > + int width, height; > + int ret; > + > + if (!stream) { > + spice_assert(drawable->sized_stream); > + stream = drawable->sized_stream; > + } > + spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY); > + > + image = drawable->red_drawable->u.copy.src_bitmap; > + > + if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) { > + return FALSE; > + } > + > + if (drawable->sized_stream) { > + if (red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_SIZED_STREAM)) { > + SpiceRect *src_rect = &drawable->red_drawable->u.copy.src_area; > + > + width = src_rect->right - src_rect->left; > + height = src_rect->bottom - src_rect->top; > + } else { > + return FALSE; > + } > + } else { > + width = stream->width; > + height = stream->height; > + } > + > + StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)]; > + uint64_t time_now = red_get_monotonic_time(); > + size_t outbuf_size; > + > + if (!dcc->use_mjpeg_encoder_rate_control) { > + if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { > + agent->frames--; > +#ifdef STREAM_STATS > + agent->stats.num_drops_fps++; > +#endif > + return TRUE; > + } > + } > + > + /* workaround for vga streams */ > + frame_mm_time = drawable->red_drawable->mm_time ? > + drawable->red_drawable->mm_time : > + reds_get_mm_time(); > + outbuf_size = dcc->send_data.stream_outbuf_size; > + ret = mjpeg_encoder_encode_frame(agent->mjpeg_encoder, > + &image->u.bitmap, width, height, > + &drawable->red_drawable->u.copy.src_area, > + stream->top_down, frame_mm_time, > + &dcc->send_data.stream_outbuf, > + &outbuf_size, &n); > + switch (ret) { > + case MJPEG_ENCODER_FRAME_DROP: > + spice_assert(dcc->use_mjpeg_encoder_rate_control); > +#ifdef STREAM_STATS > + agent->stats.num_drops_fps++; > +#endif > + return TRUE; > + case MJPEG_ENCODER_FRAME_UNSUPPORTED: > + return FALSE; > + case MJPEG_ENCODER_FRAME_ENCODE_DONE: > + break; > + default: > + spice_error("bad return value (%d) from mjpeg_encoder_encode_frame", ret); > + return FALSE; > + } > + dcc->send_data.stream_outbuf_size = outbuf_size; > + > + if (!drawable->sized_stream) { > + SpiceMsgDisplayStreamData stream_data; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL); > + > + stream_data.base.id = get_stream_id(display, stream); > + stream_data.base.multi_media_time = frame_mm_time; > + stream_data.data_size = n; > + > + spice_marshall_msg_display_stream_data(base_marshaller, &stream_data); > + } else { > + SpiceMsgDisplayStreamDataSized stream_data; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL); > + > + stream_data.base.id = get_stream_id(display, stream); > + stream_data.base.multi_media_time = frame_mm_time; > + stream_data.data_size = n; > + stream_data.width = width; > + stream_data.height = height; > + stream_data.dest = drawable->red_drawable->bbox; > + > + spice_debug("stream %d: sized frame: dest ==> ", stream_data.base.id); > + rect_debug(&stream_data.dest); > + spice_marshall_msg_display_stream_data_sized(base_marshaller, &stream_data); > + } > + spice_marshaller_add_ref(base_marshaller, > + dcc->send_data.stream_outbuf, n); > + agent->last_send_time = time_now; > +#ifdef STREAM_STATS > + agent->stats.num_frames_sent++; > + agent->stats.size_sent += n; > + agent->stats.end = frame_mm_time; > +#endif > + > + return TRUE; > +} > + > +static inline void marshall_inval_palette(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + CacheItem *cache_item) > +{ > + SpiceMsgDisplayInvalOne inval_one; > + > + red_channel_client_init_send_data(rcc, cache_item->inval_type, NULL); > + inval_one.id = *(uint64_t *)&cache_item->id; > + > + spice_marshall_msg_display_inval_palette(base_marshaller, &inval_one); > + > +} > + > +static void display_channel_marshall_migrate_data_surfaces(DisplayChannelClient *dcc, > + SpiceMarshaller *m, > + int lossy) > +{ > + SpiceMarshaller *m2 = spice_marshaller_get_ptr_submarshaller(m, 0); > + uint32_t *num_surfaces_created; > + uint32_t i; > + > + num_surfaces_created = (uint32_t *)spice_marshaller_reserve_space(m2, sizeof(uint32_t)); > + *num_surfaces_created = 0; > + for (i = 0; i < NUM_SURFACES; i++) { > + SpiceRect lossy_rect; > + > + if (!dcc->surface_client_created[i]) { > + continue; > + } > + spice_marshaller_add_uint32(m2, i); > + (*num_surfaces_created)++; > + > + if (!lossy) { > + continue; > + } > + region_extents(&dcc->surface_client_lossy_region[i], &lossy_rect); > + spice_marshaller_add_int32(m2, lossy_rect.left); > + spice_marshaller_add_int32(m2, lossy_rect.top); > + spice_marshaller_add_int32(m2, lossy_rect.right); > + spice_marshaller_add_int32(m2, lossy_rect.bottom); > + } > +} > + > +static void display_channel_marshall_migrate_data(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller) > +{ > + DisplayChannel *display_channel; > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMigrateDataDisplay display_data = {0,}; > + > + display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL); > + spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC); > + spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_VERSION); > + > + spice_assert(dcc->pixmap_cache); > + spice_assert(MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == 4 && > + MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == MAX_CACHE_CLIENTS); > + > + display_data.message_serial = red_channel_client_get_message_serial(rcc); > + display_data.low_bandwidth_setting = dcc->common.is_low_bandwidth; > + > + display_data.pixmap_cache_freezer = pixmap_cache_freeze(dcc->pixmap_cache); > + display_data.pixmap_cache_id = dcc->pixmap_cache->id; > + display_data.pixmap_cache_size = dcc->pixmap_cache->size; > + memcpy(display_data.pixmap_cache_clients, dcc->pixmap_cache->sync, > + sizeof(display_data.pixmap_cache_clients)); > + > + spice_assert(dcc->glz_dict); > + dcc_freeze_glz(dcc); > + display_data.glz_dict_id = dcc->glz_dict->id; > + glz_enc_dictionary_get_restore_data(dcc->glz_dict->dict, > + &display_data.glz_dict_data, > + &dcc->glz_data.usr); > + > + /* all data besided the surfaces ref */ > + spice_marshaller_add(base_marshaller, > + (uint8_t *)&display_data, sizeof(display_data) - sizeof(uint32_t)); > + display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller, > + display_channel->enable_jpeg); > +} > + > +static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMsgWaitForChannels wait; > + PixmapCache *pixmap_cache; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_WAIT_FOR_CHANNELS, NULL); > + pixmap_cache = dcc->pixmap_cache; > + > + pthread_mutex_lock(&pixmap_cache->lock); > + > + wait.wait_count = 1; > + wait.wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY; > + wait.wait_list[0].channel_id = pixmap_cache->generation_initiator.client; > + wait.wait_list[0].message_serial = pixmap_cache->generation_initiator.message; > + dcc->pixmap_cache_generation = pixmap_cache->generation; > + dcc->pending_pixmaps_sync = FALSE; > + > + pthread_mutex_unlock(&pixmap_cache->lock); > + > + spice_marshall_msg_wait_for_channels(base_marshaller, &wait); > +} > + > +static void dcc_pixmap_cache_reset(DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data) > +{ > + PixmapCache *cache = dcc->pixmap_cache; > + uint8_t wait_count; > + uint64_t serial; > + uint32_t i; > + > + serial = red_channel_client_get_message_serial(RED_CHANNEL_CLIENT(dcc)); > + pthread_mutex_lock(&cache->lock); > + pixmap_cache_clear(cache); > + > + dcc->pixmap_cache_generation = ++cache->generation; > + cache->generation_initiator.client = dcc->common.id; > + cache->generation_initiator.message = serial; > + cache->sync[dcc->common.id] = serial; > + > + wait_count = 0; > + for (i = 0; i < MAX_CACHE_CLIENTS; i++) { > + if (cache->sync[i] && i != dcc->common.id) { > + sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY; > + sync_data->wait_list[wait_count].channel_id = i; > + sync_data->wait_list[wait_count++].message_serial = cache->sync[i]; > + } > + } > + sync_data->wait_count = wait_count; > + pthread_mutex_unlock(&cache->lock); > +} > + > +static void display_channel_marshall_reset_cache(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMsgWaitForChannels wait; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL); > + dcc_pixmap_cache_reset(dcc, &wait); > + > + spice_marshall_msg_display_inval_all_pixmaps(base_marshaller, > + &wait); > +} > + > +static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + DisplayChannel *display = DCC_TO_DC(dcc); > + SpiceImage red_image; > + RedWorker *worker; > + SpiceBitmap bitmap; > + SpiceChunks *chunks; > + QRegion *surface_lossy_region; > + int comp_succeeded = FALSE; > + int lossy_comp = FALSE; > + int quic_comp = FALSE; > + SpiceImageCompression comp_mode; > + SpiceMsgDisplayDrawCopy copy; > + SpiceMarshaller *src_bitmap_out, *mask_bitmap_out; > + SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out; > + > + spice_assert(rcc && display && item); > + worker = display->common.worker; > + > + QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, generate_uid(display)); > + red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP; > + red_image.descriptor.flags = item->image_flags; > + red_image.descriptor.width = item->width; > + red_image.descriptor.height = item->height; > + > + bitmap.format = item->image_format; > + bitmap.flags = 0; > + if (item->top_down) { > + bitmap.flags |= SPICE_BITMAP_FLAGS_TOP_DOWN; > + } > + bitmap.x = item->width; > + bitmap.y = item->height; > + bitmap.stride = item->stride; > + bitmap.palette = 0; > + bitmap.palette_id = 0; > + > + chunks = spice_chunks_new_linear(item->data, bitmap.stride * bitmap.y); > + bitmap.data = chunks; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->link); > + > + copy.base.surface_id = item->surface_id; > + copy.base.box.left = item->pos.x; > + copy.base.box.top = item->pos.y; > + copy.base.box.right = item->pos.x + bitmap.x; > + copy.base.box.bottom = item->pos.y + bitmap.y; > + copy.base.clip.type = SPICE_CLIP_TYPE_NONE; > + copy.data.rop_descriptor = SPICE_ROPD_OP_PUT; > + copy.data.src_area.left = 0; > + copy.data.src_area.top = 0; > + copy.data.src_area.right = bitmap.x; > + copy.data.src_area.bottom = bitmap.y; > + copy.data.scale_mode = 0; > + copy.data.src_bitmap = 0; > + copy.data.mask.flags = 0; > + copy.data.mask.flags = 0; > + copy.data.mask.pos.x = 0; > + copy.data.mask.pos.y = 0; > + copy.data.mask.bitmap = 0; > + > + spice_marshall_msg_display_draw_copy(m, ©, > + &src_bitmap_out, &mask_bitmap_out); > + > + compress_send_data_t comp_send_data = {0}; > + > + comp_mode = dcc->image_compression; > + > + if (((comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_LZ) || > + (comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) && !bitmap_has_extra_stride(&bitmap)) { > + > + if (bitmap_fmt_has_graduality(item->image_format)) { > + BitmapGradualType grad_level; > + > + grad_level = bitmap_get_graduality_level(&bitmap); > + if (grad_level == BITMAP_GRADUAL_HIGH) { > + // if we use lz for alpha, the stride can't be extra > + lossy_comp = display->enable_jpeg && item->can_lossy; > + quic_comp = TRUE; > + } > + } > + } else if (comp_mode == SPICE_IMAGE_COMPRESSION_QUIC) { > + quic_comp = TRUE; > + } > + > + uint32_t groupid = red_worker_get_memslot(worker)->internal_groupslot_id; > + > + if (lossy_comp) { > + comp_succeeded = dcc_compress_image_jpeg(dcc, &red_image, &bitmap, &comp_send_data, groupid); > + } else if (quic_comp) { > + comp_succeeded = dcc_compress_image_quic(dcc, &red_image, &bitmap, &comp_send_data, groupid); > +#ifdef USE_LZ4 > + } else if (comp_mode == SPICE_IMAGE_COMPRESSION_LZ4 && > + bitmap_fmt_is_rgb(bitmap.format) && > + red_channel_client_test_remote_cap(&dcc->common.base, > + SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) { > + comp_succeeded = dcc_compress_image_lz4(dcc, &red_image, &bitmap, > + &comp_send_data, > + groupid); > +#endif > + } else if (comp_mode != SPICE_IMAGE_COMPRESSION_OFF) { > + comp_succeeded = dcc_compress_image_lz(dcc, &red_image, &bitmap, > + &comp_send_data, > + groupid); > + } > + > + surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id]; > + if (comp_succeeded) { > + spice_marshall_Image(src_bitmap_out, &red_image, > + &bitmap_palette_out, &lzplt_palette_out); > + > + marshaller_add_compressed(src_bitmap_out, > + comp_send_data.comp_buf, comp_send_data.comp_buf_size); > + > + if (lzplt_palette_out && comp_send_data.lzplt_palette) { > + spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette); > + } > + > + if (lossy_comp) { > + region_add(surface_lossy_region, ©.base.box); > + } else { > + region_remove(surface_lossy_region, ©.base.box); > + } > + } else { > + red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP; > + red_image.u.bitmap = bitmap; > + > + spice_marshall_Image(src_bitmap_out, &red_image, > + &bitmap_palette_out, &lzplt_palette_out); > + spice_marshaller_add_ref(src_bitmap_out, item->data, > + bitmap.y * bitmap.stride); > + region_remove(surface_lossy_region, ©.base.box); > + } > + spice_chunks_destroy(chunks); > +} > + > +static void marshall_lossy_qxl_drawable(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + switch (item->red_drawable->type) { > + case QXL_DRAW_FILL: > + red_lossy_marshall_qxl_draw_fill(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_OPAQUE: > + red_lossy_marshall_qxl_draw_opaque(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_COPY: > + red_lossy_marshall_qxl_draw_copy(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_TRANSPARENT: > + red_lossy_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_ALPHA_BLEND: > + red_lossy_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi); > + break; > + case QXL_COPY_BITS: > + red_lossy_marshall_qxl_copy_bits(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_BLEND: > + red_lossy_marshall_qxl_draw_blend(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_BLACKNESS: > + red_lossy_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_WHITENESS: > + red_lossy_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_INVERS: > + red_lossy_marshall_qxl_draw_inverse(rcc, base_marshaller, item); > + break; > + case QXL_DRAW_ROP3: > + red_lossy_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_COMPOSITE: > + red_lossy_marshall_qxl_draw_composite(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_STROKE: > + red_lossy_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi); > + break; > + case QXL_DRAW_TEXT: > + red_lossy_marshall_qxl_draw_text(rcc, base_marshaller, dpi); > + break; > + default: > + spice_warn_if_reached(); > + } > +} > + > +static void marshall_lossless_qxl_drawable(RedChannelClient *rcc, > + SpiceMarshaller *m, DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + RedDrawable *drawable = item->red_drawable; > + > + switch (drawable->type) { > + case QXL_DRAW_FILL: > + marshall_qxl_draw_fill(rcc, m, dpi); > + break; > + case QXL_DRAW_OPAQUE: > + red_marshall_qxl_draw_opaque(rcc, m, dpi, FALSE); > + break; > + case QXL_DRAW_COPY: > + red_marshall_qxl_draw_copy(rcc, m, dpi, FALSE); > + break; > + case QXL_DRAW_TRANSPARENT: > + red_marshall_qxl_draw_transparent(rcc, m, dpi); > + break; > + case QXL_DRAW_ALPHA_BLEND: > + red_marshall_qxl_draw_alpha_blend(rcc, m, dpi, FALSE); > + break; > + case QXL_COPY_BITS: > + red_marshall_qxl_copy_bits(rcc, m, dpi); > + break; > + case QXL_DRAW_BLEND: > + red_marshall_qxl_draw_blend(rcc, m, dpi); > + break; > + case QXL_DRAW_BLACKNESS: > + red_marshall_qxl_draw_blackness(rcc, m, dpi); > + break; > + case QXL_DRAW_WHITENESS: > + red_marshall_qxl_draw_whiteness(rcc, m, dpi); > + break; > + case QXL_DRAW_INVERS: > + red_marshall_qxl_draw_inverse(rcc, m, item); > + break; > + case QXL_DRAW_ROP3: > + red_marshall_qxl_draw_rop3(rcc, m, dpi); > + break; > + case QXL_DRAW_STROKE: > + red_marshall_qxl_draw_stroke(rcc, m, dpi); > + break; > + case QXL_DRAW_COMPOSITE: > + red_marshall_qxl_draw_composite(rcc, m, dpi); > + break; > + case QXL_DRAW_TEXT: > + red_marshall_qxl_draw_text(rcc, m, dpi); > + break; > + default: > + spice_warn_if_reached(); > + } > +} > + > +static void marshall_qxl_drawable(RedChannelClient *rcc, > + SpiceMarshaller *m, DrawablePipeItem *dpi) > +{ > + Drawable *item = dpi->drawable; > + DisplayChannel *display = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > + > + spice_return_if_fail(display); > + spice_return_if_fail(rcc); > + /* allow sized frames to be streamed, even if they where replaced by another frame, since > + * newer frames might not cover sized frames completely if they are bigger */ > + if ((item->stream || item->sized_stream) && red_marshall_stream_data(rcc, m, item)) { > + return; > + } > + if (display->enable_jpeg) > + marshall_lossy_qxl_drawable(rcc, m, dpi); > + else > + marshall_lossless_qxl_drawable(rcc, m, dpi); > +} > + > +static void marshall_stream_start(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, StreamAgent *agent) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + Stream *stream = agent->stream; > + > + agent->last_send_time = 0; > + spice_assert(stream); > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE, NULL); > + SpiceMsgDisplayStreamCreate stream_create; > + SpiceClipRects clip_rects; > + > + stream_create.surface_id = 0; > + stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream); > + stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0; > + stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG; > + > + stream_create.src_width = stream->width; > + stream_create.src_height = stream->height; > + stream_create.stream_width = stream_create.src_width; > + stream_create.stream_height = stream_create.src_height; > + stream_create.dest = stream->dest_area; > + > + if (stream->current) { > + RedDrawable *red_drawable = stream->current->red_drawable; > + stream_create.clip = red_drawable->clip; > + } else { > + stream_create.clip.type = SPICE_CLIP_TYPE_RECTS; > + clip_rects.num_rects = 0; > + stream_create.clip.rects = &clip_rects; > + } > + > + stream_create.stamp = 0; > + > + spice_marshall_msg_display_stream_create(base_marshaller, &stream_create); > +} > + > +static void marshall_stream_clip(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + StreamClipItem *item) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + StreamAgent *agent = item->stream_agent; > + > + spice_return_if_fail(agent->stream); > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base); > + SpiceMsgDisplayStreamClip stream_clip; > + > + stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > + stream_clip.clip.type = item->clip_type; > + stream_clip.clip.rects = item->rects; > + > + spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip); > +} > + > +static void marshall_stream_end(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, StreamAgent* agent) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMsgDisplayStreamDestroy destroy; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL); > + destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > + stream_agent_stop(agent); > + spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy); > +} > + > +static void marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller *m, > + UpgradeItem *item) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + RedDrawable *red_drawable; > + SpiceMsgDisplayDrawCopy copy; > + SpiceMarshaller *src_bitmap_out, *mask_bitmap_out; > + > + spice_assert(rcc && rcc->channel && item && item->drawable); > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->base); > + > + red_drawable = item->drawable->red_drawable; > + spice_assert(red_drawable->type == QXL_DRAW_COPY); > + spice_assert(red_drawable->u.copy.rop_descriptor == SPICE_ROPD_OP_PUT); > + spice_assert(red_drawable->u.copy.mask.bitmap == 0); > + > + copy.base.surface_id = 0; > + copy.base.box = red_drawable->bbox; > + copy.base.clip.type = SPICE_CLIP_TYPE_RECTS; > + copy.base.clip.rects = item->rects; > + copy.data = red_drawable->u.copy; > + > + spice_marshall_msg_display_draw_copy(m, ©, > + &src_bitmap_out, &mask_bitmap_out); > + > + fill_bits(dcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE); > +} > + > +static void marshall_surface_create(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + SpiceMsgSurfaceCreate *surface_create) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + > + region_init(&dcc->surface_client_lossy_region[surface_create->surface_id]); > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL); > + > + spice_marshall_msg_display_surface_create(base_marshaller, surface_create); > +} > + > +static void marshall_surface_destroy(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, uint32_t surface_id) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + SpiceMsgSurfaceDestroy surface_destroy; > + > + region_destroy(&dcc->surface_client_lossy_region[surface_id]); > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL); > + > + surface_destroy.surface_id = surface_id; > + > + spice_marshall_msg_display_surface_destroy(base_marshaller, &surface_destroy); > +} > + > +static void marshall_monitors_config(RedChannelClient *rcc, SpiceMarshaller *base_marshaller, > + MonitorsConfig *monitors_config) > +{ > + int heads_size = sizeof(SpiceHead) * monitors_config->count; > + int i; > + SpiceMsgDisplayMonitorsConfig *msg = spice_malloc0(sizeof(*msg) + heads_size); > + int count = 0; // ignore monitors_config->count, it may contain zero width monitors, remove them now > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_MONITORS_CONFIG, NULL); > + for (i = 0 ; i < monitors_config->count; ++i) { > + if (monitors_config->heads[i].width == 0 || monitors_config->heads[i].height == 0) { > + continue; > + } > + msg->heads[count].id = monitors_config->heads[i].id; > + msg->heads[count].surface_id = monitors_config->heads[i].surface_id; > + msg->heads[count].width = monitors_config->heads[i].width; > + msg->heads[count].height = monitors_config->heads[i].height; > + msg->heads[count].x = monitors_config->heads[i].x; > + msg->heads[count].y = monitors_config->heads[i].y; > + count++; > + } > + msg->count = count; > + msg->max_allowed = monitors_config->max_allowed; > + spice_marshall_msg_display_monitors_config(base_marshaller, msg); > + free(msg); > +} > + > +static void marshall_stream_activate_report(RedChannelClient *rcc, > + SpiceMarshaller *base_marshaller, > + uint32_t stream_id) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + StreamAgent *agent = &dcc->stream_agents[stream_id]; > + SpiceMsgDisplayStreamActivateReport msg; > + > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT, NULL); > + msg.stream_id = stream_id; > + msg.unique_id = agent->report_id; > + msg.max_window_size = RED_STREAM_CLIENT_REPORT_WINDOW; > + msg.timeout_ms = RED_STREAM_CLIENT_REPORT_TIMEOUT; > + spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg); > +} > + > +static void begin_send_message(RedChannelClient *rcc) > +{ > + DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > + FreeList *free_list = &dcc->send_data.free_list; > + > + if (free_list->res->count) { > + int sync_count = 0; > + int i; > + > + for (i = 0; i < MAX_CACHE_CLIENTS; i++) { > + if (i != dcc->common.id && free_list->sync[i] != 0) { > + free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY; > + free_list->wait.header.wait_list[sync_count].channel_id = i; > + free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i]; > + } > + } > + free_list->wait.header.wait_count = sync_count; > + > + if (rcc->is_mini_header) { > + send_free_list(rcc); > + } else { > + send_free_list_legacy(rcc); > + } > + } > + red_channel_client_begin_send_message(rcc); > +} > + > +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); > + > + reset_send_data(dcc); > + switch (pipe_item->type) { > + case PIPE_ITEM_TYPE_DRAW: { > + DrawablePipeItem *dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item); > + marshall_qxl_drawable(rcc, m, dpi); > + break; > + } > + case PIPE_ITEM_TYPE_INVAL_ONE: > + marshall_inval_palette(rcc, m, (CacheItem *)pipe_item); > + break; > + case PIPE_ITEM_TYPE_STREAM_CREATE: { > + StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item); > + marshall_stream_start(rcc, m, agent); > + break; > + } > + case PIPE_ITEM_TYPE_STREAM_CLIP: { > + StreamClipItem* clip_item = (StreamClipItem *)pipe_item; > + marshall_stream_clip(rcc, m, clip_item); > + break; > + } > + case PIPE_ITEM_TYPE_STREAM_DESTROY: { > + StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item); > + marshall_stream_end(rcc, m, agent); > + break; > + } > + case PIPE_ITEM_TYPE_UPGRADE: > + marshall_upgrade(rcc, m, (UpgradeItem *)pipe_item); > + break; > + case PIPE_ITEM_TYPE_VERB: > + red_marshall_verb(rcc, (VerbItem*)pipe_item); > + break; > + case PIPE_ITEM_TYPE_MIGRATE_DATA: > + display_channel_marshall_migrate_data(rcc, m); > + break; > + case PIPE_ITEM_TYPE_IMAGE: > + red_marshall_image(rcc, m, (ImageItem *)pipe_item); > + break; > + case PIPE_ITEM_TYPE_PIXMAP_SYNC: > + display_channel_marshall_pixmap_sync(rcc, m); > + break; > + case PIPE_ITEM_TYPE_PIXMAP_RESET: > + display_channel_marshall_reset_cache(rcc, m); > + break; > + case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE: > + dcc_palette_cache_reset(dcc); > + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES, NULL); > + break; > + case PIPE_ITEM_TYPE_CREATE_SURFACE: { > + SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem, > + pipe_item); > + marshall_surface_create(rcc, m, &surface_create->surface_create); > + break; > + } > + case PIPE_ITEM_TYPE_DESTROY_SURFACE: { > + SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(pipe_item, SurfaceDestroyItem, > + pipe_item); > + marshall_surface_destroy(rcc, m, surface_destroy->surface_destroy.surface_id); > + break; > + } > + case PIPE_ITEM_TYPE_MONITORS_CONFIG: { > + MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(pipe_item, > + MonitorsConfigItem, pipe_item); > + marshall_monitors_config(rcc, m, monconf_item->monitors_config); > + break; > + } > + case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: { > + StreamActivateReportItem *report_item = SPICE_CONTAINEROF(pipe_item, > + StreamActivateReportItem, > + pipe_item); > + marshall_stream_activate_report(rcc, m, report_item->stream_id); > + break; > + } > + default: > + spice_warn_if_reached(); > + } > + > + dcc_release_item(dcc, pipe_item, FALSE); > + > + // a message is pending > + if (red_channel_client_send_message_pending(rcc)) { > + begin_send_message(rcc); > + } > +} > diff --git a/server/dcc.h b/server/dcc.h > index c5767c9..2351d55 100644 > --- a/server/dcc.h > +++ b/server/dcc.h > @@ -41,6 +41,8 @@ > #define WIDE_CLIENT_ACK_WINDOW 40 > #define NARROW_CLIENT_ACK_WINDOW 20 > > +#define MAX_PIPE_SIZE 50 > + > typedef struct WaitForChannels { > SpiceMsgWaitForChannels header; > SpiceWaitForChannel buf[MAX_CACHE_CLIENTS]; > diff --git a/server/red_worker.c b/server/red_worker.c > index 2b5c162..ac52a8f 100644 > --- a/server/red_worker.c > +++ b/server/red_worker.c > @@ -50,11 +50,9 @@ > #include <spice/protocol.h> > #include <spice/qxl_dev.h> > #include "common/lz.h" > -#include "common/marshaller.h" > #include "common/rect.h" > #include "common/region.h" > #include "common/ring.h" > -#include "common/generated_server_marshallers.h" > > #include "display-channel.h" > #include "stream.h" > @@ -81,8 +79,6 @@ struct SpiceWatch { > void *watch_func_opaque; > }; > > -#define MAX_PIPE_SIZE 50 > - > struct RedWorker { > pthread_t thread; > clockid_t clockid; > @@ -117,22 +113,6 @@ struct RedWorker { > FILE *record_fd; > }; > > -typedef enum { > - BITMAP_DATA_TYPE_INVALID, > - BITMAP_DATA_TYPE_CACHE, > - BITMAP_DATA_TYPE_SURFACE, > - BITMAP_DATA_TYPE_BITMAP, > - BITMAP_DATA_TYPE_BITMAP_TO_CACHE, > -} BitmapDataType; > - > -typedef struct BitmapData { > - BitmapDataType type; > - uint64_t id; // surface id or cache item id > - SpiceRect lossy_rect; > -} BitmapData; > - > -static inline void display_begin_send_message(RedChannelClient *rcc); > - > QXLInstance* red_worker_get_qxl(RedWorker *worker) > { > spice_return_val_if_fail(worker != NULL, NULL); > @@ -140,6 +120,13 @@ QXLInstance* red_worker_get_qxl(RedWorker *worker) > return worker->qxl; > } > > +RedMemSlotInfo* red_worker_get_memslot(RedWorker *worker) > +{ > + spice_return_val_if_fail(worker != NULL, NULL); > + > + return &worker->mem_slots; > +} > + > static int display_is_connected(RedWorker *worker) > { > return (worker->display_channel && red_channel_is_connected( > @@ -152,11 +139,6 @@ static int cursor_is_connected(RedWorker *worker) > red_channel_is_connected(RED_CHANNEL(worker->cursor_channel)); > } > > -static PipeItem *dcc_get_tail(DisplayChannelClient *dcc) > -{ > - return (PipeItem*)ring_get_tail(&RED_CHANNEL_CLIENT(dcc)->pipe); > -} > - > void red_pipes_remove_drawable(Drawable *drawable) > { > DrawablePipeItem *dpi; > @@ -698,2434 +680,6 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int * > return n; > } > > -static void fill_base(SpiceMarshaller *base_marshaller, Drawable *drawable) > -{ > - SpiceMsgDisplayBase base; > - > - base.surface_id = drawable->surface_id; > - base.box = drawable->red_drawable->bbox; > - base.clip = drawable->red_drawable->clip; > - > - spice_marshall_DisplayBase(base_marshaller, &base); > -} > - > -static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, > - SpiceImage *image, SpiceImage *io_image, > - int is_lossy) > -{ > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - > - if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > - spice_assert(image->descriptor.width * image->descriptor.height > 0); > - if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) { > - if (dcc_pixmap_cache_unlocked_add(dcc, image->descriptor.id, > - image->descriptor.width * image->descriptor.height, > - is_lossy)) { > - io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; > - dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = > - image->descriptor.id; > - stat_inc_counter(display_channel->add_to_cache_counter, 1); > - } > - } > - } > - > - if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > - stat_inc_counter(display_channel->non_cache_counter, 1); > - } > -} > - > -static int dcc_pixmap_cache_unlocked_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) > -{ > - PixmapCache *cache = dcc->pixmap_cache; > - NewCacheItem *item; > - uint64_t serial; > - > - serial = red_channel_client_get_message_serial(RED_CHANNEL_CLIENT(dcc)); > - item = cache->hash_table[BITS_CACHE_HASH_KEY(id)]; > - > - while (item) { > - if (item->id == id) { > - ring_remove(&item->lru_link); > - ring_add(&cache->lru, &item->lru_link); > - spice_assert(dcc->common.id < MAX_CACHE_CLIENTS); > - item->sync[dcc->common.id] = serial; > - cache->sync[dcc->common.id] = serial; > - *lossy = item->lossy; > - break; > - } > - item = item->next; > - } > - > - return !!item; > -} > - > -static int dcc_pixmap_cache_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) > -{ > - int hit; > - PixmapCache *cache = dcc->pixmap_cache; > - > - pthread_mutex_lock(&cache->lock); > - hit = dcc_pixmap_cache_unlocked_hit(dcc, id, lossy); > - pthread_mutex_unlock(&cache->lock); > - return hit; > -} > - > - > -typedef enum { > - FILL_BITS_TYPE_INVALID, > - FILL_BITS_TYPE_CACHE, > - FILL_BITS_TYPE_SURFACE, > - FILL_BITS_TYPE_COMPRESS_LOSSLESS, > - FILL_BITS_TYPE_COMPRESS_LOSSY, > - FILL_BITS_TYPE_BITMAP, > -} FillBitsType; > - > -/* if the number of times fill_bits can be called per one qxl_drawable increases - > - MAX_LZ_DRAWABLE_INSTANCES must be increased as well */ > -static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m, > - SpiceImage *simage, Drawable *drawable, int can_lossy) > -{ > - RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc); > - DisplayChannel *display = DCC_TO_DC(dcc); > - SpiceImage image; > - compress_send_data_t comp_send_data = {0}; > - SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out; > - > - if (simage == NULL) { > - spice_assert(drawable->red_drawable->self_bitmap_image); > - simage = drawable->red_drawable->self_bitmap_image; > - } > - > - image.descriptor = simage->descriptor; > - image.descriptor.flags = 0; > - if (simage->descriptor.flags & SPICE_IMAGE_FLAGS_HIGH_BITS_SET) { > - image.descriptor.flags = SPICE_IMAGE_FLAGS_HIGH_BITS_SET; > - } > - pthread_mutex_lock(&dcc->pixmap_cache->lock); > - > - if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > - int lossy_cache_item; > - if (dcc_pixmap_cache_unlocked_hit(dcc, image.descriptor.id, &lossy_cache_item)) { > - dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = > - image.descriptor.id; > - if (can_lossy || !lossy_cache_item) { > - if (!display->enable_jpeg || lossy_cache_item) { > - image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE; > - } else { > - // making sure, in multiple monitor scenario, that lossy items that > - // should have been replaced with lossless data by one display channel, > - // will be retrieved as lossless by another display channel. > - image.descriptor.type = SPICE_IMAGE_TYPE_FROM_CACHE_LOSSLESS; > - } > - spice_marshall_Image(m, &image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_assert(bitmap_palette_out == NULL); > - spice_assert(lzplt_palette_out == NULL); > - stat_inc_counter(display->cache_hits_counter, 1); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_CACHE; > - } else { > - pixmap_cache_unlocked_set_lossy(dcc->pixmap_cache, simage->descriptor.id, > - FALSE); > - image.descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME; > - } > - } > - } > - > - switch (simage->descriptor.type) { > - case SPICE_IMAGE_TYPE_SURFACE: { > - int surface_id; > - RedSurface *surface; > - > - surface_id = simage->u.surface.surface_id; > - if (!validate_surface(display, surface_id)) { > - spice_warning("Invalid surface in SPICE_IMAGE_TYPE_SURFACE"); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_SURFACE; > - } > - > - surface = &display->surfaces[surface_id]; > - image.descriptor.type = SPICE_IMAGE_TYPE_SURFACE; > - image.descriptor.flags = 0; > - image.descriptor.width = surface->context.width; > - image.descriptor.height = surface->context.height; > - > - image.u.surface.surface_id = surface_id; > - spice_marshall_Image(m, &image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_assert(bitmap_palette_out == NULL); > - spice_assert(lzplt_palette_out == NULL); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_SURFACE; > - } > - case SPICE_IMAGE_TYPE_BITMAP: { > - SpiceBitmap *bitmap = &image.u.bitmap; > -#ifdef DUMP_BITMAP > - dump_bitmap(&simage->u.bitmap); > -#endif > - /* Images must be added to the cache only after they are compressed > - in order to prevent starvation in the client between pixmap_cache and > - global dictionary (in cases of multiple monitors) */ > - if (reds_stream_get_family(rcc->stream) == AF_UNIX || > - !dcc_compress_image(dcc, &image, &simage->u.bitmap, > - drawable, can_lossy, &comp_send_data)) { > - SpicePalette *palette; > - > - red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE); > - > - *bitmap = simage->u.bitmap; > - bitmap->flags = bitmap->flags & SPICE_BITMAP_FLAGS_TOP_DOWN; > - > - palette = bitmap->palette; > - dcc_palette_cache_palette(dcc, palette, &bitmap->flags); > - spice_marshall_Image(m, &image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_assert(lzplt_palette_out == NULL); > - > - if (bitmap_palette_out && palette) { > - spice_marshall_Palette(bitmap_palette_out, palette); > - } > - > - spice_marshaller_add_ref_chunks(m, bitmap->data); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_BITMAP; > - } else { > - red_display_add_image_to_pixmap_cache(rcc, simage, &image, > - comp_send_data.is_lossy); > - > - spice_marshall_Image(m, &image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_assert(bitmap_palette_out == NULL); > - > - marshaller_add_compressed(m, comp_send_data.comp_buf, > - comp_send_data.comp_buf_size); > - > - if (lzplt_palette_out && comp_send_data.lzplt_palette) { > - spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette); > - } > - > - spice_assert(!comp_send_data.is_lossy || can_lossy); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return (comp_send_data.is_lossy ? FILL_BITS_TYPE_COMPRESS_LOSSY : > - FILL_BITS_TYPE_COMPRESS_LOSSLESS); > - } > - break; > - } > - case SPICE_IMAGE_TYPE_QUIC: > - red_display_add_image_to_pixmap_cache(rcc, simage, &image, FALSE); > - image.u.quic = simage->u.quic; > - spice_marshall_Image(m, &image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_assert(bitmap_palette_out == NULL); > - spice_assert(lzplt_palette_out == NULL); > - spice_marshaller_add_ref_chunks(m, image.u.quic.data); > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_COMPRESS_LOSSLESS; > - default: > - spice_error("invalid image type %u", image.descriptor.type); > - } > - pthread_mutex_unlock(&dcc->pixmap_cache->lock); > - return FILL_BITS_TYPE_INVALID; > -} > - > -static void fill_mask(RedChannelClient *rcc, SpiceMarshaller *m, > - SpiceImage *mask_bitmap, Drawable *drawable) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - > - if (mask_bitmap && m) { > - if (dcc->image_compression != SPICE_IMAGE_COMPRESSION_OFF) { > - /* todo: pass compression argument */ > - SpiceImageCompression save_img_comp = dcc->image_compression; > - dcc->image_compression = SPICE_IMAGE_COMPRESSION_OFF; > - fill_bits(dcc, m, mask_bitmap, drawable, FALSE); > - dcc->image_compression = save_img_comp; > - } else { > - fill_bits(dcc, m, mask_bitmap, drawable, FALSE); > - } > - } > -} > - > -static void fill_attr(SpiceMarshaller *m, SpiceLineAttr *attr, uint32_t group_id) > -{ > - int i; > - > - if (m && attr->style_nseg) { > - for (i = 0 ; i < attr->style_nseg; i++) { > - spice_marshaller_add_uint32(m, attr->style[i]); > - } > - } > -} > - > -/* 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) > -{ > - RedSurface *surface; > - QRegion *surface_lossy_region; > - QRegion lossy_region; > - DisplayChannel *display = DCC_TO_DC(dcc); > - > - spice_return_val_if_fail(validate_surface(display, surface_id), FALSE); > - > - surface = &display->surfaces[surface_id]; > - surface_lossy_region = &dcc->surface_client_lossy_region[surface_id]; > - > - if (!area) { > - if (region_is_empty(surface_lossy_region)) { > - return FALSE; > - } else { > - out_lossy_area->top = 0; > - out_lossy_area->left = 0; > - out_lossy_area->bottom = surface->context.height; > - out_lossy_area->right = surface->context.width; > - return TRUE; > - } > - } > - > - region_init(&lossy_region); > - region_add(&lossy_region, area); > - region_and(&lossy_region, surface_lossy_region); > - if (!region_is_empty(&lossy_region)) { > - out_lossy_area->left = lossy_region.extents.x1; > - out_lossy_area->top = lossy_region.extents.y1; > - out_lossy_area->right = lossy_region.extents.x2; > - out_lossy_area->bottom = lossy_region.extents.y2; > - region_destroy(&lossy_region); > - return TRUE; > - } else { > - return FALSE; > - } > -} > -/* returns if the bitmap was already sent lossy to the client. If the bitmap hasn't been sent yet > - to the client, returns false. "area" is for surfaces. If area = NULL, > - all the surface is considered. out_lossy_data will hold info about the bitmap, and its lossy > - area in case it is lossy and part of a surface. */ > -static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect *area, > - Drawable *drawable, BitmapData *out_data) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - > - if (image == NULL) { > - // self bitmap > - out_data->type = BITMAP_DATA_TYPE_BITMAP; > - return FALSE; > - } > - > - if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { > - int is_hit_lossy; > - > - out_data->id = image->descriptor.id; > - if (dcc_pixmap_cache_hit(dcc, image->descriptor.id, &is_hit_lossy)) { > - out_data->type = BITMAP_DATA_TYPE_CACHE; > - if (is_hit_lossy) { > - return TRUE; > - } else { > - return FALSE; > - } > - } else { > - out_data->type = BITMAP_DATA_TYPE_BITMAP_TO_CACHE; > - } > - } else { > - out_data->type = BITMAP_DATA_TYPE_BITMAP; > - } > - > - if (image->descriptor.type != SPICE_IMAGE_TYPE_SURFACE) { > - return FALSE; > - } > - > - out_data->type = BITMAP_DATA_TYPE_SURFACE; > - out_data->id = image->u.surface.surface_id; > - > - if (is_surface_area_lossy(dcc, out_data->id, > - area, &out_data->lossy_rect)) > - { > - return TRUE; > - } else { > - return FALSE; > - } > -} > - > -static int is_brush_lossy(RedChannelClient *rcc, SpiceBrush *brush, > - Drawable *drawable, BitmapData *out_data) > -{ > - if (brush->type == SPICE_BRUSH_TYPE_PATTERN) { > - return is_bitmap_lossy(rcc, brush->u.pattern.pat, NULL, > - drawable, out_data); > - } else { > - out_data->type = BITMAP_DATA_TYPE_INVALID; > - return FALSE; > - } > -} > - > -static void surface_lossy_region_update(DisplayChannelClient *dcc, > - Drawable *item, int has_mask, int lossy) > -{ > - QRegion *surface_lossy_region; > - RedDrawable *drawable; > - > - if (has_mask && !lossy) { > - return; > - } > - > - surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id]; > - drawable = item->red_drawable; > - > - if (drawable->clip.type == SPICE_CLIP_TYPE_RECTS ) { > - QRegion clip_rgn; > - QRegion draw_region; > - region_init(&clip_rgn); > - region_init(&draw_region); > - region_add(&draw_region, &drawable->bbox); > - region_add_clip_rects(&clip_rgn, drawable->clip.rects); > - region_and(&draw_region, &clip_rgn); > - if (lossy) { > - region_or(surface_lossy_region, &draw_region); > - } else { > - region_exclude(surface_lossy_region, &draw_region); > - } > - > - region_destroy(&clip_rgn); > - region_destroy(&draw_region); > - } else { /* no clip */ > - if (!lossy) { > - region_remove(surface_lossy_region, &drawable->bbox); > - } else { > - region_add(surface_lossy_region, &drawable->bbox); > - } > - } > -} > - > -static inline int drawable_intersects_with_areas(Drawable *drawable, int surface_ids[], > - SpiceRect *surface_areas[], > - int num_surfaces) > -{ > - int i; > - for (i = 0; i < num_surfaces; i++) { > - if (surface_ids[i] == drawable->red_drawable->surface_id) { > - if (rect_intersects(surface_areas[i], &drawable->red_drawable->bbox)) { > - return TRUE; > - } > - } > - } > - return FALSE; > -} > - > -static inline int drawable_depends_on_areas(Drawable *drawable, > - int surface_ids[], > - SpiceRect surface_areas[], > - int num_surfaces) > -{ > - int i; > - RedDrawable *red_drawable; > - int drawable_has_shadow; > - SpiceRect shadow_rect = {0, 0, 0, 0}; > - > - red_drawable = drawable->red_drawable; > - drawable_has_shadow = has_shadow(red_drawable); > - > - if (drawable_has_shadow) { > - int delta_x = red_drawable->u.copy_bits.src_pos.x - red_drawable->bbox.left; > - int delta_y = red_drawable->u.copy_bits.src_pos.y - red_drawable->bbox.top; > - > - shadow_rect.left = red_drawable->u.copy_bits.src_pos.x; > - shadow_rect.top = red_drawable->u.copy_bits.src_pos.y; > - shadow_rect.right = red_drawable->bbox.right + delta_x; > - shadow_rect.bottom = red_drawable->bbox.bottom + delta_y; > - } > - > - for (i = 0; i < num_surfaces; i++) { > - int x; > - int dep_surface_id; > - > - for (x = 0; x < 3; ++x) { > - dep_surface_id = drawable->surface_deps[x]; > - if (dep_surface_id == surface_ids[i]) { > - if (rect_intersects(&surface_areas[i], &red_drawable->surfaces_rects[x])) { > - return TRUE; > - } > - } > - } > - > - if (surface_ids[i] == red_drawable->surface_id) { > - if (drawable_has_shadow) { > - if (rect_intersects(&surface_areas[i], &shadow_rect)) { > - return TRUE; > - } > - } > - > - // not dependent on dest > - if (red_drawable->effect == QXL_EFFECT_OPAQUE) { > - continue; > - } > - > - if (rect_intersects(&surface_areas[i], &red_drawable->bbox)) { > - return TRUE; > - } > - } > - > - } > - return FALSE; > -} > - > - > -static int pipe_rendered_drawables_intersect_with_areas(DisplayChannelClient *dcc, > - int surface_ids[], > - SpiceRect *surface_areas[], > - int num_surfaces) > -{ > - PipeItem *pipe_item; > - Ring *pipe; > - > - spice_assert(num_surfaces); > - pipe = &RED_CHANNEL_CLIENT(dcc)->pipe; > - > - for (pipe_item = (PipeItem *)ring_get_head(pipe); > - pipe_item; > - pipe_item = (PipeItem *)ring_next(pipe, &pipe_item->link)) > - { > - Drawable *drawable; > - > - if (pipe_item->type != PIPE_ITEM_TYPE_DRAW) > - continue; > - drawable = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item)->drawable; > - > - if (ring_item_is_linked(&drawable->list_link)) > - continue; // item hasn't been rendered > - > - if (drawable_intersects_with_areas(drawable, surface_ids, surface_areas, num_surfaces)) { > - return TRUE; > - } > - } > - > - return FALSE; > -} > - > -static void red_pipe_replace_rendered_drawables_with_images(DisplayChannelClient *dcc, > - int first_surface_id, > - SpiceRect *first_area) > -{ > - /* TODO: can't have those statics with multiple clients */ > - static int resent_surface_ids[MAX_PIPE_SIZE]; > - static SpiceRect resent_areas[MAX_PIPE_SIZE]; // not pointers since drawbales may be released > - int num_resent; > - PipeItem *pipe_item; > - Ring *pipe; > - > - resent_surface_ids[0] = first_surface_id; > - resent_areas[0] = *first_area; > - num_resent = 1; > - > - pipe = &RED_CHANNEL_CLIENT(dcc)->pipe; > - > - // going from the oldest to the newest > - for (pipe_item = (PipeItem *)ring_get_tail(pipe); > - pipe_item; > - pipe_item = (PipeItem *)ring_prev(pipe, &pipe_item->link)) { > - Drawable *drawable; > - DrawablePipeItem *dpi; > - ImageItem *image; > - > - if (pipe_item->type != PIPE_ITEM_TYPE_DRAW) > - continue; > - dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item); > - drawable = dpi->drawable; > - if (ring_item_is_linked(&drawable->list_link)) > - continue; // item hasn't been rendered > - > - // When a drawable command, X, depends on bitmaps that were resent, > - // these bitmaps state at the client might not be synchronized with X > - // (i.e., the bitmaps can be more futuristic w.r.t X). Thus, X shouldn't > - // be rendered at the client, and we replace it with an image as well. > - if (!drawable_depends_on_areas(drawable, > - resent_surface_ids, > - resent_areas, > - num_resent)) { > - continue; > - } > - > - image = dcc_add_surface_area_image(dcc, drawable->red_drawable->surface_id, > - &drawable->red_drawable->bbox, pipe_item, TRUE); > - resent_surface_ids[num_resent] = drawable->red_drawable->surface_id; > - resent_areas[num_resent] = drawable->red_drawable->bbox; > - num_resent++; > - > - spice_assert(image); > - red_channel_client_pipe_remove_and_release(RED_CHANNEL_CLIENT(dcc), &dpi->dpi_pipe_item); > - pipe_item = &image->link; > - } > -} > - > -static void red_add_lossless_drawable_dependencies(RedChannelClient *rcc, > - Drawable *item, > - int deps_surfaces_ids[], > - SpiceRect *deps_areas[], > - int num_deps) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - DisplayChannel *display = DCC_TO_DC(dcc); > - RedDrawable *drawable = item->red_drawable; > - int sync_rendered = FALSE; > - int i; > - > - if (!ring_item_is_linked(&item->list_link)) { > - /* drawable was already rendered, we may not be able to retrieve the lossless data > - for the lossy areas */ > - sync_rendered = TRUE; > - > - // checking if the drawable itself or one of the other commands > - // that were rendered, affected the areas that need to be resent > - if (!drawable_intersects_with_areas(item, deps_surfaces_ids, > - deps_areas, num_deps)) { > - if (pipe_rendered_drawables_intersect_with_areas(dcc, > - deps_surfaces_ids, > - deps_areas, > - num_deps)) { > - sync_rendered = TRUE; > - } > - } else { > - sync_rendered = TRUE; > - } > - } else { > - sync_rendered = FALSE; > - for (i = 0; i < num_deps; i++) { > - display_channel_draw_until(display, deps_areas[i], deps_surfaces_ids[i], item); > - } > - } > - > - if (!sync_rendered) { > - // pushing the pipe item back to the pipe > - dcc_append_drawable(dcc, item); > - // the surfaces areas will be sent as DRAW_COPY commands, that > - // will be executed before the current drawable > - for (i = 0; i < num_deps; i++) { > - dcc_add_surface_area_image(dcc, deps_surfaces_ids[i], deps_areas[i], > - dcc_get_tail(dcc), FALSE); > - > - } > - } else { > - int drawable_surface_id[1]; > - SpiceRect *drawable_bbox[1]; > - > - drawable_surface_id[0] = drawable->surface_id; > - drawable_bbox[0] = &drawable->bbox; > - > - // check if the other rendered images in the pipe have updated the drawable bbox > - if (pipe_rendered_drawables_intersect_with_areas(dcc, > - drawable_surface_id, > - drawable_bbox, > - 1)) { > - red_pipe_replace_rendered_drawables_with_images(dcc, > - drawable->surface_id, > - &drawable->bbox); > - } > - > - dcc_add_surface_area_image(dcc, drawable->surface_id, &drawable->bbox, > - dcc_get_tail(dcc), TRUE); > - } > -} > - > -static void red_marshall_qxl_draw_fill(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMarshaller *brush_pat_out; > - SpiceMarshaller *mask_bitmap_out; > - SpiceFill fill; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_FILL, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - fill = drawable->u.fill; > - spice_marshall_Fill(base_marshaller, > - &fill, > - &brush_pat_out, > - &mask_bitmap_out); > - > - if (brush_pat_out) { > - fill_bits(dcc, brush_pat_out, fill.brush.u.pattern.pat, item, FALSE); > - } > - > - fill_mask(rcc, mask_bitmap_out, fill.mask.bitmap, item); > -} > - > - > -static void red_lossy_marshall_qxl_draw_fill(RedChannelClient *rcc, > - SpiceMarshaller *m, > - DrawablePipeItem *dpi) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - > - int dest_allowed_lossy = FALSE; > - int dest_is_lossy = FALSE; > - SpiceRect dest_lossy_area; > - int brush_is_lossy; > - BitmapData brush_bitmap_data; > - uint16_t rop; > - > - rop = drawable->u.fill.rop_descriptor; > - > - dest_allowed_lossy = !((rop & SPICE_ROPD_OP_OR) || > - (rop & SPICE_ROPD_OP_AND) || > - (rop & SPICE_ROPD_OP_XOR)); > - > - brush_is_lossy = is_brush_lossy(rcc, &drawable->u.fill.brush, item, > - &brush_bitmap_data); > - if (!dest_allowed_lossy) { > - dest_is_lossy = is_surface_area_lossy(dcc, item->surface_id, &drawable->bbox, > - &dest_lossy_area); > - } > - > - if (!dest_is_lossy && > - !(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) { > - int has_mask = !!drawable->u.fill.mask.bitmap; > - > - red_marshall_qxl_draw_fill(rcc, m, dpi); > - // either the brush operation is opaque, or the dest is not lossy > - surface_lossy_region_update(dcc, item, has_mask, FALSE); > - } else { > - int resend_surface_ids[2]; > - SpiceRect *resend_areas[2]; > - int num_resend = 0; > - > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = item->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - > - if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = brush_bitmap_data.id; > - resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static FillBitsType red_marshall_qxl_draw_opaque(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi, int src_allowed_lossy) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *brush_pat_out; > - SpiceMarshaller *src_bitmap_out; > - SpiceMarshaller *mask_bitmap_out; > - SpiceOpaque opaque; > - FillBitsType src_send_type; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_OPAQUE, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - opaque = drawable->u.opaque; > - spice_marshall_Opaque(base_marshaller, > - &opaque, > - &src_bitmap_out, > - &brush_pat_out, > - &mask_bitmap_out); > - > - src_send_type = fill_bits(dcc, src_bitmap_out, opaque.src_bitmap, item, > - src_allowed_lossy); > - > - if (brush_pat_out) { > - fill_bits(dcc, brush_pat_out, opaque.brush.u.pattern.pat, item, FALSE); > - } > - fill_mask(rcc, mask_bitmap_out, opaque.mask.bitmap, item); > - > - return src_send_type; > -} > - > -static void red_lossy_marshall_qxl_draw_opaque(RedChannelClient *rcc, > - SpiceMarshaller *m, > - DrawablePipeItem *dpi) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - > - int src_allowed_lossy; > - int rop; > - int src_is_lossy = FALSE; > - int brush_is_lossy = FALSE; > - BitmapData src_bitmap_data; > - BitmapData brush_bitmap_data; > - > - rop = drawable->u.opaque.rop_descriptor; > - src_allowed_lossy = !((rop & SPICE_ROPD_OP_OR) || > - (rop & SPICE_ROPD_OP_AND) || > - (rop & SPICE_ROPD_OP_XOR)); > - > - brush_is_lossy = is_brush_lossy(rcc, &drawable->u.opaque.brush, item, > - &brush_bitmap_data); > - > - if (!src_allowed_lossy) { > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.opaque.src_bitmap, > - &drawable->u.opaque.src_area, > - item, > - &src_bitmap_data); > - } > - > - if (!(brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) && > - !(src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE))) { > - FillBitsType src_send_type; > - int has_mask = !!drawable->u.opaque.mask.bitmap; > - > - src_send_type = red_marshall_qxl_draw_opaque(rcc, m, dpi, src_allowed_lossy); > - if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > - src_is_lossy = TRUE; > - } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > - src_is_lossy = FALSE; > - } > - > - surface_lossy_region_update(dcc, item, has_mask, src_is_lossy); > - } else { > - int resend_surface_ids[2]; > - SpiceRect *resend_areas[2]; > - int num_resend = 0; > - > - if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = src_bitmap_data.id; > - resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = brush_bitmap_data.id; > - resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static FillBitsType red_marshall_qxl_draw_copy(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi, int src_allowed_lossy) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *src_bitmap_out; > - SpiceMarshaller *mask_bitmap_out; > - SpiceCopy copy; > - FillBitsType src_send_type; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - copy = drawable->u.copy; > - spice_marshall_Copy(base_marshaller, > - ©, > - &src_bitmap_out, > - &mask_bitmap_out); > - > - src_send_type = fill_bits(dcc, src_bitmap_out, copy.src_bitmap, item, src_allowed_lossy); > - fill_mask(rcc, mask_bitmap_out, copy.mask.bitmap, item); > - > - return src_send_type; > -} > - > -static void red_lossy_marshall_qxl_draw_copy(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - int has_mask = !!drawable->u.copy.mask.bitmap; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - FillBitsType src_send_type; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.copy.src_bitmap, > - &drawable->u.copy.src_area, item, &src_bitmap_data); > - > - src_send_type = red_marshall_qxl_draw_copy(rcc, base_marshaller, dpi, TRUE); > - if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > - src_is_lossy = TRUE; > - } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > - src_is_lossy = FALSE; > - } > - surface_lossy_region_update(dcc, item, has_mask, > - src_is_lossy); > -} > - > -static void red_marshall_qxl_draw_transparent(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *src_bitmap_out; > - SpiceTransparent transparent; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TRANSPARENT, > - &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - transparent = drawable->u.transparent; > - spice_marshall_Transparent(base_marshaller, > - &transparent, > - &src_bitmap_out); > - fill_bits(dcc, src_bitmap_out, transparent.src_bitmap, item, FALSE); > -} > - > -static void red_lossy_marshall_qxl_draw_transparent(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.transparent.src_bitmap, > - &drawable->u.transparent.src_area, item, &src_bitmap_data); > - > - if (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) { > - red_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi); > - // don't update surface lossy region since transperent areas might be lossy > - } else { > - int resend_surface_ids[1]; > - SpiceRect *resend_areas[1]; > - > - resend_surface_ids[0] = src_bitmap_data.id; > - resend_areas[0] = &src_bitmap_data.lossy_rect; > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, 1); > - } > -} > - > -static FillBitsType red_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi, > - int src_allowed_lossy) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *src_bitmap_out; > - SpiceAlphaBlend alpha_blend; > - FillBitsType src_send_type; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ALPHA_BLEND, > - &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - alpha_blend = drawable->u.alpha_blend; > - spice_marshall_AlphaBlend(base_marshaller, > - &alpha_blend, > - &src_bitmap_out); > - src_send_type = fill_bits(dcc, src_bitmap_out, alpha_blend.src_bitmap, item, > - src_allowed_lossy); > - > - return src_send_type; > -} > - > -static void red_lossy_marshall_qxl_draw_alpha_blend(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - FillBitsType src_send_type; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.alpha_blend.src_bitmap, > - &drawable->u.alpha_blend.src_area, item, &src_bitmap_data); > - > - src_send_type = red_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi, TRUE); > - > - if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSY) { > - src_is_lossy = TRUE; > - } else if (src_send_type == FILL_BITS_TYPE_COMPRESS_LOSSLESS) { > - src_is_lossy = FALSE; > - } > - > - if (src_is_lossy) { > - surface_lossy_region_update(dcc, item, FALSE, src_is_lossy); > - } // else, the area stays lossy/lossless as the destination > -} > - > -static void red_marshall_qxl_copy_bits(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpicePoint copy_bits; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_COPY_BITS, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - copy_bits = drawable->u.copy_bits.src_pos; > - spice_marshall_Point(base_marshaller, > - ©_bits); > -} > - > -static void red_lossy_marshall_qxl_copy_bits(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceRect src_rect; > - int horz_offset; > - int vert_offset; > - int src_is_lossy; > - SpiceRect src_lossy_area; > - > - red_marshall_qxl_copy_bits(rcc, base_marshaller, dpi); > - > - horz_offset = drawable->u.copy_bits.src_pos.x - drawable->bbox.left; > - vert_offset = drawable->u.copy_bits.src_pos.y - drawable->bbox.top; > - > - src_rect.left = drawable->u.copy_bits.src_pos.x; > - src_rect.top = drawable->u.copy_bits.src_pos.y; > - src_rect.right = drawable->bbox.right + horz_offset; > - src_rect.bottom = drawable->bbox.bottom + vert_offset; > - > - src_is_lossy = is_surface_area_lossy(dcc, item->surface_id, > - &src_rect, &src_lossy_area); > - > - surface_lossy_region_update(dcc, item, FALSE, src_is_lossy); > -} > - > -static void red_marshall_qxl_draw_blend(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *src_bitmap_out; > - SpiceMarshaller *mask_bitmap_out; > - SpiceBlend blend; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLEND, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - blend = drawable->u.blend; > - spice_marshall_Blend(base_marshaller, > - &blend, > - &src_bitmap_out, > - &mask_bitmap_out); > - > - fill_bits(dcc, src_bitmap_out, blend.src_bitmap, item, FALSE); > - > - fill_mask(rcc, mask_bitmap_out, blend.mask.bitmap, item); > -} > - > -static void red_lossy_marshall_qxl_draw_blend(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - int dest_is_lossy; > - SpiceRect dest_lossy_area; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.blend.src_bitmap, > - &drawable->u.blend.src_area, item, &src_bitmap_data); > - dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > - &drawable->bbox, &dest_lossy_area); > - > - if (!dest_is_lossy && > - (!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) { > - red_marshall_qxl_draw_blend(rcc, base_marshaller, dpi); > - } else { > - int resend_surface_ids[2]; > - SpiceRect *resend_areas[2]; > - int num_resend = 0; > - > - if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = src_bitmap_data.id; > - resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = item->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static void red_marshall_qxl_draw_blackness(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *mask_bitmap_out; > - SpiceBlackness blackness; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_BLACKNESS, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - blackness = drawable->u.blackness; > - > - spice_marshall_Blackness(base_marshaller, > - &blackness, > - &mask_bitmap_out); > - > - fill_mask(rcc, mask_bitmap_out, blackness.mask.bitmap, item); > -} > - > -static void red_lossy_marshall_qxl_draw_blackness(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int has_mask = !!drawable->u.blackness.mask.bitmap; > - > - red_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi); > - > - surface_lossy_region_update(dcc, item, has_mask, FALSE); > -} > - > -static void red_marshall_qxl_draw_whiteness(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *mask_bitmap_out; > - SpiceWhiteness whiteness; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_WHITENESS, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - whiteness = drawable->u.whiteness; > - > - spice_marshall_Whiteness(base_marshaller, > - &whiteness, > - &mask_bitmap_out); > - > - fill_mask(rcc, mask_bitmap_out, whiteness.mask.bitmap, item); > -} > - > -static void red_lossy_marshall_qxl_draw_whiteness(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int has_mask = !!drawable->u.whiteness.mask.bitmap; > - > - red_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi); > - > - surface_lossy_region_update(dcc, item, has_mask, FALSE); > -} > - > -static void red_marshall_qxl_draw_inverse(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - Drawable *item) > -{ > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *mask_bitmap_out; > - SpiceInvers inverse; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_INVERS, NULL); > - fill_base(base_marshaller, item); > - inverse = drawable->u.invers; > - > - spice_marshall_Invers(base_marshaller, > - &inverse, > - &mask_bitmap_out); > - > - fill_mask(rcc, mask_bitmap_out, inverse.mask.bitmap, item); > -} > - > -static void red_lossy_marshall_qxl_draw_inverse(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - Drawable *item) > -{ > - red_marshall_qxl_draw_inverse(rcc, base_marshaller, item); > -} > - > -static void red_marshall_qxl_draw_rop3(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceRop3 rop3; > - SpiceMarshaller *src_bitmap_out; > - SpiceMarshaller *brush_pat_out; > - SpiceMarshaller *mask_bitmap_out; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_ROP3, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - rop3 = drawable->u.rop3; > - spice_marshall_Rop3(base_marshaller, > - &rop3, > - &src_bitmap_out, > - &brush_pat_out, > - &mask_bitmap_out); > - > - fill_bits(dcc, src_bitmap_out, rop3.src_bitmap, item, FALSE); > - > - if (brush_pat_out) { > - fill_bits(dcc, brush_pat_out, rop3.brush.u.pattern.pat, item, FALSE); > - } > - fill_mask(rcc, mask_bitmap_out, rop3.mask.bitmap, item); > -} > - > -static void red_lossy_marshall_qxl_draw_rop3(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - int brush_is_lossy; > - BitmapData brush_bitmap_data; > - int dest_is_lossy; > - SpiceRect dest_lossy_area; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.rop3.src_bitmap, > - &drawable->u.rop3.src_area, item, &src_bitmap_data); > - brush_is_lossy = is_brush_lossy(rcc, &drawable->u.rop3.brush, item, > - &brush_bitmap_data); > - dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > - &drawable->bbox, &dest_lossy_area); > - > - if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > - (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > - !dest_is_lossy) { > - int has_mask = !!drawable->u.rop3.mask.bitmap; > - red_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi); > - surface_lossy_region_update(dcc, item, has_mask, FALSE); > - } else { > - int resend_surface_ids[3]; > - SpiceRect *resend_areas[3]; > - int num_resend = 0; > - > - if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = src_bitmap_data.id; > - resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = brush_bitmap_data.id; > - resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = item->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static void red_marshall_qxl_draw_composite(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceMarshaller *src_bitmap_out; > - SpiceMarshaller *mask_bitmap_out; > - SpiceComposite composite; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COMPOSITE, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - composite = drawable->u.composite; > - spice_marshall_Composite(base_marshaller, > - &composite, > - &src_bitmap_out, > - &mask_bitmap_out); > - > - fill_bits(dcc, src_bitmap_out, composite.src_bitmap, item, FALSE); > - if (mask_bitmap_out) { > - fill_bits(dcc, mask_bitmap_out, composite.mask_bitmap, item, FALSE); > - } > -} > - > -static void red_lossy_marshall_qxl_draw_composite(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int src_is_lossy; > - BitmapData src_bitmap_data; > - int mask_is_lossy; > - BitmapData mask_bitmap_data; > - int dest_is_lossy; > - SpiceRect dest_lossy_area; > - > - src_is_lossy = is_bitmap_lossy(rcc, drawable->u.composite.src_bitmap, > - NULL, item, &src_bitmap_data); > - mask_is_lossy = drawable->u.composite.mask_bitmap && > - is_bitmap_lossy(rcc, drawable->u.composite.mask_bitmap, NULL, item, &mask_bitmap_data); > - > - dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > - &drawable->bbox, &dest_lossy_area); > - > - if ((!src_is_lossy || (src_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > - (!mask_is_lossy || (mask_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > - !dest_is_lossy) { > - red_marshall_qxl_draw_composite(rcc, base_marshaller, dpi); > - surface_lossy_region_update(dcc, item, FALSE, FALSE); > - } > - else { > - int resend_surface_ids[3]; > - SpiceRect *resend_areas[3]; > - int num_resend = 0; > - > - if (src_is_lossy && (src_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = src_bitmap_data.id; > - resend_areas[num_resend] = &src_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (mask_is_lossy && (mask_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = mask_bitmap_data.id; > - resend_areas[num_resend] = &mask_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = item->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static void red_marshall_qxl_draw_stroke(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceStroke stroke; > - SpiceMarshaller *brush_pat_out; > - SpiceMarshaller *style_out; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_STROKE, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - stroke = drawable->u.stroke; > - spice_marshall_Stroke(base_marshaller, > - &stroke, > - &style_out, > - &brush_pat_out); > - > - fill_attr(style_out, &stroke.attr, item->group_id); > - if (brush_pat_out) { > - fill_bits(dcc, brush_pat_out, stroke.brush.u.pattern.pat, item, FALSE); > - } > -} > - > -static void red_lossy_marshall_qxl_draw_stroke(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int brush_is_lossy; > - BitmapData brush_bitmap_data; > - int dest_is_lossy = FALSE; > - SpiceRect dest_lossy_area; > - int rop; > - > - brush_is_lossy = is_brush_lossy(rcc, &drawable->u.stroke.brush, item, > - &brush_bitmap_data); > - > - // back_mode is not used at the client. Ignoring. > - rop = drawable->u.stroke.fore_mode; > - > - // assuming that if the brush type is solid, the destination can > - // be lossy, no matter what the rop is. > - if (drawable->u.stroke.brush.type != SPICE_BRUSH_TYPE_SOLID && > - ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) || > - (rop & SPICE_ROPD_OP_XOR))) { > - dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > - &drawable->bbox, &dest_lossy_area); > - } > - > - if (!dest_is_lossy && > - (!brush_is_lossy || (brush_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) > - { > - red_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi); > - } else { > - int resend_surface_ids[2]; > - SpiceRect *resend_areas[2]; > - int num_resend = 0; > - > - if (brush_is_lossy && (brush_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = brush_bitmap_data.id; > - resend_areas[num_resend] = &brush_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - // TODO: use the path in order to resend smaller areas > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = drawable->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static void red_marshall_qxl_draw_text(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - SpiceText text; > - SpiceMarshaller *brush_pat_out; > - SpiceMarshaller *back_brush_pat_out; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_TEXT, &dpi->dpi_pipe_item); > - fill_base(base_marshaller, item); > - text = drawable->u.text; > - spice_marshall_Text(base_marshaller, > - &text, > - &brush_pat_out, > - &back_brush_pat_out); > - > - if (brush_pat_out) { > - fill_bits(dcc, brush_pat_out, text.fore_brush.u.pattern.pat, item, FALSE); > - } > - if (back_brush_pat_out) { > - fill_bits(dcc, back_brush_pat_out, text.back_brush.u.pattern.pat, item, FALSE); > - } > -} > - > -static void red_lossy_marshall_qxl_draw_text(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *drawable = item->red_drawable; > - int fg_is_lossy; > - BitmapData fg_bitmap_data; > - int bg_is_lossy; > - BitmapData bg_bitmap_data; > - int dest_is_lossy = FALSE; > - SpiceRect dest_lossy_area; > - int rop = 0; > - > - fg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.fore_brush, item, > - &fg_bitmap_data); > - bg_is_lossy = is_brush_lossy(rcc, &drawable->u.text.back_brush, item, > - &bg_bitmap_data); > - > - // assuming that if the brush type is solid, the destination can > - // be lossy, no matter what the rop is. > - if (drawable->u.text.fore_brush.type != SPICE_BRUSH_TYPE_SOLID) { > - rop = drawable->u.text.fore_mode; > - } > - > - if (drawable->u.text.back_brush.type != SPICE_BRUSH_TYPE_SOLID) { > - rop |= drawable->u.text.back_mode; > - } > - > - if ((rop & SPICE_ROPD_OP_OR) || (rop & SPICE_ROPD_OP_AND) || > - (rop & SPICE_ROPD_OP_XOR)) { > - dest_is_lossy = is_surface_area_lossy(dcc, drawable->surface_id, > - &drawable->bbox, &dest_lossy_area); > - } > - > - if (!dest_is_lossy && > - (!fg_is_lossy || (fg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE)) && > - (!bg_is_lossy || (bg_bitmap_data.type != BITMAP_DATA_TYPE_SURFACE))) { > - red_marshall_qxl_draw_text(rcc, base_marshaller, dpi); > - } else { > - int resend_surface_ids[3]; > - SpiceRect *resend_areas[3]; > - int num_resend = 0; > - > - if (fg_is_lossy && (fg_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = fg_bitmap_data.id; > - resend_areas[num_resend] = &fg_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (bg_is_lossy && (bg_bitmap_data.type == BITMAP_DATA_TYPE_SURFACE)) { > - resend_surface_ids[num_resend] = bg_bitmap_data.id; > - resend_areas[num_resend] = &bg_bitmap_data.lossy_rect; > - num_resend++; > - } > - > - if (dest_is_lossy) { > - resend_surface_ids[num_resend] = drawable->surface_id; > - resend_areas[num_resend] = &dest_lossy_area; > - num_resend++; > - } > - red_add_lossless_drawable_dependencies(rcc, item, > - resend_surface_ids, resend_areas, num_resend); > - } > -} > - > -static void red_lossy_marshall_qxl_drawable(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - switch (item->red_drawable->type) { > - case QXL_DRAW_FILL: > - red_lossy_marshall_qxl_draw_fill(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_OPAQUE: > - red_lossy_marshall_qxl_draw_opaque(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_COPY: > - red_lossy_marshall_qxl_draw_copy(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_TRANSPARENT: > - red_lossy_marshall_qxl_draw_transparent(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_ALPHA_BLEND: > - red_lossy_marshall_qxl_draw_alpha_blend(rcc, base_marshaller, dpi); > - break; > - case QXL_COPY_BITS: > - red_lossy_marshall_qxl_copy_bits(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_BLEND: > - red_lossy_marshall_qxl_draw_blend(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_BLACKNESS: > - red_lossy_marshall_qxl_draw_blackness(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_WHITENESS: > - red_lossy_marshall_qxl_draw_whiteness(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_INVERS: > - red_lossy_marshall_qxl_draw_inverse(rcc, base_marshaller, item); > - break; > - case QXL_DRAW_ROP3: > - red_lossy_marshall_qxl_draw_rop3(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_COMPOSITE: > - red_lossy_marshall_qxl_draw_composite(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_STROKE: > - red_lossy_marshall_qxl_draw_stroke(rcc, base_marshaller, dpi); > - break; > - case QXL_DRAW_TEXT: > - red_lossy_marshall_qxl_draw_text(rcc, base_marshaller, dpi); > - break; > - default: > - spice_error("invalid type"); > - } > -} > - > -static inline void red_marshall_qxl_drawable(RedChannelClient *rcc, > - SpiceMarshaller *m, DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - RedDrawable *drawable = item->red_drawable; > - > - switch (drawable->type) { > - case QXL_DRAW_FILL: > - red_marshall_qxl_draw_fill(rcc, m, dpi); > - break; > - case QXL_DRAW_OPAQUE: > - red_marshall_qxl_draw_opaque(rcc, m, dpi, FALSE); > - break; > - case QXL_DRAW_COPY: > - red_marshall_qxl_draw_copy(rcc, m, dpi, FALSE); > - break; > - case QXL_DRAW_TRANSPARENT: > - red_marshall_qxl_draw_transparent(rcc, m, dpi); > - break; > - case QXL_DRAW_ALPHA_BLEND: > - red_marshall_qxl_draw_alpha_blend(rcc, m, dpi, FALSE); > - break; > - case QXL_COPY_BITS: > - red_marshall_qxl_copy_bits(rcc, m, dpi); > - break; > - case QXL_DRAW_BLEND: > - red_marshall_qxl_draw_blend(rcc, m, dpi); > - break; > - case QXL_DRAW_BLACKNESS: > - red_marshall_qxl_draw_blackness(rcc, m, dpi); > - break; > - case QXL_DRAW_WHITENESS: > - red_marshall_qxl_draw_whiteness(rcc, m, dpi); > - break; > - case QXL_DRAW_INVERS: > - red_marshall_qxl_draw_inverse(rcc, m, item); > - break; > - case QXL_DRAW_ROP3: > - red_marshall_qxl_draw_rop3(rcc, m, dpi); > - break; > - case QXL_DRAW_STROKE: > - red_marshall_qxl_draw_stroke(rcc, m, dpi); > - break; > - case QXL_DRAW_COMPOSITE: > - red_marshall_qxl_draw_composite(rcc, m, dpi); > - break; > - case QXL_DRAW_TEXT: > - red_marshall_qxl_draw_text(rcc, m, dpi); > - break; > - default: > - spice_error("invalid type"); > - } > -} > - > -static inline void display_marshal_sub_msg_inval_list(SpiceMarshaller *m, > - FreeList *free_list) > -{ > - /* type + size + submessage */ > - spice_marshaller_add_uint16(m, SPICE_MSG_DISPLAY_INVAL_LIST); > - spice_marshaller_add_uint32(m, sizeof(*free_list->res) + > - free_list->res->count * sizeof(free_list->res->resources[0])); > - spice_marshall_msg_display_inval_list(m, free_list->res); > -} > - > -static inline void display_marshal_sub_msg_inval_list_wait(SpiceMarshaller *m, > - FreeList *free_list) > - > -{ > - /* type + size + submessage */ > - spice_marshaller_add_uint16(m, SPICE_MSG_WAIT_FOR_CHANNELS); > - spice_marshaller_add_uint32(m, sizeof(free_list->wait.header) + > - free_list->wait.header.wait_count * sizeof(free_list->wait.buf[0])); > - spice_marshall_msg_wait_for_channels(m, &free_list->wait.header); > -} > - > -/* use legacy SpiceDataHeader (with sub_list) */ > -static inline void display_channel_send_free_list_legacy(RedChannelClient *rcc) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - FreeList *free_list = &dcc->send_data.free_list; > - SpiceMarshaller *marshaller; > - int sub_list_len = 1; > - SpiceMarshaller *wait_m = NULL; > - SpiceMarshaller *inval_m; > - SpiceMarshaller *sub_list_m; > - > - marshaller = red_channel_client_get_marshaller(rcc); > - inval_m = spice_marshaller_get_submarshaller(marshaller); > - > - display_marshal_sub_msg_inval_list(inval_m, free_list); > - > - if (free_list->wait.header.wait_count) { > - wait_m = spice_marshaller_get_submarshaller(marshaller); > - display_marshal_sub_msg_inval_list_wait(wait_m, free_list); > - sub_list_len++; > - } > - > - sub_list_m = spice_marshaller_get_submarshaller(marshaller); > - spice_marshaller_add_uint16(sub_list_m, sub_list_len); > - if (wait_m) { > - spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(wait_m)); > - } > - spice_marshaller_add_uint32(sub_list_m, spice_marshaller_get_offset(inval_m)); > - red_channel_client_set_header_sub_list(rcc, spice_marshaller_get_offset(sub_list_m)); > -} > - > -/* use mini header and SPICE_MSG_LIST */ > -static inline void display_channel_send_free_list(RedChannelClient *rcc) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - FreeList *free_list = &dcc->send_data.free_list; > - int sub_list_len = 1; > - SpiceMarshaller *urgent_marshaller; > - SpiceMarshaller *wait_m = NULL; > - SpiceMarshaller *inval_m; > - uint32_t sub_arr_offset; > - uint32_t wait_offset = 0; > - uint32_t inval_offset = 0; > - int i; > - > - urgent_marshaller = red_channel_client_switch_to_urgent_sender(rcc); > - for (i = 0; i < dcc->send_data.num_pixmap_cache_items; i++) { > - int dummy; > - /* When using the urgent marshaller, the serial number of the message that is > - * going to be sent right after the SPICE_MSG_LIST, is increased by one. > - * But all this message pixmaps cache references used its old serial. > - * we use pixmap_cache_items to collect these pixmaps, and we update their serial > - * by calling pixmap_cache_hit. */ > - dcc_pixmap_cache_hit(dcc, dcc->send_data.pixmap_cache_items[i], &dummy); > - } > - > - if (free_list->wait.header.wait_count) { > - red_channel_client_init_send_data(rcc, SPICE_MSG_LIST, NULL); > - } else { /* only one message, no need for a list */ > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_LIST, NULL); > - spice_marshall_msg_display_inval_list(urgent_marshaller, free_list->res); > - return; > - } > - > - inval_m = spice_marshaller_get_submarshaller(urgent_marshaller); > - display_marshal_sub_msg_inval_list(inval_m, free_list); > - > - if (free_list->wait.header.wait_count) { > - wait_m = spice_marshaller_get_submarshaller(urgent_marshaller); > - display_marshal_sub_msg_inval_list_wait(wait_m, free_list); > - sub_list_len++; > - } > - > - sub_arr_offset = sub_list_len * sizeof(uint32_t); > - > - spice_marshaller_add_uint16(urgent_marshaller, sub_list_len); > - inval_offset = spice_marshaller_get_offset(inval_m); // calc the offset before > - // adding the sub list > - // offsets array to the marshaller > - /* adding the array of offsets */ > - if (wait_m) { > - wait_offset = spice_marshaller_get_offset(wait_m); > - spice_marshaller_add_uint32(urgent_marshaller, wait_offset + sub_arr_offset); > - } > - spice_marshaller_add_uint32(urgent_marshaller, inval_offset + sub_arr_offset); > -} > - > -static inline void display_begin_send_message(RedChannelClient *rcc) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - FreeList *free_list = &dcc->send_data.free_list; > - > - if (free_list->res->count) { > - int sync_count = 0; > - int i; > - > - for (i = 0; i < MAX_CACHE_CLIENTS; i++) { > - if (i != dcc->common.id && free_list->sync[i] != 0) { > - free_list->wait.header.wait_list[sync_count].channel_type = SPICE_CHANNEL_DISPLAY; > - free_list->wait.header.wait_list[sync_count].channel_id = i; > - free_list->wait.header.wait_list[sync_count++].message_serial = free_list->sync[i]; > - } > - } > - free_list->wait.header.wait_count = sync_count; > - > - if (rcc->is_mini_header) { > - display_channel_send_free_list(rcc); > - } else { > - display_channel_send_free_list_legacy(rcc); > - } > - } > - red_channel_client_begin_send_message(rcc); > -} > - > -static inline int red_marshall_stream_data(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, Drawable *drawable) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - DisplayChannel *display = DCC_TO_DC(dcc); > - Stream *stream = drawable->stream; > - SpiceImage *image; > - uint32_t frame_mm_time; > - int n; > - int width, height; > - int ret; > - > - if (!stream) { > - spice_assert(drawable->sized_stream); > - stream = drawable->sized_stream; > - } > - spice_assert(drawable->red_drawable->type == QXL_DRAW_COPY); > - > - image = drawable->red_drawable->u.copy.src_bitmap; > - > - if (image->descriptor.type != SPICE_IMAGE_TYPE_BITMAP) { > - return FALSE; > - } > - > - if (drawable->sized_stream) { > - if (red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_SIZED_STREAM)) { > - SpiceRect *src_rect = &drawable->red_drawable->u.copy.src_area; > - > - width = src_rect->right - src_rect->left; > - height = src_rect->bottom - src_rect->top; > - } else { > - return FALSE; > - } > - } else { > - width = stream->width; > - height = stream->height; > - } > - > - StreamAgent *agent = &dcc->stream_agents[get_stream_id(display, stream)]; > - uint64_t time_now = red_get_monotonic_time(); > - size_t outbuf_size; > - > - if (!dcc->use_mjpeg_encoder_rate_control) { > - if (time_now - agent->last_send_time < (1000 * 1000 * 1000) / agent->fps) { > - agent->frames--; > -#ifdef STREAM_STATS > - agent->stats.num_drops_fps++; > -#endif > - return TRUE; > - } > - } > - > - /* workaround for vga streams */ > - frame_mm_time = drawable->red_drawable->mm_time ? > - drawable->red_drawable->mm_time : > - reds_get_mm_time(); > - > - outbuf_size = dcc->send_data.stream_outbuf_size; > - ret = mjpeg_encoder_encode_frame(agent->mjpeg_encoder, > - &image->u.bitmap, width, height, > - &drawable->red_drawable->u.copy.src_area, > - stream->top_down, frame_mm_time, > - &dcc->send_data.stream_outbuf, > - &outbuf_size, &n); > - switch (ret) { > - case MJPEG_ENCODER_FRAME_DROP: > - spice_assert(dcc->use_mjpeg_encoder_rate_control); > -#ifdef STREAM_STATS > - agent->stats.num_drops_fps++; > -#endif > - return TRUE; > - case MJPEG_ENCODER_FRAME_UNSUPPORTED: > - return FALSE; > - case MJPEG_ENCODER_FRAME_ENCODE_DONE: > - break; > - default: > - spice_error("bad return value (%d) from mjpeg_encoder_encode_frame", ret); > - return FALSE; > - } > - dcc->send_data.stream_outbuf_size = outbuf_size; > - > - if (!drawable->sized_stream) { > - SpiceMsgDisplayStreamData stream_data; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA, NULL); > - > - stream_data.base.id = get_stream_id(display, stream); > - stream_data.base.multi_media_time = frame_mm_time; > - stream_data.data_size = n; > - > - spice_marshall_msg_display_stream_data(base_marshaller, &stream_data); > - } else { > - SpiceMsgDisplayStreamDataSized stream_data; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, NULL); > - > - stream_data.base.id = get_stream_id(display, stream); > - stream_data.base.multi_media_time = frame_mm_time; > - stream_data.data_size = n; > - stream_data.width = width; > - stream_data.height = height; > - stream_data.dest = drawable->red_drawable->bbox; > - > - spice_debug("stream %d: sized frame: dest ==> ", stream_data.base.id); > - rect_debug(&stream_data.dest); > - spice_marshall_msg_display_stream_data_sized(base_marshaller, &stream_data); > - } > - spice_marshaller_add_ref(base_marshaller, > - dcc->send_data.stream_outbuf, n); > - agent->last_send_time = time_now; > -#ifdef STREAM_STATS > - agent->stats.num_frames_sent++; > - agent->stats.size_sent += n; > - agent->stats.end = frame_mm_time; > -#endif > - > - return TRUE; > -} > - > -static inline void marshall_qxl_drawable(RedChannelClient *rcc, > - SpiceMarshaller *m, DrawablePipeItem *dpi) > -{ > - Drawable *item = dpi->drawable; > - DisplayChannel *display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > - > - spice_assert(display_channel && rcc); > - /* allow sized frames to be streamed, even if they where replaced by another frame, since > - * newer frames might not cover sized frames completely if they are bigger */ > - if ((item->stream || item->sized_stream) && red_marshall_stream_data(rcc, m, item)) { > - return; > - } > - if (!display_channel->enable_jpeg) > - red_marshall_qxl_drawable(rcc, m, dpi); > - else > - red_lossy_marshall_qxl_drawable(rcc, m, dpi); > -} > - > -static inline void red_marshall_inval_palette(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - CacheItem *cache_item) > -{ > - SpiceMsgDisplayInvalOne inval_one; > - > - red_channel_client_init_send_data(rcc, cache_item->inval_type, NULL); > - inval_one.id = *(uint64_t *)&cache_item->id; > - > - spice_marshall_msg_display_inval_palette(base_marshaller, &inval_one); > - > -} > - > -static void display_channel_marshall_migrate_data_surfaces(DisplayChannelClient *dcc, > - SpiceMarshaller *m, > - int lossy) > -{ > - SpiceMarshaller *m2 = spice_marshaller_get_ptr_submarshaller(m, 0); > - uint32_t *num_surfaces_created; > - uint32_t i; > - > - num_surfaces_created = (uint32_t *)spice_marshaller_reserve_space(m2, sizeof(uint32_t)); > - *num_surfaces_created = 0; > - for (i = 0; i < NUM_SURFACES; i++) { > - SpiceRect lossy_rect; > - > - if (!dcc->surface_client_created[i]) { > - continue; > - } > - spice_marshaller_add_uint32(m2, i); > - (*num_surfaces_created)++; > - > - if (!lossy) { > - continue; > - } > - region_extents(&dcc->surface_client_lossy_region[i], &lossy_rect); > - spice_marshaller_add_int32(m2, lossy_rect.left); > - spice_marshaller_add_int32(m2, lossy_rect.top); > - spice_marshaller_add_int32(m2, lossy_rect.right); > - spice_marshaller_add_int32(m2, lossy_rect.bottom); > - } > -} > - > -static void display_channel_marshall_migrate_data(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller) > -{ > - DisplayChannel *display_channel; > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMigrateDataDisplay display_data = {0,}; > - > - display_channel = SPICE_CONTAINEROF(rcc->channel, DisplayChannel, common.base); > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_MIGRATE_DATA, NULL); > - spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_MAGIC); > - spice_marshaller_add_uint32(base_marshaller, SPICE_MIGRATE_DATA_DISPLAY_VERSION); > - > - spice_assert(dcc->pixmap_cache); > - spice_assert(MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == 4 && > - MIGRATE_DATA_DISPLAY_MAX_CACHE_CLIENTS == MAX_CACHE_CLIENTS); > - > - display_data.message_serial = red_channel_client_get_message_serial(rcc); > - display_data.low_bandwidth_setting = dcc->common.is_low_bandwidth; > - > - display_data.pixmap_cache_freezer = pixmap_cache_freeze(dcc->pixmap_cache); > - display_data.pixmap_cache_id = dcc->pixmap_cache->id; > - display_data.pixmap_cache_size = dcc->pixmap_cache->size; > - memcpy(display_data.pixmap_cache_clients, dcc->pixmap_cache->sync, > - sizeof(display_data.pixmap_cache_clients)); > - > - spice_assert(dcc->glz_dict); > - dcc_freeze_glz(dcc); > - display_data.glz_dict_id = dcc->glz_dict->id; > - glz_enc_dictionary_get_restore_data(dcc->glz_dict->dict, > - &display_data.glz_dict_data, > - &dcc->glz_data.usr); > - > - /* all data besided the surfaces ref */ > - spice_marshaller_add(base_marshaller, > - (uint8_t *)&display_data, sizeof(display_data) - sizeof(uint32_t)); > - display_channel_marshall_migrate_data_surfaces(dcc, base_marshaller, > - display_channel->enable_jpeg); > -} > - > -static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMsgWaitForChannels wait; > - PixmapCache *pixmap_cache; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_WAIT_FOR_CHANNELS, NULL); > - pixmap_cache = dcc->pixmap_cache; > - > - pthread_mutex_lock(&pixmap_cache->lock); > - > - wait.wait_count = 1; > - wait.wait_list[0].channel_type = SPICE_CHANNEL_DISPLAY; > - wait.wait_list[0].channel_id = pixmap_cache->generation_initiator.client; > - wait.wait_list[0].message_serial = pixmap_cache->generation_initiator.message; > - dcc->pixmap_cache_generation = pixmap_cache->generation; > - dcc->pending_pixmaps_sync = FALSE; > - > - pthread_mutex_unlock(&pixmap_cache->lock); > - > - spice_marshall_msg_wait_for_channels(base_marshaller, &wait); > -} > - > -static void dcc_pixmap_cache_reset(DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data) > -{ > - PixmapCache *cache = dcc->pixmap_cache; > - uint8_t wait_count; > - uint64_t serial; > - uint32_t i; > - > - serial = red_channel_client_get_message_serial(RED_CHANNEL_CLIENT(dcc)); > - pthread_mutex_lock(&cache->lock); > - pixmap_cache_clear(cache); > - > - dcc->pixmap_cache_generation = ++cache->generation; > - cache->generation_initiator.client = dcc->common.id; > - cache->generation_initiator.message = serial; > - cache->sync[dcc->common.id] = serial; > - > - wait_count = 0; > - for (i = 0; i < MAX_CACHE_CLIENTS; i++) { > - if (cache->sync[i] && i != dcc->common.id) { > - sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY; > - sync_data->wait_list[wait_count].channel_id = i; > - sync_data->wait_list[wait_count++].message_serial = cache->sync[i]; > - } > - } > - sync_data->wait_count = wait_count; > - pthread_mutex_unlock(&cache->lock); > -} > - > -static void display_channel_marshall_reset_cache(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMsgWaitForChannels wait; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL); > - dcc_pixmap_cache_reset(dcc, &wait); > - > - spice_marshall_msg_display_inval_all_pixmaps(base_marshaller, > - &wait); > -} > - > -static void red_marshall_image(RedChannelClient *rcc, SpiceMarshaller *m, ImageItem *item) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - DisplayChannel *display = DCC_TO_DC(dcc); > - SpiceImage red_image; > - RedWorker *worker; > - SpiceBitmap bitmap; > - SpiceChunks *chunks; > - QRegion *surface_lossy_region; > - int comp_succeeded = FALSE; > - int lossy_comp = FALSE; > - int quic_comp = FALSE; > - SpiceImageCompression comp_mode; > - SpiceMsgDisplayDrawCopy copy; > - SpiceMarshaller *src_bitmap_out, *mask_bitmap_out; > - SpiceMarshaller *bitmap_palette_out, *lzplt_palette_out; > - > - spice_assert(rcc && display && item); > - worker = display->common.worker; > - > - QXL_SET_IMAGE_ID(&red_image, QXL_IMAGE_GROUP_RED, generate_uid(display)); > - red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP; > - red_image.descriptor.flags = item->image_flags; > - red_image.descriptor.width = item->width; > - red_image.descriptor.height = item->height; > - > - bitmap.format = item->image_format; > - bitmap.flags = 0; > - if (item->top_down) { > - bitmap.flags |= SPICE_BITMAP_FLAGS_TOP_DOWN; > - } > - bitmap.x = item->width; > - bitmap.y = item->height; > - bitmap.stride = item->stride; > - bitmap.palette = 0; > - bitmap.palette_id = 0; > - > - chunks = spice_chunks_new_linear(item->data, bitmap.stride * bitmap.y); > - bitmap.data = chunks; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->link); > - > - copy.base.surface_id = item->surface_id; > - copy.base.box.left = item->pos.x; > - copy.base.box.top = item->pos.y; > - copy.base.box.right = item->pos.x + bitmap.x; > - copy.base.box.bottom = item->pos.y + bitmap.y; > - copy.base.clip.type = SPICE_CLIP_TYPE_NONE; > - copy.data.rop_descriptor = SPICE_ROPD_OP_PUT; > - copy.data.src_area.left = 0; > - copy.data.src_area.top = 0; > - copy.data.src_area.right = bitmap.x; > - copy.data.src_area.bottom = bitmap.y; > - copy.data.scale_mode = 0; > - copy.data.src_bitmap = 0; > - copy.data.mask.flags = 0; > - copy.data.mask.flags = 0; > - copy.data.mask.pos.x = 0; > - copy.data.mask.pos.y = 0; > - copy.data.mask.bitmap = 0; > - > - spice_marshall_msg_display_draw_copy(m, ©, > - &src_bitmap_out, &mask_bitmap_out); > - > - compress_send_data_t comp_send_data = {0}; > - > - comp_mode = dcc->image_compression; > - > - if (((comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_LZ) || > - (comp_mode == SPICE_IMAGE_COMPRESSION_AUTO_GLZ)) && !bitmap_has_extra_stride(&bitmap)) { > - > - if (bitmap_fmt_has_graduality(item->image_format)) { > - BitmapGradualType grad_level; > - > - grad_level = bitmap_get_graduality_level(&bitmap); > - if (grad_level == BITMAP_GRADUAL_HIGH) { > - // if we use lz for alpha, the stride can't be extra > - lossy_comp = display->enable_jpeg && item->can_lossy; > - quic_comp = TRUE; > - } > - } > - } else if (comp_mode == SPICE_IMAGE_COMPRESSION_QUIC) { > - quic_comp = TRUE; > - } > - > - if (lossy_comp) { > - comp_succeeded = dcc_compress_image_jpeg(dcc, &red_image, > - &bitmap, &comp_send_data, > - worker->mem_slots.internal_groupslot_id); > - } else if (quic_comp) { > - comp_succeeded = dcc_compress_image_quic(dcc, &red_image, &bitmap, > - &comp_send_data, > - worker->mem_slots.internal_groupslot_id); > -#ifdef USE_LZ4 > - } else if (comp_mode == SPICE_IMAGE_COMPRESSION_LZ4 && > - bitmap_fmt_is_rgb(bitmap.format) && > - red_channel_client_test_remote_cap(&dcc->common.base, > - SPICE_DISPLAY_CAP_LZ4_COMPRESSION)) { > - comp_succeeded = dcc_compress_image_lz4(dcc, &red_image, &bitmap, > - &comp_send_data, > - worker->mem_slots.internal_groupslot_id); > -#endif > - } else if (comp_mode != SPICE_IMAGE_COMPRESSION_OFF) { > - comp_succeeded = dcc_compress_image_lz(dcc, &red_image, &bitmap, > - &comp_send_data, > - worker->mem_slots.internal_groupslot_id); > - } > - > - surface_lossy_region = &dcc->surface_client_lossy_region[item->surface_id]; > - if (comp_succeeded) { > - spice_marshall_Image(src_bitmap_out, &red_image, > - &bitmap_palette_out, &lzplt_palette_out); > - > - marshaller_add_compressed(src_bitmap_out, > - comp_send_data.comp_buf, comp_send_data.comp_buf_size); > - > - if (lzplt_palette_out && comp_send_data.lzplt_palette) { > - spice_marshall_Palette(lzplt_palette_out, comp_send_data.lzplt_palette); > - } > - > - if (lossy_comp) { > - region_add(surface_lossy_region, ©.base.box); > - } else { > - region_remove(surface_lossy_region, ©.base.box); > - } > - } else { > - red_image.descriptor.type = SPICE_IMAGE_TYPE_BITMAP; > - red_image.u.bitmap = bitmap; > - > - spice_marshall_Image(src_bitmap_out, &red_image, > - &bitmap_palette_out, &lzplt_palette_out); > - spice_marshaller_add_ref(src_bitmap_out, item->data, > - bitmap.y * bitmap.stride); > - region_remove(surface_lossy_region, ©.base.box); > - } > - spice_chunks_destroy(chunks); > -} > - > -static void red_display_marshall_upgrade(RedChannelClient *rcc, SpiceMarshaller *m, > - UpgradeItem *item) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - RedDrawable *red_drawable; > - SpiceMsgDisplayDrawCopy copy; > - SpiceMarshaller *src_bitmap_out, *mask_bitmap_out; > - > - spice_assert(rcc && rcc->channel && item && item->drawable); > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_DRAW_COPY, &item->base); > - > - red_drawable = item->drawable->red_drawable; > - spice_assert(red_drawable->type == QXL_DRAW_COPY); > - spice_assert(red_drawable->u.copy.rop_descriptor == SPICE_ROPD_OP_PUT); > - spice_assert(red_drawable->u.copy.mask.bitmap == 0); > - > - copy.base.surface_id = 0; > - copy.base.box = red_drawable->bbox; > - copy.base.clip.type = SPICE_CLIP_TYPE_RECTS; > - copy.base.clip.rects = item->rects; > - copy.data = red_drawable->u.copy; > - > - spice_marshall_msg_display_draw_copy(m, ©, > - &src_bitmap_out, &mask_bitmap_out); > - > - fill_bits(dcc, src_bitmap_out, copy.data.src_bitmap, item->drawable, FALSE); > -} > - > -static void red_display_marshall_stream_start(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, StreamAgent *agent) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - Stream *stream = agent->stream; > - > - agent->last_send_time = 0; > - spice_assert(stream); > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CREATE, NULL); > - SpiceMsgDisplayStreamCreate stream_create; > - SpiceClipRects clip_rects; > - > - stream_create.surface_id = 0; > - stream_create.id = get_stream_id(DCC_TO_DC(dcc), stream); > - stream_create.flags = stream->top_down ? SPICE_STREAM_FLAGS_TOP_DOWN : 0; > - stream_create.codec_type = SPICE_VIDEO_CODEC_TYPE_MJPEG; > - > - stream_create.src_width = stream->width; > - stream_create.src_height = stream->height; > - stream_create.stream_width = stream_create.src_width; > - stream_create.stream_height = stream_create.src_height; > - stream_create.dest = stream->dest_area; > - > - if (stream->current) { > - RedDrawable *red_drawable = stream->current->red_drawable; > - stream_create.clip = red_drawable->clip; > - } else { > - stream_create.clip.type = SPICE_CLIP_TYPE_RECTS; > - clip_rects.num_rects = 0; > - stream_create.clip.rects = &clip_rects; > - } > - > - stream_create.stamp = 0; > - > - spice_marshall_msg_display_stream_create(base_marshaller, &stream_create); > -} > - > -static void red_display_marshall_stream_clip(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - StreamClipItem *item) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - StreamAgent *agent = item->stream_agent; > - > - spice_assert(agent->stream); > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_CLIP, &item->base); > - SpiceMsgDisplayStreamClip stream_clip; > - > - stream_clip.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > - stream_clip.clip.type = item->clip_type; > - stream_clip.clip.rects = item->rects; > - > - spice_marshall_msg_display_stream_clip(base_marshaller, &stream_clip); > -} > - > -static void red_display_marshall_stream_end(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, StreamAgent* agent) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMsgDisplayStreamDestroy destroy; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_DESTROY, NULL); > - destroy.id = get_stream_id(DCC_TO_DC(dcc), agent->stream); > - stream_agent_stop(agent); > - spice_marshall_msg_display_stream_destroy(base_marshaller, &destroy); > -} > - > -static void red_marshall_surface_create(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, SpiceMsgSurfaceCreate *surface_create) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - > - region_init(&dcc->surface_client_lossy_region[surface_create->surface_id]); > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_CREATE, NULL); > - > - spice_marshall_msg_display_surface_create(base_marshaller, surface_create); > -} > - > -static void red_marshall_surface_destroy(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, uint32_t surface_id) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - SpiceMsgSurfaceDestroy surface_destroy; > - > - region_destroy(&dcc->surface_client_lossy_region[surface_id]); > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_SURFACE_DESTROY, NULL); > - > - surface_destroy.surface_id = surface_id; > - > - spice_marshall_msg_display_surface_destroy(base_marshaller, &surface_destroy); > -} > - > -static void red_marshall_monitors_config(RedChannelClient *rcc, SpiceMarshaller *base_marshaller, > - MonitorsConfig *monitors_config) > -{ > - int heads_size = sizeof(SpiceHead) * monitors_config->count; > - int i; > - SpiceMsgDisplayMonitorsConfig *msg = spice_malloc0(sizeof(*msg) + heads_size); > - int count = 0; // ignore monitors_config->count, it may contain zero width monitors, remove them now > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_MONITORS_CONFIG, NULL); > - for (i = 0 ; i < monitors_config->count; ++i) { > - if (monitors_config->heads[i].width == 0 || monitors_config->heads[i].height == 0) { > - continue; > - } > - msg->heads[count].id = monitors_config->heads[i].id; > - msg->heads[count].surface_id = monitors_config->heads[i].surface_id; > - msg->heads[count].width = monitors_config->heads[i].width; > - msg->heads[count].height = monitors_config->heads[i].height; > - msg->heads[count].x = monitors_config->heads[i].x; > - msg->heads[count].y = monitors_config->heads[i].y; > - count++; > - } > - msg->count = count; > - msg->max_allowed = monitors_config->max_allowed; > - spice_marshall_msg_display_monitors_config(base_marshaller, msg); > - free(msg); > -} > - > -static void red_marshall_stream_activate_report(RedChannelClient *rcc, > - SpiceMarshaller *base_marshaller, > - uint32_t stream_id) > -{ > - DisplayChannelClient *dcc = RCC_TO_DCC(rcc); > - StreamAgent *agent = &dcc->stream_agents[stream_id]; > - SpiceMsgDisplayStreamActivateReport msg; > - > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_STREAM_ACTIVATE_REPORT, NULL); > - msg.stream_id = stream_id; > - msg.unique_id = agent->report_id; > - msg.max_window_size = RED_STREAM_CLIENT_REPORT_WINDOW; > - msg.timeout_ms = RED_STREAM_CLIENT_REPORT_TIMEOUT; > - spice_marshall_msg_display_stream_activate_report(base_marshaller, &msg); > -} > - > -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); > - > - reset_send_data(dcc); > - switch (pipe_item->type) { > - case PIPE_ITEM_TYPE_DRAW: { > - DrawablePipeItem *dpi = SPICE_CONTAINEROF(pipe_item, DrawablePipeItem, dpi_pipe_item); > - marshall_qxl_drawable(rcc, m, dpi); > - break; > - } > - case PIPE_ITEM_TYPE_INVAL_ONE: > - red_marshall_inval_palette(rcc, m, (CacheItem *)pipe_item); > - break; > - case PIPE_ITEM_TYPE_STREAM_CREATE: { > - StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, create_item); > - red_display_marshall_stream_start(rcc, m, agent); > - break; > - } > - case PIPE_ITEM_TYPE_STREAM_CLIP: { > - StreamClipItem* clip_item = (StreamClipItem *)pipe_item; > - red_display_marshall_stream_clip(rcc, m, clip_item); > - break; > - } > - case PIPE_ITEM_TYPE_STREAM_DESTROY: { > - StreamAgent *agent = SPICE_CONTAINEROF(pipe_item, StreamAgent, destroy_item); > - red_display_marshall_stream_end(rcc, m, agent); > - break; > - } > - case PIPE_ITEM_TYPE_UPGRADE: > - red_display_marshall_upgrade(rcc, m, (UpgradeItem *)pipe_item); > - break; > - case PIPE_ITEM_TYPE_VERB: > - red_marshall_verb(rcc, (VerbItem*)pipe_item); > - break; > - case PIPE_ITEM_TYPE_MIGRATE_DATA: > - display_channel_marshall_migrate_data(rcc, m); > - break; > - case PIPE_ITEM_TYPE_IMAGE: > - red_marshall_image(rcc, m, (ImageItem *)pipe_item); > - break; > - case PIPE_ITEM_TYPE_PIXMAP_SYNC: > - display_channel_marshall_pixmap_sync(rcc, m); > - break; > - case PIPE_ITEM_TYPE_PIXMAP_RESET: > - display_channel_marshall_reset_cache(rcc, m); > - break; > - case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE: > - dcc_palette_cache_reset(dcc); > - red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PALETTES, NULL); > - break; > - case PIPE_ITEM_TYPE_CREATE_SURFACE: { > - SurfaceCreateItem *surface_create = SPICE_CONTAINEROF(pipe_item, SurfaceCreateItem, > - pipe_item); > - red_marshall_surface_create(rcc, m, &surface_create->surface_create); > - break; > - } > - case PIPE_ITEM_TYPE_DESTROY_SURFACE: { > - SurfaceDestroyItem *surface_destroy = SPICE_CONTAINEROF(pipe_item, SurfaceDestroyItem, > - pipe_item); > - red_marshall_surface_destroy(rcc, m, surface_destroy->surface_destroy.surface_id); > - break; > - } > - case PIPE_ITEM_TYPE_MONITORS_CONFIG: { > - MonitorsConfigItem *monconf_item = SPICE_CONTAINEROF(pipe_item, > - MonitorsConfigItem, pipe_item); > - red_marshall_monitors_config(rcc, m, monconf_item->monitors_config); > - break; > - } > - case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT: { > - StreamActivateReportItem *report_item = SPICE_CONTAINEROF(pipe_item, > - StreamActivateReportItem, > - pipe_item); > - red_marshall_stream_activate_report(rcc, m, report_item->stream_id); > - break; > - } > - default: > - spice_error("invalid pipe item type"); > - } > - > - dcc_release_item(dcc, pipe_item, FALSE); > - > - // a message is pending > - if (red_channel_client_send_message_pending(rcc)) { > - display_begin_send_message(rcc); > - } > -} > - > static inline void red_push(RedWorker *worker) > { > if (worker->cursor_channel) { > diff --git a/server/red_worker.h b/server/red_worker.h > index cbf91b9..bbbd523 100644 > --- a/server/red_worker.h > +++ b/server/red_worker.h > @@ -110,6 +110,8 @@ QXLInstance* red_worker_get_qxl(RedWorker *worker); > RedChannel* red_worker_get_cursor_channel(RedWorker *worker); > RedChannel* red_worker_get_display_channel(RedWorker *worker); > clockid_t red_worker_get_clockid(RedWorker *worker); > +RedMemSlotInfo* red_worker_get_memslot(RedWorker *worker); > + > void red_drawable_unref(RedWorker *worker, RedDrawable *red_drawable, > uint32_t group_id); > > -- > 2.4.3 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel -- Fabiano Fidêncio _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel