[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