[Spice-devel] [PATCH spice 17/18] Handle GL_DRAW messages

Marc-André Lureau marcandre.lureau at gmail.com
Tue Dec 15 15:49:31 PST 2015


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 | 21 +++++++++++++++++++++
 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, 100 insertions(+)

diff --git a/server/dcc-send.c b/server/dcc-send.c
index 8cc2dda..fb5db72 100644
--- a/server/dcc-send.c
+++ b/server/dcc-send.c
@@ -2361,6 +2361,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);
@@ -2475,6 +2486,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 47084ca..5ed7bff 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 PIPE_ITEM(item);
 }
 
+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 PIPE_ITEM(item);
+}
+
 void dcc_destroy_surface(DisplayChannelClient *dcc, uint32_t surface_id)
 {
     DisplayChannel *display;
@@ -1586,6 +1607,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;
@@ -1661,6 +1683,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 22d236e..e878829 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 1f8f5af..2071587 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2155,3 +2155,24 @@ 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;
+    }
+}
+
+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 183a0d3..560a060 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -996,9 +996,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.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,
@@ -1018,6 +1031,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 e4ba79f..575b7bd 100644
--- a/server/red-dispatcher.h
+++ b/server/red-dispatcher.h
@@ -87,6 +87,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 7005166..64f89d0 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1294,6 +1294,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;
@@ -1536,6 +1545,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 cffa57f..ee8caf9 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -36,6 +36,7 @@ struct QXLState {
     pthread_mutex_t scanout_mutex;
     SpiceMsgDisplayGlScanoutUnix scanout;
     AsyncCommand *gl_draw_async;
+    int gl_draw_async_count;
 };
 
 struct TunnelWorker;
-- 
2.5.0



More information about the Spice-devel mailing list