mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
qxl: make qxl_render_update async
RHBZ# 747011 Removes the last user of QXL_SYNC when using update drivers that use the _ASYNC io ports. The last user is qxl_render_update, it is called both by qxl_hw_update which is the vga_hw_update_ptr passed to graphic_console_init, and by qxl_hw_screen_dump. At the same time the QXLRect area being passed to the red_worker thread is passed as a copy, as part of the QXLCookie. The implementation uses interface_update_area_complete with a bh to make sure dpy_update and qxl_flip are called from the io thread, otherwise the vga->ds->surface.data can change under our feet. With this patch sdl+spice works fine. But spice by itself doesn't produce the expected screendumps unless repeated a few times, due to ppm_save being called before update_area (rendering done in spice server thread) having a chance to complete. Fixed by next patch, but see commit message for problem introduced by it. Signed-off-by: Alon Levy <alevy@redhat.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
2e1a98c9c1
commit
81fb6f1504
4 changed files with 150 additions and 31 deletions
|
@ -82,17 +82,25 @@ void qxl_render_resize(PCIQXLDevice *qxl)
|
|||
}
|
||||
}
|
||||
|
||||
void qxl_render_update(PCIQXLDevice *qxl)
|
||||
static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area)
|
||||
{
|
||||
area->left = 0;
|
||||
area->right = qxl->guest_primary.surface.width;
|
||||
area->top = 0;
|
||||
area->bottom = qxl->guest_primary.surface.height;
|
||||
}
|
||||
|
||||
static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
|
||||
{
|
||||
VGACommonState *vga = &qxl->vga;
|
||||
QXLRect dirty[32], update;
|
||||
int i, redraw = 0;
|
||||
int i;
|
||||
DisplaySurface *surface = vga->ds->surface;
|
||||
|
||||
if (qxl->guest_primary.resized) {
|
||||
qxl->guest_primary.resized = 0;
|
||||
|
||||
qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram);
|
||||
qxl_set_rect_to_surface(qxl, &qxl->dirty[0]);
|
||||
qxl->num_dirty_rects = 1;
|
||||
dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n",
|
||||
__FUNCTION__,
|
||||
qxl->guest_primary.surface.width,
|
||||
|
@ -103,9 +111,9 @@ void qxl_render_update(PCIQXLDevice *qxl)
|
|||
}
|
||||
if (surface->width != qxl->guest_primary.surface.width ||
|
||||
surface->height != qxl->guest_primary.surface.height) {
|
||||
dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n",
|
||||
__func__);
|
||||
if (qxl->guest_primary.qxl_stride > 0) {
|
||||
dprint(qxl, 1, "%s: using guest_primary for displaysurface\n",
|
||||
__func__);
|
||||
qemu_free_displaysurface(vga->ds);
|
||||
qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
|
||||
qxl->guest_primary.surface.height,
|
||||
|
@ -113,36 +121,70 @@ void qxl_render_update(PCIQXLDevice *qxl)
|
|||
qxl->guest_primary.abs_stride,
|
||||
qxl->guest_primary.data);
|
||||
} else {
|
||||
dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n",
|
||||
__func__);
|
||||
qemu_resize_displaysurface(vga->ds,
|
||||
qxl->guest_primary.surface.width,
|
||||
qxl->guest_primary.surface.height);
|
||||
}
|
||||
}
|
||||
update.left = 0;
|
||||
update.right = qxl->guest_primary.surface.width;
|
||||
update.top = 0;
|
||||
update.bottom = qxl->guest_primary.surface.height;
|
||||
|
||||
memset(dirty, 0, sizeof(dirty));
|
||||
if (runstate_is_running() && qxl->guest_primary.commands) {
|
||||
qxl->guest_primary.commands = 0;
|
||||
qxl_spice_update_area(qxl, 0, &update,
|
||||
dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL);
|
||||
}
|
||||
if (redraw) {
|
||||
memset(dirty, 0, sizeof(dirty));
|
||||
dirty[0] = update;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(dirty); i++) {
|
||||
if (qemu_spice_rect_is_empty(dirty+i)) {
|
||||
for (i = 0; i < qxl->num_dirty_rects; i++) {
|
||||
if (qemu_spice_rect_is_empty(qxl->dirty+i)) {
|
||||
break;
|
||||
}
|
||||
qxl_flip(qxl, dirty+i);
|
||||
qxl_flip(qxl, qxl->dirty+i);
|
||||
dpy_update(vga->ds,
|
||||
dirty[i].left, dirty[i].top,
|
||||
dirty[i].right - dirty[i].left,
|
||||
dirty[i].bottom - dirty[i].top);
|
||||
qxl->dirty[i].left, qxl->dirty[i].top,
|
||||
qxl->dirty[i].right - qxl->dirty[i].left,
|
||||
qxl->dirty[i].bottom - qxl->dirty[i].top);
|
||||
}
|
||||
qxl->num_dirty_rects = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* use ssd.lock to protect render_update_cookie_num.
|
||||
* qxl_render_update is called by io thread or vcpu thread, and the completion
|
||||
* callbacks are called by spice_server thread, defering to bh called from the
|
||||
* io thread.
|
||||
*/
|
||||
void qxl_render_update(PCIQXLDevice *qxl)
|
||||
{
|
||||
QXLCookie *cookie;
|
||||
|
||||
qemu_mutex_lock(&qxl->ssd.lock);
|
||||
|
||||
if (!runstate_is_running() || !qxl->guest_primary.commands) {
|
||||
qxl_render_update_area_unlocked(qxl);
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
return;
|
||||
}
|
||||
|
||||
qxl->guest_primary.commands = 0;
|
||||
qxl->render_update_cookie_num++;
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
|
||||
0);
|
||||
qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
|
||||
qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
|
||||
0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
|
||||
}
|
||||
|
||||
void qxl_render_update_area_bh(void *opaque)
|
||||
{
|
||||
PCIQXLDevice *qxl = opaque;
|
||||
|
||||
qemu_mutex_lock(&qxl->ssd.lock);
|
||||
qxl_render_update_area_unlocked(qxl);
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
}
|
||||
|
||||
void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
|
||||
{
|
||||
qemu_mutex_lock(&qxl->ssd.lock);
|
||||
qemu_bh_schedule(qxl->update_area_bh);
|
||||
qxl->render_update_cookie_num--;
|
||||
qemu_mutex_unlock(&qxl->ssd.lock);
|
||||
g_free(cookie);
|
||||
}
|
||||
|
||||
static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue