[Spice-devel] [PATCH v4 5/6] Handle GL_DRAW messages

Marc-André Lureau marcandre.lureau at gmail.com
Tue Feb 9 13:35:05 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>
[removed unused sent field; move gl_draw_async_count to DisplayChannel
 - Frediano Ziglio]
Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/dcc-send.c        | 14 ++++++++++++++
 server/dcc.c             | 23 +++++++++++++++++++++++
 server/dcc.h             |  8 ++++++++
 server/display-channel.c | 24 ++++++++++++++++++++++++
 server/display-channel.h |  5 +++++
 server/red-dispatcher.c  | 14 ++++++++++++++
 server/red-dispatcher.h  |  1 +
 server/red-worker.c      | 14 ++++++++++++++
 8 files changed, 103 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..a482938 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,11 @@ typedef struct GlScanoutUnixItem {
     PipeItem base;
 } GlScanoutUnixItem;
 
+typedef struct GlDrawItem {
+    PipeItem base;
+    SpiceMsgDisplayGlDraw draw;
+} GlDrawItem;
+
 typedef struct ImageItem {
     PipeItem link;
     int refs;
@@ -213,6 +219,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..936c74a 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2154,3 +2154,27 @@ 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(DisplayChannel *display, int num)
+{
+    RedWorker *worker = COMMON_CHANNEL(display)->worker;
+    QXLInstance *qxl = red_worker_get_qxl(worker);
+
+    display->gl_draw_async_count = num;
+
+    if (num == 0) {
+        struct AsyncCommand *async = qxl->st->gl_draw_async;
+        qxl->st->gl_draw_async = NULL;
+        red_dispatcher_async_complete(qxl->st->dispatcher, async);
+    }
+}
+
+void display_channel_gl_draw(DisplayChannel *display, SpiceMsgDisplayGlDraw *draw)
+{
+    int num;
+
+    spice_return_if_fail(display->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(display, num);
+}
diff --git a/server/display-channel.h b/server/display-channel.h
index 346e61a..3d2a465 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 {
@@ -201,6 +202,8 @@ struct DisplayChannel {
     ImageCache image_cache;
     RedCompressBuf *free_compress_bufs;
 
+    int gl_draw_async_count;
+
 /* TODO: some day unify this, make it more runtime.. */
     stat_info_t add_stat;
     stat_info_t exclude_stat;
@@ -308,6 +311,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 26a153e..dce20c4 100644
--- a/server/red-dispatcher.c
+++ b/server/red-dispatcher.c
@@ -998,9 +998,22 @@ void spice_qxl_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,
@@ -1020,6 +1033,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 76ac41c..e7d0671 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1167,6 +1167,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;
@@ -1409,6 +1418,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);
 }
 
 
-- 
2.5.0



More information about the Spice-devel mailing list