diff options
-rw-r--r-- | common/sw_canvas.c | 64 | ||||
-rw-r--r-- | server/red_worker.c | 163 |
2 files changed, 149 insertions, 78 deletions
diff --git a/common/sw_canvas.c b/common/sw_canvas.c index a4edfa2a..a92cff65 100644 --- a/common/sw_canvas.c +++ b/common/sw_canvas.c @@ -453,16 +453,15 @@ static void __scale_image(SpiceCanvas *spice_canvas, { SwCanvas *canvas = (SwCanvas *)spice_canvas; pixman_transform_t transform; - double sx, sy; + pixman_fixed_t fsx, fsy; + int scaled_src_x, scaled_src_y; - sx = (double)(src_width) / (dest_width); - sy = (double)(src_height) / (dest_height); + fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width; + fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height; pixman_image_set_clip_region32(canvas->image, region); - pixman_transform_init_scale(&transform, - pixman_double_to_fixed(sx), - pixman_double_to_fixed(sy)); + pixman_transform_init_scale(&transform, fsx, fsy); pixman_image_set_transform(src, &transform); pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); @@ -473,9 +472,12 @@ static void __scale_image(SpiceCanvas *spice_canvas, PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD, NULL, 0); + scaled_src_x = ((pixman_fixed_48_16_t)src_x * 65536 + fsx/2 ) / fsx; + scaled_src_y = ((pixman_fixed_48_16_t)src_y * 65536 + fsy/2 ) / fsy; + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, canvas->image, - ROUND(src_x / sx), ROUND(src_y / sy), /* src */ + scaled_src_x, scaled_src_y, /* src */ 0, 0, /* mask */ dest_x, dest_y, /* dst */ dest_width, dest_height); @@ -527,10 +529,11 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas, pixman_image_t *scaled; pixman_box32_t *rects; int n_rects, i; - double sx, sy; + pixman_fixed_t fsx, fsy; + int scaled_src_x, scaled_src_y; - sx = (double)(src_width) / (dest_width); - sy = (double)(src_height) / (dest_height); + fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width; + fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height; scaled = pixman_image_create_bits(spice_pixman_image_get_format(src), dest_width, @@ -540,9 +543,7 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas, pixman_region32_translate(region, -dest_x, -dest_y); pixman_image_set_clip_region32(scaled, region); - pixman_transform_init_scale(&transform, - pixman_double_to_fixed(sx), - pixman_double_to_fixed(sy)); + pixman_transform_init_scale(&transform, fsx, fsy); pixman_image_set_transform(src, &transform); pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); @@ -553,9 +554,12 @@ static void __scale_image_rop(SpiceCanvas *spice_canvas, PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD, NULL, 0); + scaled_src_x = ((pixman_fixed_48_16_t)src_x * 65536 + fsx/2 ) / fsx; + scaled_src_y = ((pixman_fixed_48_16_t)src_y * 65536 + fsy/2 ) / fsy; + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, scaled, - ROUND(src_x / sx), ROUND(src_y / sy), /* src */ + scaled_src_x, scaled_src_y, /* src */ 0, 0, /* mask */ 0, 0, /* dst */ dest_width, @@ -724,18 +728,17 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas, SwCanvas *canvas = (SwCanvas *)spice_canvas; pixman_transform_t transform; pixman_image_t *mask, *dest; - double sx, sy; + pixman_fixed_t fsx, fsy; + int scaled_src_x, scaled_src_y; - sx = (double)(src_width) / (dest_width); - sy = (double)(src_height) / (dest_height); + fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width; + fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height; dest = canvas_get_as_surface(canvas, dest_has_alpha); pixman_image_set_clip_region32(dest, region); - pixman_transform_init_scale(&transform, - pixman_double_to_fixed(sx), - pixman_double_to_fixed(sy)); + pixman_transform_init_scale(&transform, fsx, fsy); mask = NULL; if (overall_alpha != 0xff) { @@ -753,9 +756,12 @@ static void __blend_scale_image(SpiceCanvas *spice_canvas, PIXMAN_FILTER_NEAREST : PIXMAN_FILTER_GOOD, NULL, 0); + scaled_src_x = ((pixman_fixed_48_16_t)src_x * 65536 + fsx/2 ) / fsx; + scaled_src_y = ((pixman_fixed_48_16_t)src_y * 65536 + fsy/2 ) / fsy; + pixman_image_composite32(PIXMAN_OP_OVER, src, mask, dest, - ROUND(src_x / sx), ROUND(src_y / sy), /* src */ + scaled_src_x, scaled_src_y, /* src */ 0, 0, /* mask */ dest_x, dest_y, /* dst */ dest_width, dest_height); @@ -881,10 +887,11 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas, pixman_image_t *scaled; pixman_box32_t *rects; int n_rects, i; - double sx, sy; + pixman_fixed_t fsx, fsy; + int scaled_src_x, scaled_src_y; - sx = (double)(src_width) / (dest_width); - sy = (double)(src_height) / (dest_height); + fsx = ((pixman_fixed_48_16_t) src_width * 65536) / dest_width; + fsy = ((pixman_fixed_48_16_t) src_height * 65536) / dest_height; scaled = pixman_image_create_bits(spice_pixman_image_get_format (src), dest_width, @@ -894,9 +901,7 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas, pixman_region32_translate(region, -dest_x, -dest_y); pixman_image_set_clip_region32(scaled, region); - pixman_transform_init_scale(&transform, - pixman_double_to_fixed(sx), - pixman_double_to_fixed(sy)); + pixman_transform_init_scale(&transform, fsx, fsy); pixman_image_set_transform(src, &transform); pixman_image_set_repeat(src, PIXMAN_REPEAT_NONE); @@ -904,9 +909,12 @@ static void __colorkey_scale_image(SpiceCanvas *spice_canvas, PIXMAN_FILTER_NEAREST, NULL, 0); + scaled_src_x = ((pixman_fixed_48_16_t)src_x * 65536 + fsx/2 ) / fsx; + scaled_src_y = ((pixman_fixed_48_16_t)src_y * 65536 + fsy/2 ) / fsy; + pixman_image_composite32(PIXMAN_OP_SRC, src, NULL, scaled, - ROUND(src_x / sx), ROUND(src_y / sy), /* src */ + scaled_src_x, scaled_src_y, /* src */ 0, 0, /* mask */ 0, 0, /* dst */ dest_width, diff --git a/server/red_worker.c b/server/red_worker.c index 3efaa3e4..75760870 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -74,6 +74,9 @@ #define DETACH_TIMEOUT 15000000000ULL //nano #define DETACH_SLEEP_DURATION 10000 //micro +#define CHANNEL_PUSH_TIMEOUT 30000000000ULL //nano +#define CHANNEL_PUSH_SLEEP_DURATION 10000 //micro + #define DISPLAY_CLIENT_TIMEOUT 15000000000ULL //nano #define DISPLAY_CLIENT_RETRY_INTERVAL 10000 //micro @@ -979,6 +982,7 @@ static void reset_rate(StreamAgent *stream_agent); static BitmapGradualType _get_bitmap_graduality_level(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id); static inline int _stride_is_extra(SpiceBitmap *bitmap); static void red_disconnect_cursor(RedChannel *channel); +static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item); #ifdef DUMP_BITMAP static void dump_bitmap(RedWorker *worker, SpiceBitmap *bitmap, uint32_t group_id); @@ -1489,19 +1493,19 @@ static inline void red_destroy_surface(RedWorker *worker, uint32_t surface_id) if (surface_id == 0) { red_reset_stream_trace(worker); } - if (surface->context.canvas) { - surface->context.canvas->ops->destroy(surface->context.canvas); - if (surface->create.info) { - worker->qxl->st->qif->release_resource(worker->qxl, surface->create); - } - if (surface->destroy.info) { - worker->qxl->st->qif->release_resource(worker->qxl, surface->destroy); - } + ASSERT(surface->context.canvas); - region_destroy(&surface->draw_dirty_region); - surface->context.canvas = NULL; - red_destroy_surface_item(worker, surface_id); + surface->context.canvas->ops->destroy(surface->context.canvas); + if (surface->create.info) { + worker->qxl->st->qif->release_resource(worker->qxl, surface->create); } + if (surface->destroy.info) { + worker->qxl->st->qif->release_resource(worker->qxl, surface->destroy); + } + + region_destroy(&surface->draw_dirty_region); + surface->context.canvas = NULL; + red_destroy_surface_item(worker, surface_id); PANIC_ON(!ring_is_empty(&surface->depend_on_me)); } @@ -1780,7 +1784,7 @@ static void red_current_clear(RedWorker *worker, int surface_id) } } -static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface_id) +static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface_id, int force) { Ring *ring; PipeItem *item; @@ -1790,33 +1794,53 @@ static void red_clear_surface_drawables_from_pipe(RedWorker *worker, int surface return; } + /* removing the newest drawables that their destination is surface_id and + no other drawable depends on them */ + ring = &worker->display_channel->base.pipe; item = (PipeItem *) ring; while ((item = (PipeItem *)ring_next(ring, (RingItem *)item))) { + Drawable *drawable; + int depend_found = FALSE; if (item->type == PIPE_ITEM_TYPE_DRAW) { - PipeItem *tmp_item; - Drawable *drawable; - drawable = SPICE_CONTAINEROF(item, Drawable, pipe_item); + } else if (item->type == PIPE_ITEM_TYPE_UPGRADE) { + drawable = ((UpgradeItem *)item)->drawable; + } else { + continue; + } - for (x = 0; x < 3; ++x) { - if (drawable->surfaces_dest[x] == surface_id) { - return; - } + if (drawable->surface_id == surface_id) { + PipeItem *tmp_item = item; + item = (PipeItem *)ring_prev(ring, (RingItem *)item); + ring_remove(&tmp_item->link); + worker->display_channel->base.release_item(&worker->display_channel->base, tmp_item); + worker->display_channel->base.pipe_size--; + + if (!item) { + item = (PipeItem *)ring; } + continue; + } - if (drawable->surface_id == surface_id) { - tmp_item = item; - item = (PipeItem *)ring_prev(ring, (RingItem *)item); - ring_remove(&tmp_item->link); - release_drawable(worker, drawable); - worker->display_channel->base.pipe_size--; + for (x = 0; x < 3; ++x) { + if (drawable->surfaces_dest[x] == surface_id) { + depend_found = TRUE; + break; + } + } - if (!item) { - item = (PipeItem *)ring; - } + if (depend_found) { + if (force) { + break; + } else { + return; } - } + } + } + + if (item) { + red_wait_pipe_item_sent(&worker->display_channel->base, item); } } @@ -3503,8 +3527,11 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface PANIC_ON(!red_surface->context.canvas); set_surface_release_info(worker, surface_id, 0, surface->release_info, group_id); red_handle_depends_on_target_surface(worker, surface_id); + /* note that red_handle_depends_on_target_surface must be called before red_current_clear. + otherwise "current" will hold items that other drawables may depend on, and then + red_current_clear will remove them from the pipe. */ red_current_clear(worker, surface_id); - red_clear_surface_drawables_from_pipe(worker, surface_id); + red_clear_surface_drawables_from_pipe(worker, surface_id, FALSE); red_destroy_surface(worker, surface_id); break; default: @@ -7855,6 +7882,7 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item) 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; } @@ -7956,7 +7984,8 @@ static void red_send_image(DisplayChannel *display_channel, ImageItem *item) spice_marshall_Image(src_bitmap_out, &red_image, &bitmap_palette_out, &lzplt_palette_out); - spice_marshaller_add_ref(m, item->data, bitmap.y * bitmap.stride); + spice_marshaller_add_ref(src_bitmap_out, item->data, + bitmap.y * bitmap.stride); region_remove(surface_lossy_region, ©.base.box); } display_begin_send_message(display_channel, &item->link); @@ -8798,13 +8827,6 @@ static inline void flush_all_qxl_commands(RedWorker *worker) flush_cursor_commands(worker); } -static inline void red_flush_surface_pipe(RedWorker *worker) -{ - if (worker->display_channel) { - display_channel_push(worker); - } -} - static void push_new_primary_surface(RedWorker *worker) { DisplayChannel *display_channel; @@ -9628,6 +9650,48 @@ static void red_wait_outgoing_item(RedChannel *channel) red_unref_channel(channel); } +static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item) +{ + uint64_t end_time; + int item_in_pipe; + + if (!channel) { + return; + } + + red_printf(""); + red_ref_channel(channel); + channel->hold_item(item); + + end_time = red_now() + CHANNEL_PUSH_TIMEOUT; + + if (channel->send_data.blocked) { + red_receive(channel); + red_send_data(channel, NULL); + } + // todo: different push for each channel + red_push(channel->worker); + + while((item_in_pipe = ring_item_is_linked(&item->link)) && (red_now() < end_time)) { + usleep(CHANNEL_PUSH_SLEEP_DURATION); + red_receive(channel); + red_send_data(channel, NULL); + red_push(channel->worker); + } + + if (item_in_pipe) { + red_printf("timeout"); + channel->disconnect(channel); + } else { + if (channel->send_data.item == item) { + red_wait_outgoing_item(channel); + } + } + + channel->release_item(channel, item); + red_unref_channel(channel); +} + static inline void handle_dev_update(RedWorker *worker) { RedWorkerMessage message; @@ -9691,12 +9755,18 @@ static inline void handle_dev_del_memslot(RedWorker *worker) static inline void destroy_surface_wait(RedWorker *worker, int surface_id) { - if (worker->surfaces[surface_id].context.canvas) { - red_handle_depends_on_target_surface(worker, surface_id); + if (!worker->surfaces[surface_id].context.canvas) { + return; } - red_flush_surface_pipe(worker); + + red_handle_depends_on_target_surface(worker, surface_id); + /* note that red_handle_depends_on_target_surface must be called before red_current_clear. + otherwise "current" will hold items that other drawables may depend on, and then + red_current_clear will remove them from the pipe. */ red_current_clear(worker, surface_id); - red_clear_surface_drawables_from_pipe(worker, surface_id); + red_clear_surface_drawables_from_pipe(worker, surface_id, TRUE); + // in case that the pipe didn't contain any item that is dependent on the surface, but + // there is one during sending. red_wait_outgoing_item((RedChannel *)worker->display_channel); if (worker->display_channel) { ASSERT(!worker->display_channel->base.send_data.item); @@ -9730,15 +9800,13 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker) red_printf(""); flush_all_qxl_commands(worker); //to handle better - if (worker->surfaces[0].context.canvas) { - destroy_surface_wait(worker, 0); - } for (i = 0; i < NUM_SURFACES; ++i) { if (worker->surfaces[i].context.canvas) { destroy_surface_wait(worker, i); if (worker->surfaces[i].context.canvas) { red_destroy_surface(worker, i); } + ASSERT(!worker->surfaces[i].context.canvas); } } ASSERT(ring_is_empty(&worker->streams)); @@ -9759,11 +9827,6 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker) red_display_clear_glz_drawables(worker->display_channel); - //to handle better - for (i = 0; i < NUM_SURFACES; ++i) { - ASSERT(!worker->surfaces[i].context.canvas); - } - worker->cursor_visible = TRUE; worker->cursor_position.x = worker->cursor_position.y = 0; worker->cursor_trail_length = worker->cursor_trail_frequency = 0; |