Merge remote branch 'mst/for_anthony' into staging
[qemu.git] / hw / qxl-render.c
blob58965e0179dcadfdb1b318e36bdefd6bdb99d406
1 /*
2 * qxl local rendering (aka display on sdl/vnc)
4 * Copyright (C) 2010 Red Hat, Inc.
6 * maintained by Gerd Hoffmann <kraxel@redhat.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 or
11 * (at your option) version 3 of the License.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "qxl.h"
24 static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
26 uint8_t *src = qxl->guest_primary.data;
27 uint8_t *dst = qxl->guest_primary.flipped;
28 int len, i;
30 src += (qxl->guest_primary.surface.height - rect->top - 1) *
31 qxl->guest_primary.stride;
32 dst += rect->top * qxl->guest_primary.stride;
33 src += rect->left * qxl->guest_primary.bytes_pp;
34 dst += rect->left * qxl->guest_primary.bytes_pp;
35 len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
37 for (i = rect->top; i < rect->bottom; i++) {
38 memcpy(dst, src, len);
39 dst += qxl->guest_primary.stride;
40 src -= qxl->guest_primary.stride;
44 void qxl_render_resize(PCIQXLDevice *qxl)
46 QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
48 qxl->guest_primary.stride = sc->stride;
49 qxl->guest_primary.resized++;
50 switch (sc->format) {
51 case SPICE_SURFACE_FMT_16_555:
52 qxl->guest_primary.bytes_pp = 2;
53 qxl->guest_primary.bits_pp = 15;
54 break;
55 case SPICE_SURFACE_FMT_16_565:
56 qxl->guest_primary.bytes_pp = 2;
57 qxl->guest_primary.bits_pp = 16;
58 break;
59 case SPICE_SURFACE_FMT_32_xRGB:
60 case SPICE_SURFACE_FMT_32_ARGB:
61 qxl->guest_primary.bytes_pp = 4;
62 qxl->guest_primary.bits_pp = 32;
63 break;
64 default:
65 fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
66 qxl->guest_primary.surface.format);
67 qxl->guest_primary.bytes_pp = 4;
68 qxl->guest_primary.bits_pp = 32;
69 break;
73 void qxl_render_update(PCIQXLDevice *qxl)
75 VGACommonState *vga = &qxl->vga;
76 QXLRect dirty[32], update;
77 void *ptr;
78 int i;
80 if (qxl->guest_primary.resized) {
81 qxl->guest_primary.resized = 0;
83 if (qxl->guest_primary.flipped) {
84 qemu_free(qxl->guest_primary.flipped);
85 qxl->guest_primary.flipped = NULL;
87 qemu_free_displaysurface(vga->ds);
89 qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
90 if (qxl->guest_primary.stride < 0) {
91 /* spice surface is upside down -> need extra buffer to flip */
92 qxl->guest_primary.stride = -qxl->guest_primary.stride;
93 qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
94 qxl->guest_primary.stride);
95 ptr = qxl->guest_primary.flipped;
96 } else {
97 ptr = qxl->guest_primary.data;
99 dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
100 __FUNCTION__,
101 qxl->guest_primary.surface.width,
102 qxl->guest_primary.surface.height,
103 qxl->guest_primary.stride,
104 qxl->guest_primary.bytes_pp,
105 qxl->guest_primary.bits_pp,
106 qxl->guest_primary.flipped ? "yes" : "no");
107 vga->ds->surface =
108 qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
109 qxl->guest_primary.surface.height,
110 qxl->guest_primary.bits_pp,
111 qxl->guest_primary.stride,
112 ptr);
113 dpy_resize(vga->ds);
116 if (!qxl->guest_primary.commands) {
117 return;
119 qxl->guest_primary.commands = 0;
121 update.left = 0;
122 update.right = qxl->guest_primary.surface.width;
123 update.top = 0;
124 update.bottom = qxl->guest_primary.surface.height;
126 memset(dirty, 0, sizeof(dirty));
127 qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
128 dirty, ARRAY_SIZE(dirty), 1);
130 for (i = 0; i < ARRAY_SIZE(dirty); i++) {
131 if (qemu_spice_rect_is_empty(dirty+i)) {
132 break;
134 if (qxl->guest_primary.flipped) {
135 qxl_flip(qxl, dirty+i);
137 dpy_update(vga->ds,
138 dirty[i].left, dirty[i].top,
139 dirty[i].right - dirty[i].left,
140 dirty[i].bottom - dirty[i].top);
144 static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
146 QEMUCursor *c;
147 uint8_t *image, *mask;
148 int size;
150 c = cursor_alloc(cursor->header.width, cursor->header.height);
151 c->hot_x = cursor->header.hot_spot_x;
152 c->hot_y = cursor->header.hot_spot_y;
153 switch (cursor->header.type) {
154 case SPICE_CURSOR_TYPE_ALPHA:
155 size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
156 memcpy(c->data, cursor->chunk.data, size);
157 if (qxl->debug > 2) {
158 cursor_print_ascii_art(c, "qxl/alpha");
160 break;
161 case SPICE_CURSOR_TYPE_MONO:
162 mask = cursor->chunk.data;
163 image = mask + cursor_get_mono_bpl(c) * c->width;
164 cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
165 if (qxl->debug > 2) {
166 cursor_print_ascii_art(c, "qxl/mono");
168 break;
169 default:
170 fprintf(stderr, "%s: not implemented: type %d\n",
171 __FUNCTION__, cursor->header.type);
172 goto fail;
174 return c;
176 fail:
177 cursor_put(c);
178 return NULL;
182 /* called from spice server thread context only */
183 void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
185 QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
186 QXLCursor *cursor;
187 QEMUCursor *c;
188 int x = -1, y = -1;
190 if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
191 return;
194 if (qxl->debug > 1 && cmd->type != QXL_CURSOR_MOVE) {
195 fprintf(stderr, "%s", __FUNCTION__);
196 qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
197 fprintf(stderr, "\n");
199 switch (cmd->type) {
200 case QXL_CURSOR_SET:
201 x = cmd->u.set.position.x;
202 y = cmd->u.set.position.y;
203 cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
204 if (cursor->chunk.data_size != cursor->data_size) {
205 fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
206 return;
208 c = qxl_cursor(qxl, cursor);
209 if (c == NULL) {
210 c = cursor_builtin_left_ptr();
212 qemu_mutex_lock_iothread();
213 qxl->ssd.ds->cursor_define(c);
214 qxl->ssd.ds->mouse_set(x, y, 1);
215 qemu_mutex_unlock_iothread();
216 cursor_put(c);
217 break;
218 case QXL_CURSOR_MOVE:
219 x = cmd->u.position.x;
220 y = cmd->u.position.y;
221 qemu_mutex_lock_iothread();
222 qxl->ssd.ds->mouse_set(x, y, 1);
223 qemu_mutex_unlock_iothread();
224 break;