[Spice-devel] [PATCH v3 8/9] Handle GL_DRAW messages
Frediano Ziglio
fziglio at redhat.com
Thu Feb 4 15:25:53 UTC 2016
>
> Create an async, and marshall the GL_DRAW message. Count number of
> clients, and wait until gl_draw_async_count is 0 to complete the async.
> The count is going to be updated in the following patch when the client
> is done with the draw.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau at gmail.com>
> ---
> server/dcc-send.c | 14 ++++++++++++++
> server/dcc.c | 23 +++++++++++++++++++++++
> server/dcc.h | 9 +++++++++
> server/display-channel.c | 22 ++++++++++++++++++++++
> server/display-channel.h | 3 +++
> server/red-dispatcher.c | 14 ++++++++++++++
> server/red-dispatcher.h | 1 +
> server/red-worker.c | 14 ++++++++++++++
> server/reds.h | 1 +
> 9 files changed, 101 insertions(+)
>
> diff --git a/server/dcc-send.c b/server/dcc-send.c
> index a9cc19c..3af5760 100644
> --- a/server/dcc-send.c
> +++ b/server/dcc-send.c
> @@ -2321,6 +2321,17 @@ end:
> pthread_mutex_unlock(&qxl->st->scanout_mutex);
> }
>
> +static void marshall_gl_draw(RedChannelClient *rcc,
> + SpiceMarshaller *m,
> + PipeItem *item)
> +{
> + GlDrawItem *p = SPICE_CONTAINEROF(item, GlDrawItem, base);
> +
> + red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_GL_DRAW, NULL);
> + spice_marshall_msg_display_gl_draw(m, &p->draw);
> +}
> +
> +
> static void begin_send_message(RedChannelClient *rcc)
> {
> DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> @@ -2435,6 +2446,9 @@ void dcc_send_item(DisplayChannelClient *dcc, PipeItem
> *pipe_item)
> case PIPE_ITEM_TYPE_GL_SCANOUT:
> marshall_gl_scanout(rcc, m, pipe_item);
> break;
> + case PIPE_ITEM_TYPE_GL_DRAW:
> + marshall_gl_draw(rcc, m, pipe_item);
> + break;
> default:
> spice_warn_if_reached();
> }
> diff --git a/server/dcc.c b/server/dcc.c
> index 58ae55c..6972616 100644
> --- a/server/dcc.c
> +++ b/server/dcc.c
> @@ -586,6 +586,27 @@ PipeItem *dcc_gl_scanout_item_new(RedChannelClient *rcc,
> void *data, int num)
> return &item->base;
> }
>
> +PipeItem *dcc_gl_draw_item_new(RedChannelClient *rcc, void *data, int num)
> +{
> + DisplayChannelClient *dcc = RCC_TO_DCC(rcc);
> + const SpiceMsgDisplayGlDraw *draw = data;
> + GlDrawItem *item = spice_new(GlDrawItem, 1);
> + spice_return_val_if_fail(item != NULL, NULL);
> +
> + if (!red_channel_client_test_remote_cap(rcc,
> SPICE_DISPLAY_CAP_GL_SCANOUT)) {
> + spice_printerr("FIXME: client does not support GL scanout");
> + red_channel_client_disconnect(rcc);
> + return NULL;
> + }
> +
> + dcc->gl_draw_ongoing = TRUE;
> + item->draw = *draw;
> + red_channel_pipe_item_init(rcc->channel, &item->base,
> + PIPE_ITEM_TYPE_GL_DRAW);
> +
> + return &item->base;
> +}
> +
> void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
> {
> DisplayChannel *display;
> @@ -1558,6 +1579,7 @@ static void
> release_item_after_push(DisplayChannelClient *dcc, PipeItem *item)
> image_item_unref((ImageItem *)item);
> break;
> case PIPE_ITEM_TYPE_GL_SCANOUT:
> + case PIPE_ITEM_TYPE_GL_DRAW:
> case PIPE_ITEM_TYPE_VERB:
> free(item);
> break;
> @@ -1633,6 +1655,7 @@ static void
> release_item_before_push(DisplayChannelClient *dcc, PipeItem *item)
> case PIPE_ITEM_TYPE_INVAL_PALETTE_CACHE:
> case PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT:
> case PIPE_ITEM_TYPE_GL_SCANOUT:
> + case PIPE_ITEM_TYPE_GL_DRAW:
> free(item);
> break;
> default:
> diff --git a/server/dcc.h b/server/dcc.h
> index 4ef6073..842b7d4 100644
> --- a/server/dcc.h
> +++ b/server/dcc.h
> @@ -111,6 +111,7 @@ struct DisplayChannelClient {
> int use_mjpeg_encoder_rate_control;
> uint32_t streams_max_latency;
> uint64_t streams_max_bit_rate;
> + bool gl_draw_ongoing;
> };
>
> #define DCC_TO_WORKER(dcc) \
> @@ -128,6 +129,12 @@ typedef struct GlScanoutUnixItem {
> PipeItem base;
> } GlScanoutUnixItem;
>
> +typedef struct GlDrawItem {
> + PipeItem base;
> + SpiceMsgDisplayGlDraw draw;
> + int sent;
> +} GlDrawItem;
> +
> typedef struct ImageItem {
> PipeItem link;
> int refs;
> @@ -213,6 +220,8 @@ int dcc_drawable_is_in_pipe
> (DisplayCha
> Drawable
> *drawable);
> PipeItem * dcc_gl_scanout_item_new
> (RedChannelClient *rcc,
> void
> *data,
> int
> num);
> +PipeItem * dcc_gl_draw_item_new
> (RedChannelClient *rcc,
> + void
> *data, int num);
>
> typedef struct compress_send_data_t {
> void* comp_buf;
> diff --git a/server/display-channel.c b/server/display-channel.c
> index bd8098e..0f962a7 100644
> --- a/server/display-channel.c
> +++ b/server/display-channel.c
> @@ -2154,3 +2154,25 @@ void display_channel_gl_scanout(DisplayChannel
> *display)
> {
> red_channel_pipes_new_add_push(RED_CHANNEL(display),
> dcc_gl_scanout_item_new, NULL);
> }
> +
> +static void set_gl_draw_async_count(QXLInstance *qxl, int num)
> +{
> + qxl->st->gl_draw_async_count = num;
> +
> + if (num == 0) {
> + red_dispatcher_async_complete(qxl->st->dispatcher,
> qxl->st->gl_draw_async);
> + qxl->st->gl_draw_async = NULL;
Here you can have a race condition.
If red_dispatcher_async_complete wake up the Qemu thread before reset
gl_draw_async it could be possible Qemu will try to send another draw
finding gl_draw_async not NULL and returning without doing nothing
Just save on an automatic variable, set to NULL and call complete
function
Frediano
> + }
> +}
> +
> +void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw
> *draw)
> +{
> + RedWorker *worker = COMMON_CHANNEL(display)->worker;
> + QXLInstance *qxl = red_worker_get_qxl(worker);
> + int num;
> +
> + spice_return_if_fail(qxl->st->gl_draw_async_count == 0);
> +
> + num = red_channel_pipes_new_add_push(RED_CHANNEL(display),
> dcc_gl_draw_item_new, draw);
> + set_gl_draw_async_count(qxl, num);
> +}
> diff --git a/server/display-channel.h b/server/display-channel.h
> index 346e61a..6eb947a 100644
> --- a/server/display-channel.h
> +++ b/server/display-channel.h
> @@ -107,6 +107,7 @@ enum {
> PIPE_ITEM_TYPE_MONITORS_CONFIG,
> PIPE_ITEM_TYPE_STREAM_ACTIVATE_REPORT,
> PIPE_ITEM_TYPE_GL_SCANOUT,
> + PIPE_ITEM_TYPE_GL_DRAW,
> };
>
> typedef struct MonitorsConfig {
> @@ -308,6 +309,8 @@ void
> display_channel_process_surface_cmd (DisplayCha
> void display_channel_update_compression
> (DisplayChannel *display,
> DisplayChannelClient
> *dcc);
> void display_channel_gl_scanout
> (DisplayChannel *display);
> +void display_channel_gl_draw
> (DisplayChannel *display,
> +
> SpiceMsgDisplayGlDraw
> *draw);
>
> static inline int validate_surface(DisplayChannel *display, uint32_t
> surface_id)
> {
> diff --git a/server/red-dispatcher.c b/server/red-dispatcher.c
> index 6d705fc..cf36a42 100644
> --- a/server/red-dispatcher.c
> +++ b/server/red-dispatcher.c
> @@ -997,9 +997,22 @@ void spice_gl_draw_async(QXLInstance *qxl,
> uint32_t w, uint32_t h,
> uint64_t cookie)
> {
> + RedDispatcher *dispatcher;
> + RedWorkerMessage message = RED_WORKER_MESSAGE_GL_DRAW_ASYNC;
> + SpiceMsgDisplayGlDraw draw = {
> + .x = x,
> + .y = y,
> + .w = w,
> + .h = h
> + };
> +
> spice_return_if_fail(qxl != NULL);
> spice_return_if_fail(qxl->st->scanout.drm_dma_buf_fd != -1);
> spice_return_if_fail(qxl->st->gl_draw_async == NULL);
> +
> + dispatcher = qxl->st->dispatcher;
> + qxl->st->gl_draw_async = async_command_alloc(dispatcher, message,
> cookie);
> + dispatcher_send_message(&dispatcher->dispatcher, message, &draw);
> }
>
> void red_dispatcher_async_complete(struct RedDispatcher *dispatcher,
> @@ -1019,6 +1032,7 @@ void red_dispatcher_async_complete(struct RedDispatcher
> *dispatcher,
> case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
> case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
> case RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC:
> + case RED_WORKER_MESSAGE_GL_DRAW_ASYNC:
> break;
> case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
> red_dispatcher_create_primary_surface_complete(dispatcher);
> diff --git a/server/red-dispatcher.h b/server/red-dispatcher.h
> index cc60c10..11a4f2a 100644
> --- a/server/red-dispatcher.h
> +++ b/server/red-dispatcher.h
> @@ -89,6 +89,7 @@ enum {
> RED_WORKER_MESSAGE_MONITORS_CONFIG_ASYNC,
> RED_WORKER_MESSAGE_DRIVER_UNLOAD,
> RED_WORKER_MESSAGE_GL_SCANOUT,
> + RED_WORKER_MESSAGE_GL_DRAW_ASYNC,
>
> RED_WORKER_MESSAGE_COUNT // LAST
> };
> diff --git a/server/red-worker.c b/server/red-worker.c
> index 266014d..065771b 100644
> --- a/server/red-worker.c
> +++ b/server/red-worker.c
> @@ -1291,6 +1291,15 @@ void handle_dev_gl_scanout(void *opaque, void
> *payload)
> display_channel_gl_scanout(worker->display_channel);
> }
>
> +static
> +void handle_dev_gl_draw_async(void *opaque, void *payload)
> +{
> + RedWorker *worker = opaque;
> + SpiceMsgDisplayGlDraw *draw = payload;
> +
> + display_channel_gl_draw(worker->display_channel, draw);
> +}
> +
> static int loadvm_command(RedWorker *worker, QXLCommandExt *ext)
> {
> RedCursorCmd *cursor_cmd;
> @@ -1533,6 +1542,11 @@ static void register_callbacks(Dispatcher *dispatcher)
> handle_dev_gl_scanout,
> 0,
> DISPATCHER_NONE);
> + dispatcher_register_handler(dispatcher,
> + RED_WORKER_MESSAGE_GL_DRAW_ASYNC,
> + handle_dev_gl_draw_async,
> + sizeof(SpiceMsgDisplayGlDraw),
> + DISPATCHER_NONE);
> }
>
>
> diff --git a/server/reds.h b/server/reds.h
> index 308edea..c4d8bda 100644
> --- a/server/reds.h
> +++ b/server/reds.h
> @@ -39,6 +39,7 @@ struct QXLState {
> pthread_mutex_t scanout_mutex;
> SpiceMsgDisplayGlScanoutUnix scanout;
> struct AsyncCommand *gl_draw_async;
> + int gl_draw_async_count;
> };
>
> struct TunnelWorker;
> --
> 2.5.0
>
>
More information about the Spice-devel
mailing list