|
|
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.