Skip to content

Commit b000a89

Browse files
committed
[WIP] Implement cursor plane rendering for VirtIO GPU
1 parent 7e2c711 commit b000a89

File tree

3 files changed

+176
-20
lines changed

3 files changed

+176
-20
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
}
@@ -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 =
@@ -819,6 +844,19 @@ static void virtio_gpu_cmd_update_cursor_handler(virtio_gpu_state_t *vgpu,
819844
struct virtq_desc *vq_desc,
820845
uint32_t *plen)
821846
{
847+
/* Read request */
848+
struct virtio_gpu_update_cursor *cursor =
849+
vgpu_mem_host_to_guest(vgpu, vq_desc[0].addr);
850+
851+
/* Update cursor image */
852+
struct vgpu_resource_2d *res_2d =
853+
acquire_vgpu_resource_2d(cursor->resource_id);
854+
855+
window_lock(cursor->pos.scanout_id);
856+
cursor_update((struct gpu_resource *) res_2d, cursor->pos.scanout_id,
857+
cursor->pos.x, cursor->pos.y);
858+
window_unlock(cursor->pos.scanout_id);
859+
822860
/* Write response */
823861
struct vgpu_ctrl_hdr *response =
824862
vgpu_mem_host_to_guest(vgpu, vq_desc[1].addr);
@@ -834,6 +872,15 @@ static void virtio_gpu_cmd_move_cursor_handler(virtio_gpu_state_t *vgpu,
834872
struct virtq_desc *vq_desc,
835873
uint32_t *plen)
836874
{
875+
/* Read request */
876+
struct virtio_gpu_update_cursor *cursor =
877+
vgpu_mem_host_to_guest(vgpu, vq_desc[0].addr);
878+
879+
/* Move cursor to new position */
880+
window_lock(cursor->pos.scanout_id);
881+
cursor_move(cursor->pos.scanout_id, cursor->pos.x, cursor->pos.y);
882+
window_unlock(cursor->pos.scanout_id);
883+
837884
/* Write response */
838885
struct vgpu_ctrl_hdr *response =
839886
vgpu_mem_host_to_guest(vgpu, vq_desc[1].addr);

window.c

Lines changed: 118 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,27 @@ struct key_map_entry key_map[] = {
127127
};
128128

129129
struct display_info {
130+
/* Request type: primary or cursor */
131+
int render_type;
132+
133+
/* Primary plane */
130134
struct gpu_resource resource;
131-
uint32_t sdl_format;
135+
uint32_t primary_sdl_format;
136+
SDL_Texture *primary_texture;
137+
138+
/* Cursor plane */
139+
struct gpu_resource cursor;
140+
uint32_t cursor_sdl_format;
141+
uint32_t *cursor_img;
142+
SDL_Rect cursor_rect; /* Cursor size and position */
143+
SDL_Texture *cursor_texture;
144+
132145
SDL_mutex *img_mtx;
133146
SDL_cond *img_cond;
134147
SDL_Thread *win_thread;
135148
SDL_Thread *ev_thread;
136149
SDL_Window *window;
137150
SDL_Renderer *renderer;
138-
SDL_Surface *surface;
139-
SDL_Texture *texture;
140151
};
141152

142153
static struct display_info displays[VIRTIO_GPU_MAX_SCANOUTS];
@@ -203,6 +214,7 @@ static int window_thread(void *data)
203214
{
204215
struct display_info *display = (struct display_info *) data;
205216
struct gpu_resource *resource = &display->resource;
217+
struct gpu_resource *cursor = &display->cursor;
206218

207219
/* Create SDL window */
208220
display->window = SDL_CreateWindow("semu", SDL_WINDOWPOS_UNDEFINED,
@@ -223,6 +235,9 @@ static int window_thread(void *data)
223235
exit(2);
224236
}
225237

238+
/* FIXME */
239+
SDL_SetRenderDrawBlendMode(display->renderer, SDL_BLENDMODE_BLEND);
240+
226241
/* Render the whole screen with black color */
227242
SDL_SetRenderDrawColor(display->renderer, 0, 0, 0, 255);
228243
SDL_RenderClear(display->renderer);
@@ -232,24 +247,56 @@ static int window_thread(void *data)
232247
((struct display_info *) data)->ev_thread =
233248
SDL_CreateThread(event_thread, NULL, data);
234249

250+
SDL_Surface *surface;
251+
235252
while (1) {
253+
/* Mutex lock */
236254
SDL_LockMutex(display->img_mtx);
237255

238256
/* Wait until the image is arrived */
239257
while (SDL_CondWaitTimeout(display->img_cond, display->img_mtx,
240258
SDL_COND_TIMEOUT))
241259
;
242260

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);
261+
if (display->render_type == RENDER_PRIMARY_PLANE) {
262+
/* Generate primary plane texture */
263+
surface = SDL_CreateRGBSurfaceWithFormatFrom(
264+
resource->image, resource->width, resource->height,
265+
resource->bits_per_pixel, resource->stride,
266+
display->primary_sdl_format);
267+
268+
SDL_DestroyTexture(display->primary_texture);
269+
display->primary_texture =
270+
SDL_CreateTextureFromSurface(display->renderer, surface);
271+
SDL_FreeSurface(surface);
272+
} else if (display->render_type == UPDATE_CURSOR_IMAGE) {
273+
/* Generate cursor plane texture */
274+
surface = SDL_CreateRGBSurfaceWithFormatFrom(
275+
cursor->image, cursor->width, cursor->height,
276+
cursor->bits_per_pixel, cursor->stride,
277+
/*display->cursor_sdl_format*/
278+
SDL_PIXELFORMAT_RGBA32 /* FIXME */);
279+
280+
SDL_DestroyTexture(display->cursor_texture);
281+
display->cursor_texture =
282+
SDL_CreateTextureFromSurface(display->renderer, surface);
283+
SDL_FreeSurface(surface);
284+
}
285+
286+
/* Render primary and cursor planes */
287+
SDL_RenderClear(display->renderer);
288+
289+
if (display->primary_texture)
290+
SDL_RenderCopy(display->renderer, display->primary_texture, NULL,
291+
NULL);
292+
293+
if (display->cursor_texture)
294+
SDL_RenderCopy(display->renderer, display->cursor_texture, NULL,
295+
&display->cursor_rect);
296+
250297
SDL_RenderPresent(display->renderer);
251-
SDL_DestroyTexture(display->texture);
252298

299+
/* Mutex unlock */
253300
SDL_UnlockMutex(display->img_mtx);
254301
}
255302
}
@@ -314,15 +361,69 @@ static bool virtio_gpu_to_sdl_format(uint32_t virtio_gpu_format,
314361
}
315362
}
316363

364+
void cursor_update(struct gpu_resource *resource, int scanout_id, int x, int y)
365+
{
366+
/* Convert virtio-gpu resource format to SDL format */
367+
uint32_t sdl_format;
368+
bool legal_format = virtio_gpu_to_sdl_format(resource->format, &sdl_format);
369+
370+
if (!legal_format) {
371+
fprintf(stderr, "Invalid resource format.\n");
372+
return;
373+
}
374+
375+
/* Update cursor information */
376+
struct display_info *display = &displays[scanout_id];
377+
display->cursor_rect.x = x;
378+
display->cursor_rect.y = y;
379+
display->cursor_rect.w = resource->width;
380+
display->cursor_rect.h = resource->height;
381+
display->cursor_sdl_format = sdl_format;
382+
383+
/* Cursor resource update */
384+
memcpy(&display->cursor, resource, sizeof(struct gpu_resource));
385+
size_t pixels_size = sizeof(uint32_t) * resource->width * resource->height;
386+
free(display->cursor_img); /* FIXME */
387+
display->cursor_img = malloc(pixels_size);
388+
display->cursor.image = display->cursor_img;
389+
memcpy(display->cursor_img, resource->image, pixels_size);
390+
391+
/* Trigger cursor rendering */
392+
display->render_type = UPDATE_CURSOR_IMAGE;
393+
SDL_CondSignal(display->img_cond);
394+
}
395+
396+
void cursor_move(int scanout_id, int x, int y)
397+
{
398+
/* Update cursor position */
399+
struct display_info *display = &displays[scanout_id];
400+
display->cursor_rect.x = x;
401+
display->cursor_rect.y = y;
402+
403+
/* Trigger cursor rendering */
404+
display->render_type = MOVE_CURSOR;
405+
SDL_CondSignal(display->img_cond);
406+
}
407+
317408
void window_render(struct gpu_resource *resource)
318409
{
319410
int id = resource->scanout_id;
411+
struct display_info *display = &displays[id];
412+
413+
/* Convert virtio-gpu resource format to SDL format */
414+
uint32_t sdl_format;
415+
bool legal_format = virtio_gpu_to_sdl_format(resource->format, &sdl_format);
416+
417+
if (!legal_format) {
418+
fprintf(stderr, "Invalid resource format.\n");
419+
return;
420+
}
320421

321-
/* Resource update */
322-
memcpy(&displays[id].resource, resource, sizeof(struct gpu_resource));
323-
bool legal_format =
324-
virtio_gpu_to_sdl_format(resource->format, &displays[id].sdl_format);
422+
/* Update main plane resource */
423+
display->primary_sdl_format = sdl_format;
424+
memcpy(&display->resource, resource, sizeof(struct gpu_resource));
325425

326-
if (legal_format)
327-
SDL_CondSignal(displays[id].img_cond);
426+
/* Trigger main plane rendering */
427+
displays[id].render_type = RENDER_PRIMARY_PLANE;
428+
SDL_CondSignal(display->img_cond);
328429
}

window.h

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

3+
enum {
4+
RENDER_PRIMARY_PLANE,
5+
UPDATE_CURSOR_IMAGE,
6+
MOVE_CURSOR,
7+
};
8+
39
#if SEMU_HAS(VIRTIOGPU)
410
/* Public interface to the vgpu_resource_2d structure */
511
struct gpu_resource {
@@ -15,6 +21,8 @@ struct gpu_resource {
1521
void window_init(void);
1622
void window_add(uint32_t width, uint32_t height);
1723
void window_render(struct gpu_resource *resource);
24+
void cursor_update(struct gpu_resource *resource, int scanout_id, int x, int y);
25+
void cursor_move(int scanout_id, int x, int y);
1826
void window_lock(uint32_t id);
1927
void window_unlock(uint32_t id);
2028
#endif

0 commit comments

Comments
 (0)