@@ -49,6 +49,7 @@ struct vgpu_resource_2d {
4949 uint32_t stride ;
5050 uint32_t bits_per_pixel ;
5151 uint32_t * image ;
52+ bool scanout_attached ;
5253 /* Private: */
5354 uint32_t resource_id ;
5455 size_t page_cnt ;
@@ -169,6 +170,22 @@ PACKED(struct virtio_gpu_ctx_create {
169170 char debug_name [64 ];
170171});
171172
173+ PACKED (struct virtio_gpu_cursor_pos {
174+ uint32_t scanout_id ;
175+ uint32_t x ;
176+ uint32_t y ;
177+ uint32_t padding ;
178+ });
179+
180+ PACKED (struct virtio_gpu_update_cursor {
181+ struct vgpu_ctrl_hdr hdr ;
182+ struct virtio_gpu_cursor_pos pos ;
183+ uint32_t resource_id ;
184+ uint32_t hot_x ;
185+ uint32_t hot_y ;
186+ uint32_t padding ;
187+ });
188+
172189/* clang-format off */
173190PACKED (struct virtio_gpu_ctx_destroy {
174191 struct vgpu_ctrl_hdr hdr ;
@@ -244,6 +261,7 @@ static struct vgpu_resource_2d *create_vgpu_resource_2d(int resource_id)
244261 return NULL ;
245262
246263 res -> resource_id = resource_id ;
264+ res -> scanout_attached = false;
247265 list_add (& res -> list , & vgpu_res_2d_list );
248266 return res ;
249267}
@@ -267,15 +285,18 @@ static int destroy_vgpu_resource_2d(uint32_t resource_id)
267285 if (!res_2d )
268286 return -1 ;
269287
270- window_lock (resource_id );
288+ int scanout_id = res_2d -> scanout_id ;
289+ if (res_2d -> scanout_attached )
290+ window_lock (scanout_id );
271291
272292 /* Release the resource */
273293 free (res_2d -> image );
274294 list_del (& res_2d -> list );
275295 free (res_2d -> iovec );
276296 free (res_2d );
277297
278- window_unlock (resource_id );
298+ if (res_2d -> scanout_attached )
299+ window_unlock (scanout_id );
279300
280301 return 0 ;
281302}
@@ -629,9 +650,11 @@ static void virtio_gpu_cmd_set_scanout_handler(virtio_gpu_state_t *vgpu,
629650
630651 /* Linux's virtio-gpu driver may send scanout command
631652 * even if the resource does not exist */
632- if (res_2d )
653+ if (res_2d ) {
633654 /* Set scanout ID to proper 2D resource */
634655 res_2d -> scanout_id = request -> scanout_id ;
656+ res_2d -> scanout_attached = true;
657+ }
635658
636659 /* Write response */
637660 struct vgpu_ctrl_hdr * response =
@@ -657,7 +680,9 @@ static void virtio_gpu_cmd_resource_flush_handler(virtio_gpu_state_t *vgpu,
657680 acquire_vgpu_resource_2d (request -> resource_id );
658681
659682 /* Trigger display window rendering */
683+ window_lock (res_2d -> scanout_id );
660684 window_render ((struct gpu_resource * ) res_2d );
685+ window_unlock (res_2d -> scanout_id );
661686
662687 /* Write response */
663688 struct vgpu_ctrl_hdr * response =
@@ -670,36 +695,9 @@ static void virtio_gpu_cmd_resource_flush_handler(virtio_gpu_state_t *vgpu,
670695 * plen = sizeof (* response );
671696}
672697
673- static void virtio_gpu_cmd_transfer_to_host_2d_handler (
674- virtio_gpu_state_t * vgpu ,
675- struct virtq_desc * vq_desc ,
676- uint32_t * plen )
698+ static void virtio_gpu_copy_image_from_pages (struct vgpu_trans_to_host_2d * req ,
699+ struct vgpu_resource_2d * res_2d )
677700{
678- /* Read request */
679- struct vgpu_trans_to_host_2d * req =
680- vgpu_mem_host_to_guest (vgpu , vq_desc [0 ].addr );
681-
682- /* Acquire 2D resource */
683- struct vgpu_resource_2d * res_2d =
684- acquire_vgpu_resource_2d (req -> resource_id );
685-
686- if (!res_2d ) {
687- fprintf (stderr , "%s(): Failed to find 2D resource\n" , __func__ );
688- virtio_gpu_set_fail (vgpu );
689- return ;
690- }
691-
692- /* Check image boundary */
693- if (req -> r .x > res_2d -> width || req -> r .y > res_2d -> height ||
694- req -> r .width > res_2d -> width || req -> r .height > res_2d -> height ||
695- req -> r .x + req -> r .width > res_2d -> width ||
696- req -> r .y + req -> r .height > res_2d -> height ) {
697- fprintf (stderr , "%s(): Invalid image size\n" , __func__ );
698- virtio_gpu_set_fail (vgpu );
699- return ;
700- }
701-
702- /* Transfer frame data from guest to host */
703701 uint32_t stride = res_2d -> stride ;
704702 uint32_t bpp = res_2d -> bits_per_pixel / 8 ; /* Bytes per pixel */
705703 uint32_t width =
@@ -752,6 +750,54 @@ static void virtio_gpu_cmd_transfer_to_host_2d_handler(
752750 }
753751 }
754752 }
753+ }
754+
755+ static void virtio_gpu_cursor_image_copy (struct vgpu_resource_2d * res_2d )
756+ {
757+ /* The cursor resource is tightly packed and contiguous */
758+ memcpy (res_2d -> image , res_2d -> iovec [0 ].iov_base ,
759+ sizeof (uint32_t ) * CURSOR_WIDTH * CURSOR_HEIGHT );
760+ }
761+
762+ static void virtio_gpu_cmd_transfer_to_host_2d_handler (
763+ virtio_gpu_state_t * vgpu ,
764+ struct virtq_desc * vq_desc ,
765+ uint32_t * plen )
766+ {
767+ /* Read request */
768+ struct vgpu_trans_to_host_2d * req =
769+ vgpu_mem_host_to_guest (vgpu , vq_desc [0 ].addr );
770+
771+ /* Acquire 2D resource */
772+ struct vgpu_resource_2d * res_2d =
773+ acquire_vgpu_resource_2d (req -> resource_id );
774+
775+ if (!res_2d ) {
776+ fprintf (stderr , "%s(): Failed to find 2D resource\n" , __func__ );
777+ virtio_gpu_set_fail (vgpu );
778+ return ;
779+ }
780+
781+ /* Check image boundary */
782+ if (req -> r .x > res_2d -> width || req -> r .y > res_2d -> height ||
783+ req -> r .width > res_2d -> width || req -> r .height > res_2d -> height ||
784+ req -> r .x + req -> r .width > res_2d -> width ||
785+ req -> r .y + req -> r .height > res_2d -> height ) {
786+ fprintf (stderr , "%s(): Invalid image size\n" , __func__ );
787+ virtio_gpu_set_fail (vgpu );
788+ return ;
789+ }
790+
791+ uint32_t width =
792+ (req -> r .width < res_2d -> width ) ? req -> r .width : res_2d -> width ;
793+ uint32_t height =
794+ (req -> r .height < res_2d -> height ) ? req -> r .height : res_2d -> height ;
795+
796+ /* Transfer frame data from guest to host */
797+ if (width == CURSOR_WIDTH && height == CURSOR_HEIGHT )
798+ virtio_gpu_cursor_image_copy (res_2d );
799+ else
800+ virtio_gpu_copy_image_from_pages (req , res_2d );
755801
756802 /* Write response */
757803 struct vgpu_ctrl_hdr * response =
@@ -819,6 +865,27 @@ static void virtio_gpu_cmd_update_cursor_handler(virtio_gpu_state_t *vgpu,
819865 struct virtq_desc * vq_desc ,
820866 uint32_t * plen )
821867{
868+ /* Read request */
869+ struct virtio_gpu_update_cursor * cursor =
870+ vgpu_mem_host_to_guest (vgpu , vq_desc [0 ].addr );
871+
872+ /* Update cursor image */
873+ struct vgpu_resource_2d * res_2d =
874+ acquire_vgpu_resource_2d (cursor -> resource_id );
875+
876+ if (res_2d != NULL ) {
877+ window_lock (cursor -> pos .scanout_id );
878+ cursor_update ((struct gpu_resource * ) res_2d , cursor -> pos .scanout_id ,
879+ cursor -> pos .x , cursor -> pos .y );
880+ window_unlock (cursor -> pos .scanout_id );
881+ } else if (cursor -> resource_id == 0 ) {
882+ window_lock (cursor -> pos .scanout_id );
883+ cursor_clear (cursor -> pos .scanout_id );
884+ window_unlock (cursor -> pos .scanout_id );
885+ } else {
886+ fprintf (stderr , "Invalid resource ID %d.\n" , cursor -> resource_id );
887+ }
888+
822889 /* Write response */
823890 struct vgpu_ctrl_hdr * response =
824891 vgpu_mem_host_to_guest (vgpu , vq_desc [1 ].addr );
@@ -834,6 +901,15 @@ static void virtio_gpu_cmd_move_cursor_handler(virtio_gpu_state_t *vgpu,
834901 struct virtq_desc * vq_desc ,
835902 uint32_t * plen )
836903{
904+ /* Read request */
905+ struct virtio_gpu_update_cursor * cursor =
906+ vgpu_mem_host_to_guest (vgpu , vq_desc [0 ].addr );
907+
908+ /* Move cursor to new position */
909+ window_lock (cursor -> pos .scanout_id );
910+ cursor_move (cursor -> pos .scanout_id , cursor -> pos .x , cursor -> pos .y );
911+ window_unlock (cursor -> pos .scanout_id );
912+
837913 /* Write response */
838914 struct vgpu_ctrl_hdr * response =
839915 vgpu_mem_host_to_guest (vgpu , vq_desc [1 ].addr );
0 commit comments