Skip to content

Commit 18d5ff7

Browse files
committed
[WIP] Implement cursor plane rendering for VirtIO GPU
1 parent 7074c77 commit 18d5ff7

File tree

3 files changed

+131
-12
lines changed

3 files changed

+131
-12
lines changed

virtio-gpu.c

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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 */
173190
PACKED(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
}
@@ -617,9 +638,11 @@ static void virtio_gpu_cmd_set_scanout_handler(virtio_gpu_state_t *vgpu,
617638

618639
/* Linux's virtio-gpu driver may send scanout command
619640
* even if the resource does not exist */
620-
if (res_2d)
641+
if (res_2d) {
621642
/* Set scanout ID to proper 2D resource */
622643
res_2d->scanout_id = request->scanout_id;
644+
res_2d->scanout_attached = true;
645+
}
623646

624647
/* Write response */
625648
struct vgpu_ctrl_hdr *response =
@@ -645,7 +668,9 @@ static void virtio_gpu_cmd_resource_flush_handler(virtio_gpu_state_t *vgpu,
645668
acquire_vgpu_resource_2d(request->resource_id);
646669

647670
/* Trigger display window rendering */
671+
window_lock(res_2d->scanout_id);
648672
window_render((struct gpu_resource *) res_2d);
673+
window_unlock(res_2d->scanout_id);
649674

650675
/* Write response */
651676
struct vgpu_ctrl_hdr *response =
@@ -801,6 +826,19 @@ static void virtio_gpu_cmd_update_cursor_handler(virtio_gpu_state_t *vgpu,
801826
struct virtq_desc *vq_desc,
802827
uint32_t *plen)
803828
{
829+
/* Read request */
830+
struct virtio_gpu_update_cursor *cursor =
831+
vgpu_mem_host_to_guest(vgpu, vq_desc[0].addr);
832+
833+
/* Update cursor image */
834+
struct vgpu_resource_2d *res_2d =
835+
acquire_vgpu_resource_2d(cursor->resource_id);
836+
837+
window_lock(cursor->pos.scanout_id);
838+
cursor_update((struct gpu_resource *) res_2d, cursor->pos.scanout_id,
839+
cursor->pos.x, cursor->pos.y);
840+
window_unlock(cursor->pos.scanout_id);
841+
804842
/* Write response */
805843
struct vgpu_ctrl_hdr *response =
806844
vgpu_mem_host_to_guest(vgpu, vq_desc[1].addr);
@@ -816,6 +854,15 @@ static void virtio_gpu_cmd_move_cursor_handler(virtio_gpu_state_t *vgpu,
816854
struct virtq_desc *vq_desc,
817855
uint32_t *plen)
818856
{
857+
/* Read request */
858+
struct virtio_gpu_update_cursor *cursor =
859+
vgpu_mem_host_to_guest(vgpu, vq_desc[0].addr);
860+
861+
/* Move cursor to new position */
862+
window_lock(cursor->pos.scanout_id);
863+
cursor_move(cursor->pos.scanout_id, cursor->pos.x, cursor->pos.y);
864+
window_unlock(cursor->pos.scanout_id);
865+
819866
/* Write response */
820867
struct vgpu_ctrl_hdr *response =
821868
vgpu_mem_host_to_guest(vgpu, vq_desc[1].addr);

window.c

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ struct key_map_entry key_map[] = {
128128

129129
struct display_info {
130130
struct gpu_resource resource;
131+
struct gpu_resource cursor;
132+
int cursor_x, cursor_y;
133+
uint32_t cursor_sdl_format;
134+
int render_type;
131135
uint32_t sdl_format;
132136
SDL_mutex *img_mtx;
133137
SDL_cond *img_cond;
@@ -203,6 +207,7 @@ static int window_thread(void *data)
203207
{
204208
struct display_info *display = (struct display_info *) data;
205209
struct gpu_resource *resource = &display->resource;
210+
struct gpu_resource *cursor = &display->cursor;
206211

207212
/* Create SDL window */
208213
display->window = SDL_CreateWindow("semu", SDL_WINDOWPOS_UNDEFINED,
@@ -232,6 +237,8 @@ static int window_thread(void *data)
232237
((struct display_info *) data)->ev_thread =
233238
SDL_CreateThread(event_thread, NULL, data);
234239

240+
SDL_Texture *cursor_texture = NULL;
241+
235242
while (1) {
236243
SDL_LockMutex(display->img_mtx);
237244

@@ -240,15 +247,40 @@ static int window_thread(void *data)
240247
SDL_COND_TIMEOUT))
241248
;
242249

243-
/* Render image */
244-
display->surface = SDL_CreateRGBSurfaceWithFormatFrom(
245-
resource->image, resource->width, resource->height,
246-
resource->bits_per_pixel, resource->stride, display->sdl_format);
247-
display->texture =
248-
SDL_CreateTextureFromSurface(display->renderer, display->surface);
249-
SDL_RenderCopy(display->renderer, display->texture, NULL, NULL);
250-
SDL_RenderPresent(display->renderer);
251-
SDL_DestroyTexture(display->texture);
250+
if (display->render_type == RENDER_PRIMARY_PLANE) {
251+
/* Render main plane */
252+
display->surface = SDL_CreateRGBSurfaceWithFormatFrom(
253+
resource->image, resource->width, resource->height,
254+
resource->bits_per_pixel, resource->stride,
255+
display->sdl_format);
256+
display->texture = SDL_CreateTextureFromSurface(display->renderer,
257+
display->surface);
258+
SDL_RenderCopy(display->renderer, display->texture, NULL, NULL);
259+
SDL_RenderPresent(display->renderer);
260+
SDL_DestroyTexture(display->texture);
261+
SDL_FreeSurface(display->surface);
262+
} else if (display->render_type == RENDER_CURSOR_PLANE) {
263+
SDL_Rect cursor_rect = {
264+
.x = display->cursor_x,
265+
.y = display->cursor_y,
266+
.w = cursor->width,
267+
.h = cursor->height,
268+
};
269+
270+
display->surface = SDL_CreateRGBSurfaceWithFormatFrom(
271+
cursor->image, cursor->width, cursor->height,
272+
cursor->bits_per_pixel, cursor->stride,
273+
display->cursor_sdl_format);
274+
275+
cursor_texture = SDL_CreateTextureFromSurface(display->renderer,
276+
display->surface);
277+
SDL_SetTextureBlendMode(display->texture, SDL_BLENDMODE_BLEND);
278+
SDL_RenderCopy(display->renderer, cursor_texture, NULL,
279+
&cursor_rect);
280+
SDL_RenderPresent(display->renderer);
281+
SDL_DestroyTexture(cursor_texture);
282+
SDL_FreeSurface(display->surface);
283+
}
252284

253285
SDL_UnlockMutex(display->img_mtx);
254286
}
@@ -314,6 +346,39 @@ static bool virtio_gpu_to_sdl_format(uint32_t virtio_gpu_format,
314346
}
315347
}
316348

349+
void cursor_update(struct gpu_resource *resource, int scanout_id, int x, int y)
350+
{
351+
displays[scanout_id].render_type = RENDER_CURSOR_PLANE;
352+
displays[scanout_id].cursor_x = x;
353+
displays[scanout_id].cursor_y = y;
354+
355+
/* Resource update */
356+
memcpy(&displays[scanout_id].cursor, resource, sizeof(struct gpu_resource));
357+
358+
/* TODO: Cursor image copy (which involves stride calculation, ARGB
359+
* ordering, etc.) Without saving the cursor image properlly, the cursor can
360+
* not be rendered correctly on the screen. The user should currently only
361+
* expect to see a black square moving on the screen) */
362+
363+
bool legal_format = virtio_gpu_to_sdl_format(
364+
resource->format, &displays[scanout_id].cursor_sdl_format);
365+
366+
if (legal_format) {
367+
SDL_CondSignal(displays[scanout_id].img_cond);
368+
} else {
369+
exit(2);
370+
}
371+
}
372+
373+
void cursor_move(int scanout_id, int x, int y)
374+
{
375+
displays[scanout_id].render_type = RENDER_CURSOR_PLANE;
376+
displays[scanout_id].cursor_x = x;
377+
displays[scanout_id].cursor_y = y;
378+
379+
SDL_CondSignal(displays[scanout_id].img_cond);
380+
}
381+
317382
void window_render(struct gpu_resource *resource)
318383
{
319384
int id = resource->scanout_id;

window.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
#pragma once
22

3+
enum {
4+
RENDER_PRIMARY_PLANE,
5+
RENDER_CURSOR_PLANE,
6+
};
7+
38
#if SEMU_HAS(VIRTIOGPU)
49
/* Public interface to the vgpu_resource_2d structure */
510
struct gpu_resource {
@@ -15,6 +20,8 @@ struct gpu_resource {
1520
void window_init(void);
1621
void window_add(uint32_t width, uint32_t height);
1722
void window_render(struct gpu_resource *resource);
23+
void cursor_update(struct gpu_resource *resource, int scanout_id, int x, int y);
24+
void cursor_move(int scanout_id, int x, int y);
1825
void window_lock(uint32_t id);
1926
void window_unlock(uint32_t id);
2027
#endif

0 commit comments

Comments
 (0)