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/>.
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
;
30 src
+= (qxl
->guest_primary
.surface
.height
- rect
->top
- 1) *
31 qxl
->guest_primary
.abs_stride
;
32 dst
+= rect
->top
* qxl
->guest_primary
.abs_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
.abs_stride
;
40 src
-= qxl
->guest_primary
.abs_stride
;
44 void qxl_render_resize(PCIQXLDevice
*qxl
)
46 QXLSurfaceCreate
*sc
= &qxl
->guest_primary
.surface
;
48 qxl
->guest_primary
.qxl_stride
= sc
->stride
;
49 qxl
->guest_primary
.abs_stride
= abs(sc
->stride
);
50 qxl
->guest_primary
.resized
++;
52 case SPICE_SURFACE_FMT_16_555
:
53 qxl
->guest_primary
.bytes_pp
= 2;
54 qxl
->guest_primary
.bits_pp
= 15;
56 case SPICE_SURFACE_FMT_16_565
:
57 qxl
->guest_primary
.bytes_pp
= 2;
58 qxl
->guest_primary
.bits_pp
= 16;
60 case SPICE_SURFACE_FMT_32_xRGB
:
61 case SPICE_SURFACE_FMT_32_ARGB
:
62 qxl
->guest_primary
.bytes_pp
= 4;
63 qxl
->guest_primary
.bits_pp
= 32;
66 fprintf(stderr
, "%s: unhandled format: %x\n", __FUNCTION__
,
67 qxl
->guest_primary
.surface
.format
);
68 qxl
->guest_primary
.bytes_pp
= 4;
69 qxl
->guest_primary
.bits_pp
= 32;
74 void qxl_render_update(PCIQXLDevice
*qxl
)
76 VGACommonState
*vga
= &qxl
->vga
;
77 QXLRect dirty
[32], update
;
81 if (!is_buffer_shared(vga
->ds
->surface
)) {
82 dprint(qxl
, 1, "%s: restoring shared displaysurface\n", __func__
);
83 qxl
->guest_primary
.resized
++;
84 qxl
->guest_primary
.commands
++;
88 if (qxl
->guest_primary
.resized
) {
89 qxl
->guest_primary
.resized
= 0;
91 if (qxl
->guest_primary
.flipped
) {
92 g_free(qxl
->guest_primary
.flipped
);
93 qxl
->guest_primary
.flipped
= NULL
;
95 qemu_free_displaysurface(vga
->ds
);
97 qxl
->guest_primary
.data
= memory_region_get_ram_ptr(&qxl
->vga
.vram
);
98 if (qxl
->guest_primary
.qxl_stride
< 0) {
99 /* spice surface is upside down -> need extra buffer to flip */
100 qxl
->guest_primary
.flipped
=
101 g_malloc(qxl
->guest_primary
.surface
.width
*
102 qxl
->guest_primary
.abs_stride
);
103 ptr
= qxl
->guest_primary
.flipped
;
105 ptr
= qxl
->guest_primary
.data
;
107 dprint(qxl
, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
109 qxl
->guest_primary
.surface
.width
,
110 qxl
->guest_primary
.surface
.height
,
111 qxl
->guest_primary
.qxl_stride
,
112 qxl
->guest_primary
.bytes_pp
,
113 qxl
->guest_primary
.bits_pp
,
114 qxl
->guest_primary
.flipped
? "yes" : "no");
116 qemu_create_displaysurface_from(qxl
->guest_primary
.surface
.width
,
117 qxl
->guest_primary
.surface
.height
,
118 qxl
->guest_primary
.bits_pp
,
119 qxl
->guest_primary
.abs_stride
,
124 if (!qxl
->guest_primary
.commands
) {
127 qxl
->guest_primary
.commands
= 0;
130 update
.right
= qxl
->guest_primary
.surface
.width
;
132 update
.bottom
= qxl
->guest_primary
.surface
.height
;
134 memset(dirty
, 0, sizeof(dirty
));
135 qxl_spice_update_area(qxl
, 0, &update
,
136 dirty
, ARRAY_SIZE(dirty
), 1, QXL_SYNC
);
138 memset(dirty
, 0, sizeof(dirty
));
142 for (i
= 0; i
< ARRAY_SIZE(dirty
); i
++) {
143 if (qemu_spice_rect_is_empty(dirty
+i
)) {
146 if (qxl
->guest_primary
.flipped
) {
147 qxl_flip(qxl
, dirty
+i
);
150 dirty
[i
].left
, dirty
[i
].top
,
151 dirty
[i
].right
- dirty
[i
].left
,
152 dirty
[i
].bottom
- dirty
[i
].top
);
156 static QEMUCursor
*qxl_cursor(PCIQXLDevice
*qxl
, QXLCursor
*cursor
)
159 uint8_t *image
, *mask
;
162 c
= cursor_alloc(cursor
->header
.width
, cursor
->header
.height
);
163 c
->hot_x
= cursor
->header
.hot_spot_x
;
164 c
->hot_y
= cursor
->header
.hot_spot_y
;
165 switch (cursor
->header
.type
) {
166 case SPICE_CURSOR_TYPE_ALPHA
:
167 size
= cursor
->header
.width
* cursor
->header
.height
* sizeof(uint32_t);
168 memcpy(c
->data
, cursor
->chunk
.data
, size
);
169 if (qxl
->debug
> 2) {
170 cursor_print_ascii_art(c
, "qxl/alpha");
173 case SPICE_CURSOR_TYPE_MONO
:
174 mask
= cursor
->chunk
.data
;
175 image
= mask
+ cursor_get_mono_bpl(c
) * c
->width
;
176 cursor_set_mono(c
, 0xffffff, 0x000000, image
, 1, mask
);
177 if (qxl
->debug
> 2) {
178 cursor_print_ascii_art(c
, "qxl/mono");
182 fprintf(stderr
, "%s: not implemented: type %d\n",
183 __FUNCTION__
, cursor
->header
.type
);
194 /* called from spice server thread context only */
195 void qxl_render_cursor(PCIQXLDevice
*qxl
, QXLCommandExt
*ext
)
197 QXLCursorCmd
*cmd
= qxl_phys2virt(qxl
, ext
->cmd
.data
, ext
->group_id
);
201 if (!qxl
->ssd
.ds
->mouse_set
|| !qxl
->ssd
.ds
->cursor_define
) {
205 if (qxl
->debug
> 1 && cmd
->type
!= QXL_CURSOR_MOVE
) {
206 fprintf(stderr
, "%s", __FUNCTION__
);
207 qxl_log_cmd_cursor(qxl
, cmd
, ext
->group_id
);
208 fprintf(stderr
, "\n");
212 cursor
= qxl_phys2virt(qxl
, cmd
->u
.set
.shape
, ext
->group_id
);
213 if (cursor
->chunk
.data_size
!= cursor
->data_size
) {
214 fprintf(stderr
, "%s: multiple chunks\n", __FUNCTION__
);
217 c
= qxl_cursor(qxl
, cursor
);
219 c
= cursor_builtin_left_ptr();
221 qemu_mutex_lock(&qxl
->ssd
.lock
);
222 if (qxl
->ssd
.cursor
) {
223 cursor_put(qxl
->ssd
.cursor
);
226 qxl
->ssd
.mouse_x
= cmd
->u
.set
.position
.x
;
227 qxl
->ssd
.mouse_y
= cmd
->u
.set
.position
.y
;
228 qemu_mutex_unlock(&qxl
->ssd
.lock
);
230 case QXL_CURSOR_MOVE
:
231 qemu_mutex_lock(&qxl
->ssd
.lock
);
232 qxl
->ssd
.mouse_x
= cmd
->u
.position
.x
;
233 qxl
->ssd
.mouse_y
= cmd
->u
.position
.y
;
234 qemu_mutex_unlock(&qxl
->ssd
.lock
);