static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) { static const int blksize = 32; int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize; int dirty_top[blocks]; int y, yoff, x, xoff, blk, bw; int bpp = ds_get_bytes_per_pixel(ssd->ds); uint8_t *guest, *mirror; if (qemu_spice_rect_is_empty(&ssd->dirty)) { return; }; if (ssd->conv == NULL) { PixelFormat dst = qemu_default_pixelformat(32); ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); assert(ssd->conv); } if (ssd->ds_mirror == NULL) { int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); ssd->ds_mirror = g_malloc0(size); } for (blk = 0; blk < blocks; blk++) { dirty_top[blk] = -1; } guest = ds_get_data(ssd->ds); mirror = ssd->ds_mirror; for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { yoff = y * ds_get_linesize(ssd->ds); for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { xoff = x * bpp; blk = x / blksize; bw = MIN(blksize, ssd->dirty.right - x); if (memcmp(guest + yoff + xoff, mirror + yoff + xoff, bw * bpp) == 0) { if (dirty_top[blk] != -1) { QXLRect update = { .top = dirty_top[blk], .bottom = y, .left = x, .right = x + bw, }; qemu_spice_create_one_update(ssd, &update); dirty_top[blk] = -1; } } else { if (dirty_top[blk] == -1) { dirty_top[blk] = y; } } } }
static DisplaySurface* sdl_create_displaysurface(int width, int height) { DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); if (surface == NULL) { fprintf(stderr, "sdl_create_displaysurface: malloc failed\n"); exit(1); } surface->width = width; surface->height = height; if (scaling_active) { if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) { surface->linesize = width * 4; surface->pf = qemu_default_pixelformat(32); } else { surface->linesize = width * host_format.BytesPerPixel; surface->pf = sdl_to_qemu_pixelformat(&host_format); } #ifdef HOST_WORDS_BIGENDIAN surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; #else surface->flags = QEMU_ALLOCATED_FLAG; #endif surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height); return surface; } if (host_format.BitsPerPixel == 16) do_sdl_resize(width, height, 16); else do_sdl_resize(width, height, 32); surface->pf = sdl_to_qemu_pixelformat(real_screen->format); surface->linesize = real_screen->pitch; surface->data = real_screen->pixels; #ifdef HOST_WORDS_BIGENDIAN surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG; #else surface->flags = QEMU_REALPIXELS_FLAG; #endif allocator = 1; return surface; }
static DisplaySurface* sdl_create_displaysurface(int width, int height) { DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface)); surface->width = width; surface->height = height; if (scaling_active) { int linesize; PixelFormat pf; if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) { linesize = width * 4; pf = qemu_default_pixelformat(32); } else { linesize = width * host_format.BytesPerPixel; pf = sdl_to_qemu_pixelformat(&host_format); } qemu_alloc_display(surface, width, height, linesize, pf, 0); return surface; } if (host_format.BitsPerPixel == 16) do_sdl_resize(width, height, 16); else do_sdl_resize(width, height, 32); surface->pf = sdl_to_qemu_pixelformat(real_screen->format); surface->linesize = real_screen->pitch; surface->data = real_screen->pixels; #ifdef HOST_WORDS_BIGENDIAN surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG; #else surface->flags = QEMU_REALPIXELS_FLAG; #endif allocator = 1; return surface; }
static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) { SimpleSpiceUpdate *update; QXLDrawable *drawable; QXLImage *image; QXLCommand *cmd; uint8_t *src, *dst; int by, bw, bh; struct timespec time_space; if (qemu_spice_rect_is_empty(&ssd->dirty)) { return NULL; }; trace_qemu_spice_create_update( ssd->dirty.left, ssd->dirty.right, ssd->dirty.top, ssd->dirty.bottom); update = g_malloc0(sizeof(*update)); drawable = &update->drawable; image = &update->image; cmd = &update->ext.cmd; bw = ssd->dirty.right - ssd->dirty.left; bh = ssd->dirty.bottom - ssd->dirty.top; update->bitmap = g_malloc(bw * bh * 4); drawable->bbox = ssd->dirty; drawable->clip.type = SPICE_CLIP_TYPE_NONE; drawable->effect = QXL_EFFECT_OPAQUE; drawable->release_info.id = (uintptr_t)update; drawable->type = QXL_DRAW_COPY; drawable->surfaces_dest[0] = -1; drawable->surfaces_dest[1] = -1; drawable->surfaces_dest[2] = -1; clock_gettime(CLOCK_MONOTONIC, &time_space); /* time in milliseconds from epoch. */ drawable->mm_time = time_space.tv_sec * 1000 + time_space.tv_nsec / 1000 / 1000; drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; drawable->u.copy.src_bitmap = (uintptr_t)image; drawable->u.copy.src_area.right = bw; drawable->u.copy.src_area.bottom = bh; QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++); image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; image->bitmap.stride = bw * 4; image->descriptor.width = image->bitmap.x = bw; image->descriptor.height = image->bitmap.y = bh; image->bitmap.data = (uintptr_t)(update->bitmap); image->bitmap.palette = 0; image->bitmap.format = SPICE_BITMAP_FMT_32BIT; if (ssd->conv == NULL) { PixelFormat dst = qemu_default_pixelformat(32); ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); assert(ssd->conv); } src = ds_get_data(ssd->ds) + ssd->dirty.top * ds_get_linesize(ssd->ds) + ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds); dst = update->bitmap; for (by = 0; by < bh; by++) { qemu_pf_conv_run(ssd->conv, dst, src, bw); src += ds_get_linesize(ssd->ds); dst += image->bitmap.stride; } cmd->type = QXL_CMD_DRAW; cmd->data = (uintptr_t)drawable; memset(&ssd->dirty, 0, sizeof(ssd->dirty)); return update; }