summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/sw_canvas.c64
-rw-r--r--server/red_worker.c163
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, &copy.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;