diff options
author | Yaniv Kamay <ykamay@redhat.com> | 2009-12-23 01:37:57 +0200 |
---|---|---|
committer | Yaniv Kamay <ykamay@redhat.com> | 2009-12-23 01:48:20 +0200 |
commit | 75b614a407938beff2dcbc796f1acbd3cf0f585f (patch) | |
tree | defbe0e534871d02c13a38c80f9d5cd0ff6c3d68 | |
parent | 7fe765d123c9ade3613f6128ae86a3be7a602d60 (diff) |
qxl: deffer vga updates in case commands ring is full
-rw-r--r-- | qemu/hw/qxl.c | 110 |
1 files changed, 76 insertions, 34 deletions
diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c index e869c812..60210efb 100644 --- a/qemu/hw/qxl.c +++ b/qemu/hw/qxl.c @@ -41,10 +41,6 @@ #define TRUE 1 #define FALSE 0 -#define WAIT_CMD_DELAY_MS 10 -#define WAIT_CMD_MESSAGE_THRESHOLD 2 -#define WAIT_CMD_MESSAGE_INTERVAL_MS 5000 - #define QXL_DEV_NAME "qxl" #define VDI_PORT_DEV_NAME "vdi_port" @@ -155,6 +151,7 @@ struct PCIQXLDevice { QXLState state; int id; DisplayState ds; + Rect dirty_rect; struct PCIQXLDevice *dev_next; struct PCIQXLDevice *vga_next; int pipe_fd[2]; @@ -235,6 +232,7 @@ typedef struct QXLVga { PCIQXLDevice *clients; int active_clients; QEMUTimer *timer; + int need_update; } QXLVga; static void qxl_exit_vga_mode(PCIQXLDevice *d); @@ -691,6 +689,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) printf("%u: %s\n", d->id, __FUNCTION__); d->state.rom->mode = ~0; d->state.mode = QXL_MODE_VGA; + memset(&d->dirty_rect, 0, sizeof(d->dirty_rect)); qxl_notify_mode_change(d); qxl_add_vga_client(); } @@ -1364,12 +1363,54 @@ inline uint32_t msb_mask(uint32_t val) return mask; } +static int rect_is_empty(const Rect* r) +{ + return r->top == r->bottom || r->left == r->right; +} + +static void rect_union(Rect *dest, const Rect *r) +{ + if (rect_is_empty(r)) { + return; + } + + if (rect_is_empty(dest)) { + *dest = *r; + return; + } + + dest->top = MIN(dest->top, r->top); + dest->left = MIN(dest->left, r->left); + dest->bottom = MAX(dest->bottom, r->bottom); + dest->right = MAX(dest->right, r->right); +} + static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int h) { PCIQXLDevice *client; + Rect update_area; - client = qxl_vga.clients; - while (client) { + qxl_vga.need_update = TRUE; + + update_area.left = x, + update_area.right = x + w; + update_area.top = y; + update_area.bottom = y + h; + + for (client = qxl_vga.clients; client; client = client->vga_next) { + if (client->state.mode == QXL_MODE_VGA && client->state.running) { + rect_union(&client->dirty_rect, &update_area); + } + } +} + +static void qxl_vga_update(void) +{ + PCIQXLDevice *client; + + qxl_vga.need_update = FALSE; + + for (client = qxl_vga.clients; client; client = client->vga_next) { if (client->state.mode == QXL_MODE_VGA && client->state.running) { QXLDrawable *drawable; QXLImage *image; @@ -1377,15 +1418,27 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int QXLCommand *cmd; int wait; int notify; - int wait_count; + Rect *dirty_rect = &client->dirty_rect; + + if (rect_is_empty(dirty_rect)) { + continue; + } + + ring = &client->state.vga_ring; + RING_PROD_WAIT(ring, wait); + if (wait) { + qxl_vga.need_update = TRUE; + continue; + } drawable = (QXLDrawable *)malloc(sizeof(*drawable) + sizeof(*image)); - ASSERT(drawable); + if (!drawable) { + printf("%s: alloc drawable failed\n", __FUNCTION__); + abort(); + } + image = (QXLImage *)(drawable + 1); - drawable->bbox.left = x; - drawable->bbox.right = x + w; - drawable->bbox.top = y; - drawable->bbox.bottom = y + h; + drawable->bbox = *dirty_rect; drawable->clip.type = CLIP_TYPE_NONE; drawable->clip.data = 0; drawable->effect = QXL_EFFECT_OPAQUE; @@ -1396,8 +1449,8 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int drawable->u.copy.rop_decriptor = ROPD_OP_PUT; drawable->u.copy.src_bitmap = (PHYSICAL)image; drawable->u.copy.src_area.left = drawable->u.copy.src_area.top = 0; - drawable->u.copy.src_area.right = w; - drawable->u.copy.src_area.bottom = h; + drawable->u.copy.src_area.right = dirty_rect->right - dirty_rect->left; + drawable->u.copy.src_area.bottom = dirty_rect->bottom - dirty_rect->top; drawable->u.copy.scale_mode = 0; memset(&drawable->u.copy.mask, 0, sizeof(QMask)); @@ -1406,26 +1459,12 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ++client->state.bits_unique); image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN | QXL_BITMAP_UNSTABLE; image->bitmap.format = BITMAP_FMT_32BIT; - image->bitmap.stride = ds->linesize; - image->descriptor.width = image->bitmap.x = w; - image->descriptor.height = image->bitmap.y = h; - image->bitmap.data = (PHYSICAL)(ds->data + y * ds->linesize + x * 4); + image->bitmap.stride = qxl_vga.ds->linesize; + image->descriptor.width = image->bitmap.x = drawable->u.copy.src_area.right; + image->descriptor.height = image->bitmap.y = drawable->u.copy.src_area.bottom; + image->bitmap.data = (PHYSICAL)(qxl_vga.ds->data + dirty_rect->top * qxl_vga.ds->linesize + dirty_rect->left * 4); image->bitmap.palette = 0; - ring = &client->state.vga_ring; - wait_count = -WAIT_CMD_MESSAGE_THRESHOLD; - for (;;) { - RING_PROD_WAIT(ring, wait); - if (wait) { - usleep(WAIT_CMD_DELAY_MS * 1000); - if (!(wait_count++ % (WAIT_CMD_MESSAGE_INTERVAL_MS / WAIT_CMD_DELAY_MS))) { - printf("%s: waiting for command\n", __FUNCTION__); - } - continue; - } - break; - } - cmd = RING_PROD_ITEM(ring); cmd->type = QXL_CMD_DRAW; cmd->data = (PHYSICAL)drawable; @@ -1433,8 +1472,8 @@ static void qxl_display_update(struct DisplayState *ds, int x, int y, int w, int if (notify) { client->worker->wakeup(client->worker); } + memset(dirty_rect, 0, sizeof(*dirty_rect)); } - client = client->vga_next; } } @@ -1467,6 +1506,9 @@ static void qxl_display_refresh(struct DisplayState *ds) { if (qxl_vga.active_clients) { vga_hw_update(); + if (qxl_vga.need_update) { + qxl_vga_update(); + } } } @@ -2210,7 +2252,7 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, } d->state.num_ranges = num_ranges + 1; - printf("%s: rom(%p, 0x%x, 0x%x) ram(%p, 0x%x, 0x%x) vram(%p, 0x%lx, 0x%x)\n", + printf("%s: rom(%p, 0x%lx, 0x%x) ram(%p, 0x%lx, 0x%x) vram(%p, 0x%lx, 0x%x)\n", __FUNCTION__, d->state.rom, d->state.rom_offset, |