|
|
1.1 root 1: /*
2: * qxl local rendering (aka display on sdl/vnc)
3: *
4: * Copyright (C) 2010 Red Hat, Inc.
5: *
6: * maintained by Gerd Hoffmann <[email protected]>
7: *
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.
12: *
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.
17: *
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/>.
20: */
21:
22: #include "qxl.h"
23:
24: static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
25: {
26: uint8_t *src = qxl->guest_primary.data;
27: uint8_t *dst = qxl->guest_primary.flipped;
28: int len, i;
29:
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;
36:
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;
41: }
42: }
43:
44: void qxl_render_resize(PCIQXLDevice *qxl)
45: {
46: QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
47:
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;
70: }
71: }
72:
73: void qxl_render_update(PCIQXLDevice *qxl)
74: {
75: VGACommonState *vga = &qxl->vga;
76: QXLRect dirty[32], update;
77: void *ptr;
78: int i;
79:
80: if (qxl->guest_primary.resized) {
81: qxl->guest_primary.resized = 0;
82:
83: if (qxl->guest_primary.flipped) {
84: qemu_free(qxl->guest_primary.flipped);
85: qxl->guest_primary.flipped = NULL;
86: }
87: qemu_free_displaysurface(vga->ds);
88:
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;
98: }
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);
114: }
115:
116: if (!qxl->guest_primary.commands) {
117: return;
118: }
119: qxl->guest_primary.commands = 0;
120:
121: update.left = 0;
122: update.right = qxl->guest_primary.surface.width;
123: update.top = 0;
124: update.bottom = qxl->guest_primary.surface.height;
125:
126: memset(dirty, 0, sizeof(dirty));
127: qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
128: dirty, ARRAY_SIZE(dirty), 1);
129:
130: for (i = 0; i < ARRAY_SIZE(dirty); i++) {
131: if (qemu_spice_rect_is_empty(dirty+i)) {
132: break;
133: }
134: if (qxl->guest_primary.flipped) {
135: qxl_flip(qxl, dirty+i);
136: }
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);
141: }
142: }
143:
144: static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
145: {
146: QEMUCursor *c;
147: uint8_t *image, *mask;
148: int size;
149:
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");
159: }
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");
167: }
168: break;
169: default:
170: fprintf(stderr, "%s: not implemented: type %d\n",
171: __FUNCTION__, cursor->header.type);
172: goto fail;
173: }
174: return c;
175:
176: fail:
177: cursor_put(c);
178: return NULL;
179: }
180:
181:
182: /* called from spice server thread context only */
183: void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
184: {
185: QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
186: QXLCursor *cursor;
187: QEMUCursor *c;
188: int x = -1, y = -1;
189:
190: if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
191: return;
192: }
193:
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");
198: }
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;
207: }
208: c = qxl_cursor(qxl, cursor);
209: if (c == NULL) {
210: c = cursor_builtin_left_ptr();
211: }
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;
225: }
226: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.