4 * Copyright Red Hat, Inc. 2013-2014
7 * Dave Airlie <airlied@redhat.com>
8 * Gerd Hoffmann <kraxel@redhat.com>
10 * This work is licensed under the terms of the GNU GPL, version 2.
11 * See the COPYING file in the top-level directory.
14 #include "qemu-common.h"
16 #include "ui/console.h"
18 #include "hw/virtio/virtio.h"
19 #include "hw/virtio/virtio-gpu.h"
20 #include "hw/virtio/virtio-bus.h"
22 static struct virtio_gpu_simple_resource
*
23 virtio_gpu_find_resource(VirtIOGPU
*g
, uint32_t resource_id
);
25 static void update_cursor_data_simple(VirtIOGPU
*g
,
26 struct virtio_gpu_scanout
*s
,
29 struct virtio_gpu_simple_resource
*res
;
32 res
= virtio_gpu_find_resource(g
, resource_id
);
37 if (pixman_image_get_width(res
->image
) != s
->current_cursor
->width
||
38 pixman_image_get_height(res
->image
) != s
->current_cursor
->height
) {
42 pixels
= s
->current_cursor
->width
* s
->current_cursor
->height
;
43 memcpy(s
->current_cursor
->data
,
44 pixman_image_get_data(res
->image
),
45 pixels
* sizeof(uint32_t));
48 static void update_cursor(VirtIOGPU
*g
, struct virtio_gpu_update_cursor
*cursor
)
50 struct virtio_gpu_scanout
*s
;
52 if (cursor
->pos
.scanout_id
>= g
->conf
.max_outputs
) {
55 s
= &g
->scanout
[cursor
->pos
.scanout_id
];
57 if (cursor
->hdr
.type
!= VIRTIO_GPU_CMD_MOVE_CURSOR
) {
58 if (!s
->current_cursor
) {
59 s
->current_cursor
= cursor_alloc(64, 64);
62 s
->current_cursor
->hot_x
= cursor
->hot_x
;
63 s
->current_cursor
->hot_y
= cursor
->hot_y
;
65 if (cursor
->resource_id
> 0) {
66 update_cursor_data_simple(g
, s
, cursor
->resource_id
);
68 dpy_cursor_define(s
->con
, s
->current_cursor
);
70 dpy_mouse_set(s
->con
, cursor
->pos
.x
, cursor
->pos
.y
,
71 cursor
->resource_id
? 1 : 0);
74 static void virtio_gpu_get_config(VirtIODevice
*vdev
, uint8_t *config
)
76 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
77 memcpy(config
, &g
->virtio_config
, sizeof(g
->virtio_config
));
80 static void virtio_gpu_set_config(VirtIODevice
*vdev
, const uint8_t *config
)
82 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
83 struct virtio_gpu_config vgconfig
;
85 memcpy(&vgconfig
, config
, sizeof(g
->virtio_config
));
87 if (vgconfig
.events_clear
) {
88 g
->virtio_config
.events_read
&= ~vgconfig
.events_clear
;
92 static uint64_t virtio_gpu_get_features(VirtIODevice
*vdev
, uint64_t features
,
98 static void virtio_gpu_notify_event(VirtIOGPU
*g
, uint32_t event_type
)
100 g
->virtio_config
.events_read
|= event_type
;
101 virtio_notify_config(&g
->parent_obj
);
104 static struct virtio_gpu_simple_resource
*
105 virtio_gpu_find_resource(VirtIOGPU
*g
, uint32_t resource_id
)
107 struct virtio_gpu_simple_resource
*res
;
109 QTAILQ_FOREACH(res
, &g
->reslist
, next
) {
110 if (res
->resource_id
== resource_id
) {
117 void virtio_gpu_ctrl_response(VirtIOGPU
*g
,
118 struct virtio_gpu_ctrl_command
*cmd
,
119 struct virtio_gpu_ctrl_hdr
*resp
,
124 if (cmd
->cmd_hdr
.flags
& VIRTIO_GPU_FLAG_FENCE
) {
125 resp
->flags
|= VIRTIO_GPU_FLAG_FENCE
;
126 resp
->fence_id
= cmd
->cmd_hdr
.fence_id
;
127 resp
->ctx_id
= cmd
->cmd_hdr
.ctx_id
;
129 s
= iov_from_buf(cmd
->elem
.in_sg
, cmd
->elem
.in_num
, 0, resp
, resp_len
);
131 qemu_log_mask(LOG_GUEST_ERROR
,
132 "%s: response size incorrect %zu vs %zu\n",
133 __func__
, s
, resp_len
);
135 virtqueue_push(cmd
->vq
, &cmd
->elem
, s
);
136 virtio_notify(VIRTIO_DEVICE(g
), cmd
->vq
);
137 cmd
->finished
= true;
140 void virtio_gpu_ctrl_response_nodata(VirtIOGPU
*g
,
141 struct virtio_gpu_ctrl_command
*cmd
,
142 enum virtio_gpu_ctrl_type type
)
144 struct virtio_gpu_ctrl_hdr resp
;
146 memset(&resp
, 0, sizeof(resp
));
148 virtio_gpu_ctrl_response(g
, cmd
, &resp
, sizeof(resp
));
152 virtio_gpu_fill_display_info(VirtIOGPU
*g
,
153 struct virtio_gpu_resp_display_info
*dpy_info
)
157 for (i
= 0; i
< g
->conf
.max_outputs
; i
++) {
158 if (g
->enabled_output_bitmask
& (1 << i
)) {
159 dpy_info
->pmodes
[i
].enabled
= 1;
160 dpy_info
->pmodes
[i
].r
.width
= g
->req_state
[i
].width
;
161 dpy_info
->pmodes
[i
].r
.height
= g
->req_state
[i
].height
;
166 void virtio_gpu_get_display_info(VirtIOGPU
*g
,
167 struct virtio_gpu_ctrl_command
*cmd
)
169 struct virtio_gpu_resp_display_info display_info
;
171 trace_virtio_gpu_cmd_get_display_info();
172 memset(&display_info
, 0, sizeof(display_info
));
173 display_info
.hdr
.type
= VIRTIO_GPU_RESP_OK_DISPLAY_INFO
;
174 virtio_gpu_fill_display_info(g
, &display_info
);
175 virtio_gpu_ctrl_response(g
, cmd
, &display_info
.hdr
,
176 sizeof(display_info
));
179 static pixman_format_code_t
get_pixman_format(uint32_t virtio_gpu_format
)
181 switch (virtio_gpu_format
) {
182 #ifdef HOST_WORDS_BIGENDIAN
183 case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM
:
184 return PIXMAN_b8g8r8x8
;
185 case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM
:
186 return PIXMAN_b8g8r8a8
;
187 case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM
:
188 return PIXMAN_x8r8g8b8
;
189 case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM
:
190 return PIXMAN_a8r8g8b8
;
191 case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM
:
192 return PIXMAN_r8g8b8x8
;
193 case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM
:
194 return PIXMAN_r8g8b8a8
;
195 case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM
:
196 return PIXMAN_x8b8g8r8
;
197 case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM
:
198 return PIXMAN_a8b8g8r8
;
200 case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM
:
201 return PIXMAN_x8r8g8b8
;
202 case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM
:
203 return PIXMAN_a8r8g8b8
;
204 case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM
:
205 return PIXMAN_b8g8r8x8
;
206 case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM
:
207 return PIXMAN_b8g8r8a8
;
208 case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM
:
209 return PIXMAN_x8b8g8r8
;
210 case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM
:
211 return PIXMAN_a8b8g8r8
;
212 case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM
:
213 return PIXMAN_r8g8b8x8
;
214 case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM
:
215 return PIXMAN_r8g8b8a8
;
222 static void virtio_gpu_resource_create_2d(VirtIOGPU
*g
,
223 struct virtio_gpu_ctrl_command
*cmd
)
225 pixman_format_code_t pformat
;
226 struct virtio_gpu_simple_resource
*res
;
227 struct virtio_gpu_resource_create_2d c2d
;
229 VIRTIO_GPU_FILL_CMD(c2d
);
230 trace_virtio_gpu_cmd_res_create_2d(c2d
.resource_id
, c2d
.format
,
231 c2d
.width
, c2d
.height
);
233 if (c2d
.resource_id
== 0) {
234 qemu_log_mask(LOG_GUEST_ERROR
, "%s: resource id 0 is not allowed\n",
236 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
240 res
= virtio_gpu_find_resource(g
, c2d
.resource_id
);
242 qemu_log_mask(LOG_GUEST_ERROR
, "%s: resource already exists %d\n",
243 __func__
, c2d
.resource_id
);
244 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
248 res
= g_new0(struct virtio_gpu_simple_resource
, 1);
250 res
->width
= c2d
.width
;
251 res
->height
= c2d
.height
;
252 res
->format
= c2d
.format
;
253 res
->resource_id
= c2d
.resource_id
;
255 pformat
= get_pixman_format(c2d
.format
);
257 qemu_log_mask(LOG_GUEST_ERROR
,
258 "%s: host couldn't handle guest format %d\n",
259 __func__
, c2d
.format
);
260 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER
;
263 res
->image
= pixman_image_create_bits(pformat
,
269 qemu_log_mask(LOG_GUEST_ERROR
,
270 "%s: resource creation failed %d %d %d\n",
271 __func__
, c2d
.resource_id
, c2d
.width
, c2d
.height
);
273 cmd
->error
= VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY
;
277 QTAILQ_INSERT_HEAD(&g
->reslist
, res
, next
);
280 static void virtio_gpu_resource_destroy(VirtIOGPU
*g
,
281 struct virtio_gpu_simple_resource
*res
)
283 pixman_image_unref(res
->image
);
284 QTAILQ_REMOVE(&g
->reslist
, res
, next
);
288 static void virtio_gpu_resource_unref(VirtIOGPU
*g
,
289 struct virtio_gpu_ctrl_command
*cmd
)
291 struct virtio_gpu_simple_resource
*res
;
292 struct virtio_gpu_resource_unref unref
;
294 VIRTIO_GPU_FILL_CMD(unref
);
295 trace_virtio_gpu_cmd_res_unref(unref
.resource_id
);
297 res
= virtio_gpu_find_resource(g
, unref
.resource_id
);
299 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
300 __func__
, unref
.resource_id
);
301 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
304 virtio_gpu_resource_destroy(g
, res
);
307 static void virtio_gpu_transfer_to_host_2d(VirtIOGPU
*g
,
308 struct virtio_gpu_ctrl_command
*cmd
)
310 struct virtio_gpu_simple_resource
*res
;
312 uint32_t src_offset
, dst_offset
, stride
;
314 pixman_format_code_t format
;
315 struct virtio_gpu_transfer_to_host_2d t2d
;
317 VIRTIO_GPU_FILL_CMD(t2d
);
318 trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d
.resource_id
);
320 res
= virtio_gpu_find_resource(g
, t2d
.resource_id
);
321 if (!res
|| !res
->iov
) {
322 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
323 __func__
, t2d
.resource_id
);
324 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
328 if (t2d
.r
.x
> res
->width
||
329 t2d
.r
.y
> res
->height
||
330 t2d
.r
.width
> res
->width
||
331 t2d
.r
.height
> res
->height
||
332 t2d
.r
.x
+ t2d
.r
.width
> res
->width
||
333 t2d
.r
.y
+ t2d
.r
.height
> res
->height
) {
334 qemu_log_mask(LOG_GUEST_ERROR
, "%s: transfer bounds outside resource"
335 " bounds for resource %d: %d %d %d %d vs %d %d\n",
336 __func__
, t2d
.resource_id
, t2d
.r
.x
, t2d
.r
.y
,
337 t2d
.r
.width
, t2d
.r
.height
, res
->width
, res
->height
);
338 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER
;
342 format
= pixman_image_get_format(res
->image
);
343 bpp
= (PIXMAN_FORMAT_BPP(format
) + 7) / 8;
344 stride
= pixman_image_get_stride(res
->image
);
346 if (t2d
.offset
|| t2d
.r
.x
|| t2d
.r
.y
||
347 t2d
.r
.width
!= pixman_image_get_width(res
->image
)) {
348 void *img_data
= pixman_image_get_data(res
->image
);
349 for (h
= 0; h
< t2d
.r
.height
; h
++) {
350 src_offset
= t2d
.offset
+ stride
* h
;
351 dst_offset
= (t2d
.r
.y
+ h
) * stride
+ (t2d
.r
.x
* bpp
);
353 iov_to_buf(res
->iov
, res
->iov_cnt
, src_offset
,
355 + dst_offset
, t2d
.r
.width
* bpp
);
358 iov_to_buf(res
->iov
, res
->iov_cnt
, 0,
359 pixman_image_get_data(res
->image
),
360 pixman_image_get_stride(res
->image
)
361 * pixman_image_get_height(res
->image
));
365 static void virtio_gpu_resource_flush(VirtIOGPU
*g
,
366 struct virtio_gpu_ctrl_command
*cmd
)
368 struct virtio_gpu_simple_resource
*res
;
369 struct virtio_gpu_resource_flush rf
;
370 pixman_region16_t flush_region
;
373 VIRTIO_GPU_FILL_CMD(rf
);
374 trace_virtio_gpu_cmd_res_flush(rf
.resource_id
,
375 rf
.r
.width
, rf
.r
.height
, rf
.r
.x
, rf
.r
.y
);
377 res
= virtio_gpu_find_resource(g
, rf
.resource_id
);
379 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
380 __func__
, rf
.resource_id
);
381 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
385 if (rf
.r
.x
> res
->width
||
386 rf
.r
.y
> res
->height
||
387 rf
.r
.width
> res
->width
||
388 rf
.r
.height
> res
->height
||
389 rf
.r
.x
+ rf
.r
.width
> res
->width
||
390 rf
.r
.y
+ rf
.r
.height
> res
->height
) {
391 qemu_log_mask(LOG_GUEST_ERROR
, "%s: flush bounds outside resource"
392 " bounds for resource %d: %d %d %d %d vs %d %d\n",
393 __func__
, rf
.resource_id
, rf
.r
.x
, rf
.r
.y
,
394 rf
.r
.width
, rf
.r
.height
, res
->width
, res
->height
);
395 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER
;
399 pixman_region_init_rect(&flush_region
,
400 rf
.r
.x
, rf
.r
.y
, rf
.r
.width
, rf
.r
.height
);
401 for (i
= 0; i
< VIRTIO_GPU_MAX_SCANOUT
; i
++) {
402 struct virtio_gpu_scanout
*scanout
;
403 pixman_region16_t region
, finalregion
;
404 pixman_box16_t
*extents
;
406 if (!(res
->scanout_bitmask
& (1 << i
))) {
409 scanout
= &g
->scanout
[i
];
411 pixman_region_init(&finalregion
);
412 pixman_region_init_rect(®ion
, scanout
->x
, scanout
->y
,
413 scanout
->width
, scanout
->height
);
415 pixman_region_intersect(&finalregion
, &flush_region
, ®ion
);
416 pixman_region_translate(&finalregion
, -scanout
->x
, -scanout
->y
);
417 extents
= pixman_region_extents(&finalregion
);
418 /* work out the area we need to update for each console */
419 dpy_gfx_update(g
->scanout
[i
].con
,
420 extents
->x1
, extents
->y1
,
421 extents
->x2
- extents
->x1
,
422 extents
->y2
- extents
->y1
);
424 pixman_region_fini(®ion
);
425 pixman_region_fini(&finalregion
);
427 pixman_region_fini(&flush_region
);
430 static void virtio_gpu_set_scanout(VirtIOGPU
*g
,
431 struct virtio_gpu_ctrl_command
*cmd
)
433 struct virtio_gpu_simple_resource
*res
;
434 struct virtio_gpu_scanout
*scanout
;
435 pixman_format_code_t format
;
438 struct virtio_gpu_set_scanout ss
;
440 VIRTIO_GPU_FILL_CMD(ss
);
441 trace_virtio_gpu_cmd_set_scanout(ss
.scanout_id
, ss
.resource_id
,
442 ss
.r
.width
, ss
.r
.height
, ss
.r
.x
, ss
.r
.y
);
445 if (ss
.resource_id
== 0) {
446 scanout
= &g
->scanout
[ss
.scanout_id
];
447 if (scanout
->resource_id
) {
448 res
= virtio_gpu_find_resource(g
, scanout
->resource_id
);
450 res
->scanout_bitmask
&= ~(1 << ss
.scanout_id
);
453 if (ss
.scanout_id
== 0 ||
454 ss
.scanout_id
>= g
->conf
.max_outputs
) {
455 qemu_log_mask(LOG_GUEST_ERROR
,
456 "%s: illegal scanout id specified %d",
457 __func__
, ss
.scanout_id
);
458 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID
;
461 dpy_gfx_replace_surface(g
->scanout
[ss
.scanout_id
].con
, NULL
);
468 /* create a surface for this scanout */
469 if (ss
.scanout_id
>= VIRTIO_GPU_MAX_SCANOUT
||
470 ss
.scanout_id
>= g
->conf
.max_outputs
) {
471 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal scanout id specified %d",
472 __func__
, ss
.scanout_id
);
473 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID
;
477 res
= virtio_gpu_find_resource(g
, ss
.resource_id
);
479 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
480 __func__
, ss
.resource_id
);
481 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
485 if (ss
.r
.x
> res
->width
||
486 ss
.r
.y
> res
->height
||
487 ss
.r
.width
> res
->width
||
488 ss
.r
.height
> res
->height
||
489 ss
.r
.x
+ ss
.r
.width
> res
->width
||
490 ss
.r
.y
+ ss
.r
.height
> res
->height
) {
491 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal scanout %d bounds for"
492 " resource %d, (%d,%d)+%d,%d vs %d %d\n",
493 __func__
, ss
.scanout_id
, ss
.resource_id
, ss
.r
.x
, ss
.r
.y
,
494 ss
.r
.width
, ss
.r
.height
, res
->width
, res
->height
);
495 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER
;
499 scanout
= &g
->scanout
[ss
.scanout_id
];
501 format
= pixman_image_get_format(res
->image
);
502 bpp
= (PIXMAN_FORMAT_BPP(format
) + 7) / 8;
503 offset
= (ss
.r
.x
* bpp
) + ss
.r
.y
* pixman_image_get_stride(res
->image
);
504 if (!scanout
->ds
|| surface_data(scanout
->ds
)
505 != ((uint8_t *)pixman_image_get_data(res
->image
) + offset
) ||
506 scanout
->width
!= ss
.r
.width
||
507 scanout
->height
!= ss
.r
.height
) {
508 /* realloc the surface ptr */
509 scanout
->ds
= qemu_create_displaysurface_from
510 (ss
.r
.width
, ss
.r
.height
, format
,
511 pixman_image_get_stride(res
->image
),
512 (uint8_t *)pixman_image_get_data(res
->image
) + offset
);
514 cmd
->error
= VIRTIO_GPU_RESP_ERR_UNSPEC
;
517 dpy_gfx_replace_surface(g
->scanout
[ss
.scanout_id
].con
, scanout
->ds
);
520 res
->scanout_bitmask
|= (1 << ss
.scanout_id
);
521 scanout
->resource_id
= ss
.resource_id
;
524 scanout
->width
= ss
.r
.width
;
525 scanout
->height
= ss
.r
.height
;
528 int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing
*ab
,
529 struct virtio_gpu_ctrl_command
*cmd
,
532 struct virtio_gpu_mem_entry
*ents
;
536 if (ab
->nr_entries
> 16384) {
537 qemu_log_mask(LOG_GUEST_ERROR
,
538 "%s: nr_entries is too big (%d > 16384)\n",
539 __func__
, ab
->nr_entries
);
543 esize
= sizeof(*ents
) * ab
->nr_entries
;
544 ents
= g_malloc(esize
);
545 s
= iov_to_buf(cmd
->elem
.out_sg
, cmd
->elem
.out_num
,
546 sizeof(*ab
), ents
, esize
);
548 qemu_log_mask(LOG_GUEST_ERROR
,
549 "%s: command data size incorrect %zu vs %zu\n",
555 *iov
= g_malloc0(sizeof(struct iovec
) * ab
->nr_entries
);
556 for (i
= 0; i
< ab
->nr_entries
; i
++) {
557 hwaddr len
= ents
[i
].length
;
558 (*iov
)[i
].iov_len
= ents
[i
].length
;
559 (*iov
)[i
].iov_base
= cpu_physical_memory_map(ents
[i
].addr
, &len
, 1);
560 if (!(*iov
)[i
].iov_base
|| len
!= ents
[i
].length
) {
561 qemu_log_mask(LOG_GUEST_ERROR
, "%s: failed to map MMIO memory for"
562 " resource %d element %d\n",
563 __func__
, ab
->resource_id
, i
);
564 virtio_gpu_cleanup_mapping_iov(*iov
, i
);
575 void virtio_gpu_cleanup_mapping_iov(struct iovec
*iov
, uint32_t count
)
579 for (i
= 0; i
< count
; i
++) {
580 cpu_physical_memory_unmap(iov
[i
].iov_base
, iov
[i
].iov_len
, 1,
585 static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource
*res
)
587 virtio_gpu_cleanup_mapping_iov(res
->iov
, res
->iov_cnt
);
594 virtio_gpu_resource_attach_backing(VirtIOGPU
*g
,
595 struct virtio_gpu_ctrl_command
*cmd
)
597 struct virtio_gpu_simple_resource
*res
;
598 struct virtio_gpu_resource_attach_backing ab
;
601 VIRTIO_GPU_FILL_CMD(ab
);
602 trace_virtio_gpu_cmd_res_back_attach(ab
.resource_id
);
604 res
= virtio_gpu_find_resource(g
, ab
.resource_id
);
606 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
607 __func__
, ab
.resource_id
);
608 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
612 ret
= virtio_gpu_create_mapping_iov(&ab
, cmd
, &res
->iov
);
614 cmd
->error
= VIRTIO_GPU_RESP_ERR_UNSPEC
;
618 res
->iov_cnt
= ab
.nr_entries
;
622 virtio_gpu_resource_detach_backing(VirtIOGPU
*g
,
623 struct virtio_gpu_ctrl_command
*cmd
)
625 struct virtio_gpu_simple_resource
*res
;
626 struct virtio_gpu_resource_detach_backing detach
;
628 VIRTIO_GPU_FILL_CMD(detach
);
629 trace_virtio_gpu_cmd_res_back_detach(detach
.resource_id
);
631 res
= virtio_gpu_find_resource(g
, detach
.resource_id
);
632 if (!res
|| !res
->iov
) {
633 qemu_log_mask(LOG_GUEST_ERROR
, "%s: illegal resource specified %d\n",
634 __func__
, detach
.resource_id
);
635 cmd
->error
= VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID
;
638 virtio_gpu_cleanup_mapping(res
);
641 static void virtio_gpu_simple_process_cmd(VirtIOGPU
*g
,
642 struct virtio_gpu_ctrl_command
*cmd
)
644 VIRTIO_GPU_FILL_CMD(cmd
->cmd_hdr
);
646 switch (cmd
->cmd_hdr
.type
) {
647 case VIRTIO_GPU_CMD_GET_DISPLAY_INFO
:
648 virtio_gpu_get_display_info(g
, cmd
);
650 case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D
:
651 virtio_gpu_resource_create_2d(g
, cmd
);
653 case VIRTIO_GPU_CMD_RESOURCE_UNREF
:
654 virtio_gpu_resource_unref(g
, cmd
);
656 case VIRTIO_GPU_CMD_RESOURCE_FLUSH
:
657 virtio_gpu_resource_flush(g
, cmd
);
659 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D
:
660 virtio_gpu_transfer_to_host_2d(g
, cmd
);
662 case VIRTIO_GPU_CMD_SET_SCANOUT
:
663 virtio_gpu_set_scanout(g
, cmd
);
665 case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING
:
666 virtio_gpu_resource_attach_backing(g
, cmd
);
668 case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING
:
669 virtio_gpu_resource_detach_backing(g
, cmd
);
672 cmd
->error
= VIRTIO_GPU_RESP_ERR_UNSPEC
;
675 if (!cmd
->finished
) {
676 virtio_gpu_ctrl_response_nodata(g
, cmd
, cmd
->error
? cmd
->error
:
677 VIRTIO_GPU_RESP_OK_NODATA
);
681 static void virtio_gpu_handle_ctrl_cb(VirtIODevice
*vdev
, VirtQueue
*vq
)
683 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
684 qemu_bh_schedule(g
->ctrl_bh
);
687 static void virtio_gpu_handle_cursor_cb(VirtIODevice
*vdev
, VirtQueue
*vq
)
689 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
690 qemu_bh_schedule(g
->cursor_bh
);
693 static void virtio_gpu_handle_ctrl(VirtIODevice
*vdev
, VirtQueue
*vq
)
695 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
696 struct virtio_gpu_ctrl_command
*cmd
;
698 if (!virtio_queue_ready(vq
)) {
702 cmd
= g_new(struct virtio_gpu_ctrl_command
, 1);
703 while (virtqueue_pop(vq
, &cmd
->elem
)) {
706 cmd
->finished
= false;
709 virtio_gpu_simple_process_cmd(g
, cmd
);
710 if (!cmd
->finished
) {
711 QTAILQ_INSERT_TAIL(&g
->fenceq
, cmd
, next
);
713 if (g
->stats
.max_inflight
< g
->stats
.inflight
) {
714 g
->stats
.max_inflight
= g
->stats
.inflight
;
716 fprintf(stderr
, "inflight: %3d (+)\r", g
->stats
.inflight
);
717 cmd
= g_new(struct virtio_gpu_ctrl_command
, 1);
723 static void virtio_gpu_ctrl_bh(void *opaque
)
725 VirtIOGPU
*g
= opaque
;
726 virtio_gpu_handle_ctrl(&g
->parent_obj
, g
->ctrl_vq
);
729 static void virtio_gpu_handle_cursor(VirtIODevice
*vdev
, VirtQueue
*vq
)
731 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
732 VirtQueueElement elem
;
734 struct virtio_gpu_update_cursor cursor_info
;
736 if (!virtio_queue_ready(vq
)) {
739 while (virtqueue_pop(vq
, &elem
)) {
740 s
= iov_to_buf(elem
.out_sg
, elem
.out_num
, 0,
741 &cursor_info
, sizeof(cursor_info
));
742 if (s
!= sizeof(cursor_info
)) {
743 qemu_log_mask(LOG_GUEST_ERROR
,
744 "%s: cursor size incorrect %zu vs %zu\n",
745 __func__
, s
, sizeof(cursor_info
));
747 update_cursor(g
, &cursor_info
);
749 virtqueue_push(vq
, &elem
, 0);
750 virtio_notify(vdev
, vq
);
754 static void virtio_gpu_cursor_bh(void *opaque
)
756 VirtIOGPU
*g
= opaque
;
757 virtio_gpu_handle_cursor(&g
->parent_obj
, g
->cursor_vq
);
760 static void virtio_gpu_invalidate_display(void *opaque
)
764 static void virtio_gpu_update_display(void *opaque
)
768 static void virtio_gpu_text_update(void *opaque
, console_ch_t
*chardata
)
772 static int virtio_gpu_ui_info(void *opaque
, uint32_t idx
, QemuUIInfo
*info
)
774 VirtIOGPU
*g
= opaque
;
776 if (idx
> g
->conf
.max_outputs
) {
780 g
->req_state
[idx
].x
= info
->xoff
;
781 g
->req_state
[idx
].y
= info
->yoff
;
782 g
->req_state
[idx
].width
= info
->width
;
783 g
->req_state
[idx
].height
= info
->height
;
785 if (info
->width
&& info
->height
) {
786 g
->enabled_output_bitmask
|= (1 << idx
);
788 g
->enabled_output_bitmask
&= ~(1 << idx
);
791 /* send event to guest */
792 virtio_gpu_notify_event(g
, VIRTIO_GPU_EVENT_DISPLAY
);
796 const GraphicHwOps virtio_gpu_ops
= {
797 .invalidate
= virtio_gpu_invalidate_display
,
798 .gfx_update
= virtio_gpu_update_display
,
799 .text_update
= virtio_gpu_text_update
,
800 .ui_info
= virtio_gpu_ui_info
,
803 static void virtio_gpu_device_realize(DeviceState
*qdev
, Error
**errp
)
805 VirtIODevice
*vdev
= VIRTIO_DEVICE(qdev
);
806 VirtIOGPU
*g
= VIRTIO_GPU(qdev
);
809 g
->config_size
= sizeof(struct virtio_gpu_config
);
810 g
->virtio_config
.num_scanouts
= g
->conf
.max_outputs
;
811 virtio_init(VIRTIO_DEVICE(g
), "virtio-gpu", VIRTIO_ID_GPU
,
814 g
->req_state
[0].width
= 1024;
815 g
->req_state
[0].height
= 768;
817 g
->ctrl_vq
= virtio_add_queue(vdev
, 64, virtio_gpu_handle_ctrl_cb
);
818 g
->cursor_vq
= virtio_add_queue(vdev
, 16, virtio_gpu_handle_cursor_cb
);
820 g
->ctrl_bh
= qemu_bh_new(virtio_gpu_ctrl_bh
, g
);
821 g
->cursor_bh
= qemu_bh_new(virtio_gpu_cursor_bh
, g
);
822 QTAILQ_INIT(&g
->reslist
);
823 QTAILQ_INIT(&g
->fenceq
);
825 g
->enabled_output_bitmask
= 1;
828 for (i
= 0; i
< g
->conf
.max_outputs
; i
++) {
830 graphic_console_init(DEVICE(g
), i
, &virtio_gpu_ops
, g
);
832 dpy_gfx_replace_surface(g
->scanout
[i
].con
, NULL
);
837 static void virtio_gpu_instance_init(Object
*obj
)
841 static void virtio_gpu_reset(VirtIODevice
*vdev
)
843 VirtIOGPU
*g
= VIRTIO_GPU(vdev
);
844 struct virtio_gpu_simple_resource
*res
, *tmp
;
849 QTAILQ_FOREACH_SAFE(res
, &g
->reslist
, next
, tmp
) {
850 virtio_gpu_resource_destroy(g
, res
);
852 for (i
= 0; i
< g
->conf
.max_outputs
; i
++) {
854 g
->req_state
[i
].x
= 0;
855 g
->req_state
[i
].y
= 0;
857 g
->req_state
[0].width
= 1024;
858 g
->req_state
[0].height
= 768;
860 g
->req_state
[i
].width
= 0;
861 g
->req_state
[i
].height
= 0;
864 g
->scanout
[i
].resource_id
= 0;
865 g
->scanout
[i
].width
= 0;
866 g
->scanout
[i
].height
= 0;
869 g
->scanout
[i
].ds
= NULL
;
871 g
->enabled_output_bitmask
= 1;
874 static Property virtio_gpu_properties
[] = {
875 DEFINE_PROP_UINT32("max_outputs", VirtIOGPU
, conf
.max_outputs
, 1),
876 DEFINE_PROP_END_OF_LIST(),
879 static void virtio_gpu_class_init(ObjectClass
*klass
, void *data
)
881 DeviceClass
*dc
= DEVICE_CLASS(klass
);
882 VirtioDeviceClass
*vdc
= VIRTIO_DEVICE_CLASS(klass
);
884 vdc
->realize
= virtio_gpu_device_realize
;
885 vdc
->get_config
= virtio_gpu_get_config
;
886 vdc
->set_config
= virtio_gpu_set_config
;
887 vdc
->get_features
= virtio_gpu_get_features
;
889 vdc
->reset
= virtio_gpu_reset
;
891 dc
->props
= virtio_gpu_properties
;
894 static const TypeInfo virtio_gpu_info
= {
895 .name
= TYPE_VIRTIO_GPU
,
896 .parent
= TYPE_VIRTIO_DEVICE
,
897 .instance_size
= sizeof(VirtIOGPU
),
898 .instance_init
= virtio_gpu_instance_init
,
899 .class_init
= virtio_gpu_class_init
,
902 static void virtio_register_types(void)
904 type_register_static(&virtio_gpu_info
);
907 type_init(virtio_register_types
)
909 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr
) != 24);
910 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor
) != 56);
911 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref
) != 32);
912 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d
) != 40);
913 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout
) != 48);
914 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush
) != 48);
915 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d
) != 56);
916 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry
) != 16);
917 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing
) != 32);
918 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing
) != 32);
919 QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info
) != 408);