diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2010-06-01 10:30:52 +0300 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-06-09 11:41:02 +0200 |
commit | 2fc2f13be90b2246ddcb8ed0d3a669868a24f69e (patch) | |
tree | 7e173ab590ba3aad4ec95b9e025011181c351f2c | |
parent | 5d2ae66f5022187e0028a1d7ccf67fe48fdaa94b (diff) | |
download | spice-2fc2f13be90b2246ddcb8ed0d3a669868a24f69e.tar.gz spice-2fc2f13be90b2246ddcb8ed0d3a669868a24f69e.tar.xz spice-2fc2f13be90b2246ddcb8ed0d3a669868a24f69e.zip |
lossy surface regions in the client: infrastructure for tracking and updating
-rw-r--r-- | server/red_worker.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/server/red_worker.c b/server/red_worker.c index aa3b2a52..bedb82bd 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -657,6 +657,7 @@ struct DisplayChannel { pthread_mutex_t glz_drawables_inst_to_free_lock; uint8_t surface_client_created[NUM_SURFACES]; + QRegion surface_client_lossy_region[NUM_SURFACES]; struct { union { @@ -1021,6 +1022,20 @@ typedef struct RedWorker { int jpeg_quality; } RedWorker; +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 void red_draw_qxl_drawable(RedWorker *worker, Drawable *drawable); static void red_current_flush(RedWorker *worker, int surface_id); static void display_channel_push(RedWorker *worker); @@ -6788,6 +6803,151 @@ static inline void red_display_reset_send_data(DisplayChannel *channel) memset(channel->send_data.free_list.sync, 0, sizeof(channel->send_data.free_list.sync)); } +/* set area=NULL for testing the whole surface */ +static int is_surface_area_lossy(DisplayChannel *display_channel, uint32_t surface_id, + const SpiceRect *area, SpiceRect *out_lossy_area) +{ + RedSurface *surface; + QRegion *surface_lossy_region; + QRegion lossy_region; + + validate_surface(display_channel->base.worker, surface_id); + surface = &display_channel->base.worker->surfaces[surface_id]; + surface_lossy_region = &display_channel->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(DisplayChannel *display_channel, SPICE_ADDRESS bitmap, SpiceRect *area, + Drawable *drawable, BitmapData *out_data) +{ + RedWorker *worker = display_channel->base.worker; + QXLImage *qxl_image; + + if (bitmap == 0) { + // self bitmap + out_data->type = BITMAP_DATA_TYPE_BITMAP; + return FALSE; + } + + qxl_image = (QXLImage *)get_virt(&worker->mem_slots, bitmap, sizeof(QXLImage), + drawable->group_id); + + if ((qxl_image->descriptor.flags & QXL_IMAGE_CACHE)) { + int is_hit_lossy; + + out_data->id = qxl_image->descriptor.id; + if (pixmap_cache_hit(display_channel->pixmap_cache, qxl_image->descriptor.id, + &is_hit_lossy, display_channel)) { + 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 (qxl_image->descriptor.type != SPICE_IMAGE_TYPE_SURFACE) { + return FALSE; + } + + out_data->type = BITMAP_DATA_TYPE_SURFACE; + out_data->id = qxl_image->surface_image.surface_id; + + if (is_surface_area_lossy(display_channel, qxl_image->surface_image.surface_id, + area, &out_data->lossy_rect)) + { + return TRUE; + } else { + return FALSE; + } +} + +SPICE_GNUC_UNUSED static int is_brush_lossy(DisplayChannel *display_channel, SpiceBrush *brush, + Drawable *drawable, BitmapData *out_data) +{ + if (brush->type == SPICE_BRUSH_TYPE_PATTERN) { + return is_bitmap_lossy(display_channel, brush->u.pattern.pat, NULL, + drawable, out_data); + } else { + out_data->type = BITMAP_DATA_TYPE_INVALID; + return FALSE; + } +} + +SPICE_GNUC_UNUSED static void surface_lossy_region_update(RedWorker *worker, DisplayChannel *display_channel, + Drawable *item, int has_mask, int lossy) +{ + QRegion *surface_lossy_region; + QXLDrawable *drawable; + + if (has_mask && !lossy) { + return; + } + + surface_lossy_region = &display_channel->surface_client_lossy_region[item->surface_id]; + drawable = item->qxl_drawable; + + if ((drawable->clip.type == SPICE_CLIP_TYPE_NONE) || + ((drawable->clip.type == SPICE_CLIP_TYPE_PATH) && lossy)) { + if (!lossy) { + region_remove(surface_lossy_region, &drawable->bbox); + } else { + region_add(surface_lossy_region, &drawable->bbox); + } + } else 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); + add_clip_rects(worker, &clip_rgn, + drawable->clip.data + SPICE_OFFSETOF(QXLClipRects, chunk), + item->group_id); + 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 SPICE_CLIP_TYPE_PATH and lossless: leave the area as is +} + static inline void red_send_qxl_drawable(RedWorker *worker, DisplayChannel *display_channel, Drawable *item) { |