diff options
author | Søren Sandmann Pedersen <ssp@redhat.com> | 2011-08-09 05:16:56 -0400 |
---|---|---|
committer | Søren Sandmann Pedersen <ssp@redhat.com> | 2011-08-10 07:15:12 -0400 |
commit | d4a7afd1327bcb2fbf127c1e5f6b4410b993d020 (patch) | |
tree | 36e8c6a670bea1d3110ad81fb92bd82d191170fd | |
parent | 2cb39c630347ae60617db9beb7e547f3876f77ef (diff) |
Transmit images in smaller chunks
This makes use of the 'chunks' feature of the SPICE protocol to send
images in chunks smaller than 512 * 512 bytes. This reduces the
likelihood of running out of memory when big image are transmitted.
-rw-r--r-- | src/qxl_image.c | 76 |
1 files changed, 60 insertions, 16 deletions
diff --git a/src/qxl_image.c b/src/qxl_image.c index af83bd6..2a9af56 100644 --- a/src/qxl_image.c +++ b/src/qxl_image.c @@ -123,6 +123,9 @@ remove_image_info (image_info_t *info) free (info); } +#define MAX(a,b) (((a) > (b))? (a) : (b)) +#define MIN(a,b) (((a) < (b))? (a) : (b)) + struct QXLImage * qxl_image_create (qxl_screen_t *qxl, const uint8_t *data, int x, int y, int width, int height, @@ -133,6 +136,7 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data, data += y * stride + x * Bpp; +#if 0 hash = hash_and_copy (data, stride, NULL, -1, Bpp, width, height); info = lookup_image_info (hash, width, height); @@ -174,10 +178,13 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data, return info->image; } else +#endif { struct QXLImage *image; - struct QXLDataChunk *chunk; + struct QXLDataChunk *head; + struct QXLDataChunk *tail; int dest_stride = width * Bpp; + int h; #if 0 ErrorF ("Must create new image of size %d %d\n", width, height); @@ -186,15 +193,40 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data, /* Chunk */ /* FIXME: Check integer overflow */ - chunk = qxl_allocnf (qxl, sizeof *chunk + height * dest_stride); - - chunk->data_size = height * dest_stride; - chunk->prev_chunk = 0; - chunk->next_chunk = 0; - - hash_and_copy (data, stride, - chunk->data, dest_stride, - Bpp, width, height); + + head = tail = NULL; + + h = height; + while (h) + { + int chunk_size = MAX (512 * 512, dest_stride); + int n_lines = MIN ((chunk_size / dest_stride), h); + QXLDataChunk *chunk = + qxl_allocnf (qxl, sizeof *chunk + n_lines * dest_stride); + + chunk->data_size = n_lines * dest_stride; + hash_and_copy (data, stride, + chunk->data, dest_stride, + Bpp, width, n_lines); + + if (tail) + { + tail->next_chunk = physical_address (qxl, chunk, qxl->main_mem_slot); + chunk->prev_chunk = physical_address (qxl, tail, qxl->main_mem_slot); + chunk->next_chunk = 0; + + tail = chunk; + } + else + { + head = tail = chunk; + chunk->next_chunk = 0; + chunk->prev_chunk = 0; + } + + data += n_lines * stride; + h -= n_lines; + } /* Image */ image = qxl_allocnf (qxl, sizeof *image); @@ -219,14 +251,16 @@ qxl_image_create (qxl_screen_t *qxl, const uint8_t *data, image->bitmap.format = SPICE_BITMAP_FMT_32BIT; } else - abort(); + { + abort(); + } image->bitmap.flags = SPICE_BITMAP_FLAGS_TOP_DOWN; image->bitmap.x = width; image->bitmap.y = height; image->bitmap.stride = width * Bpp; image->bitmap.palette = 0; - image->bitmap.data = physical_address (qxl, chunk, qxl->main_mem_slot); + image->bitmap.data = physical_address (qxl, head, qxl->main_mem_slot); #if 0 ErrorF ("%p has size %d %d\n", image, width, height); @@ -256,11 +290,9 @@ void qxl_image_destroy (qxl_screen_t *qxl, struct QXLImage *image) { - struct QXLDataChunk *chunk; image_info_t *info; + uint64_t chunk; - chunk = virtual_address (qxl, u64_to_pointer (image->bitmap.data), qxl->main_mem_slot); - info = lookup_image_info (image->descriptor.id, image->descriptor.width, image->descriptor.height); @@ -279,7 +311,19 @@ qxl_image_destroy (qxl_screen_t *qxl, remove_image_info (info); } - qxl_free (qxl->mem, chunk); + + chunk = image->bitmap.data; + while (chunk) + { + struct QXLDataChunk *virtual; + + virtual = virtual_address (qxl, (void *)chunk, qxl->main_mem_slot); + + chunk = virtual->next_chunk; + + qxl_free (qxl->mem, virtual); + } + qxl_free (qxl->mem, image); } |